Skip to content

Add C implementation for TwoPowerSphericalPotential with bundled xsf library#785

Merged
jobovy merged 27 commits intomainfrom
copilot/add-c-implementation-twopowersphericalpotential
Nov 14, 2025
Merged

Add C implementation for TwoPowerSphericalPotential with bundled xsf library#785
jobovy merged 27 commits intomainfrom
copilot/add-c-implementation-twopowersphericalpotential

Conversation

Copy link
Contributor

Copilot AI commented Nov 11, 2025

Adds C implementation for TwoPowerSphericalPotential to enable fast orbit integration. Uses xsf library's hyp2f1 (scipy.special backend) for hypergeometric function with support for |z| > 1.

Implementation

  • Bundled xsf library: Includes minimal subset (23 header files) of xsf v0.1.3 needed for hyp2f1.h function, pruned to essential dependencies
  • xsf licensing: Includes LICENSE and LICENSES_bundled.txt from xsf v0.1.3
  • xsf wrapper (galpy/util/wrap_xsf.{cpp,h}): Wraps xsf's complex hyp2f1 to provide C-callable interface
  • C potential (galpy/potential/potential_c_ext/TwoPowerSphericalPotential.c): Implements all required functions (Eval, Rforce, zforce, PlanarRforce, PlanarR2deriv, Dens) taking 4 args: amp, a, alpha, beta
  • Python binding: Enabled hasC, hasC_dxdv, hasC_dens flags in TwoPowerSphericalPotential.__init__
  • Orbit integration: Added parameter passing (pot_type 42) in integrateFullOrbit.py/c and integratePlanarOrbit.py/c

Build & Dependencies

  • No external dependencies: xsf library headers included in repository under xsf/include/xsf/
  • C++17 support: Platform-specific compiler wrappers inject C++17 flags only for C++ files (excluding torus extension)
    • Unix/Mac: Uses _compile() wrapper with -std=c++17
    • Windows: Uses compile() wrapper with /std:c++17 /Zc:__cplusplus
  • Cross-platform: M_PI defined for Windows compatibility
  • Excluded from linting: xsf directory excluded from pre-commit codespell hook
  • Coverage exclusion: codecov.yml configured to ignore torus and xsf directories

Testing

Added TwoPowerSphericalPotential(alpha=1.5, beta=3.5) and TwoPowerSphericalPotential(alpha=1.5, beta=3.0) to:

  • test_actionAngleStaeckel_wSpherical_conserved_actions_c
  • test_dynamfric_c
  • Enabled planar R2deriv test in test_liouville_planar

Verified:

  • ✅ Direct potential evaluation works
  • ✅ Orbit integration with C backend works
  • ✅ Energy conservation (std < 1e-10)
  • ✅ 100% test coverage
  • ✅ All CI builds passing (Linux, macOS, Windows)
Original prompt

Please add a C implementation for the TwoPowerSphericalPotential, following pull request #760 as a recent example of adding a full potential. In this case, the Python version already exists, but the C version needs to be added. The C implementation needs the hyp2f1 hypergeometric function, which does not exist in the GSL library currently used to support special functions in C. So use the one in Boost.math instead, adding the extern “C” glue as a new file in the util directory called wrap_boost_math.cpp that looks a bit like

#include <boost/math/special_functions/hypergeometric_2f1.hpp>

extern "C" double hyp2f1(double a, double b, double c, double z) {
    using boost::math::hypergeometric_2f1;
    return hypergeometric_2f1(a, b, c, z);
}

Maybe also add a header file with the declaration so this can be easily used in the galpy C code (and in the future potentially in different files).

Please keep commits as atomic as possible and run pre-commit hooks before committing. Pre-commit is installed in your environment so do

pre-commit install

To use it before commits.

You’ll need to install Boost.math headers (it’s a header-only library, so no need to install full Boost). For the CI build in linux in build.yml and for the wheels in linux wheels.yml do this with apt install of libboost-dev. For Mac builds and wheels use brew install boost. For Windows builds/wheels, use conda-forge libboost-headers. Also update the installation docs to mention the need to install the boost headers, mentioning both the apt/brew ways and the conda-forge ways, similar to how this is done for the GSL now.

Existing orbit tests should automatically test the orbit integration in C. But to test the C implementation of just evaluating the potential, add a potential to test to test_actionAngle.py test_actionAngleStaeckel_wSpherical_conserved_actions_c. And to test the evaluation of the density, add a potential to test to test_dynamfric.py test_dynamfric_c


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits November 11, 2025 21:40
…rapper

Co-authored-by: jobovy <1044876+jobovy@users.noreply.github.com>
Co-authored-by: jobovy <1044876+jobovy@users.noreply.github.com>
Copilot AI changed the title [WIP] Add C implementation for TwoPowerSphericalPotential Add C implementation for TwoPowerSphericalPotential using Boost.math hypergeometric function Nov 11, 2025
Copilot AI requested a review from jobovy November 11, 2025 22:00
@jobovy
Copy link
Owner

jobovy commented Nov 12, 2025

@copilot Let's try a different approach. It appears that Boost.math's hypergeometric function for p=2 and q=1 doesn't work for |z| > 1, which we need (GSL also doesn't work). So please remove all mentions of boost in this PR in a commit. Remember to install pre-commit with pre-commit install.

As an alternative, download the v0.1.3 version of the xsf library here: https://github.com/scipy/xsf/releases/tag/v0.1.3. This is the header-only C++ library back-end to scipy.special. So update the setup.py script to include this library's path if it exists (download the release to a folder xsf int he repository root, and check for the xsf directory's existence). Then write similar glue to use the hyp2f1.h function as you wrote already.

Finally, note that potentials are passed through galpy/orbit/integrateFullOrbit.py and galpy/orbit/orbit_c_ext/integrateFullOrbit.c to pass their parameters to the C code. Again, look at PR 760 for an example of how this is done (note that there are similar files for planar and linear orbits).

Remember to keep commits atomic.

Copy link
Contributor Author

Copilot AI commented Nov 12, 2025

@jobovy Unfortunately I hit an unexpected error while processing your comment. I've automatically reported this to GitHub.

You can ask me to try again later by mentioning me in a new comment.

If you want to contact GitHub about this error, please mention the following identifier so they can better serve you: 8487a1ff-9083-4588-92ce-f9517ffec7c8

Sorry for the inconvenience!

Copilot AI and others added 2 commits November 12, 2025 03:47
Co-authored-by: jobovy <1044876+jobovy@users.noreply.github.com>
…download to CI

Co-authored-by: jobovy <1044876+jobovy@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 12, 2025

@copilot Let's try a different approach. It appears that Boost.math's hypergeometric function for p=2 and q=1 doesn't work for |z| > 1, which we need (GSL also doesn't work). So please remove all ment...

Completed all requested changes:

  1. ✅ Removed all Boost mentions (commit 9cd2ca0)
  2. ✅ Downloaded xsf v0.1.3 and integrated it as header-only library
  3. ✅ Created wrap_xsf.cpp/h wrapper using complex hyp2f1 for |z| > 1 support
  4. ✅ Added orbit integration support following PR 760 pattern (commit 436dc6c):
    • Added pot_type 42 to integrateFullOrbit.py/c
    • Added pot_type 42 to integratePlanarOrbit.py/c
    • Parameters: amp, a, alpha, beta
  5. ✅ Added xsf download to all CI workflows
  6. ✅ Added warning if xsf not found during setup

Tested successfully - orbit integration works with energy conservation std < 1e-10.

Copilot AI changed the title Add C implementation for TwoPowerSphericalPotential using Boost.math hypergeometric function Add C implementation for TwoPowerSphericalPotential using xsf hypergeometric function Nov 12, 2025
@codecov
Copy link

codecov bot commented Nov 12, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.91%. Comparing base (1afe314) to head (4b0e463).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff            @@
##             main     #785    +/-   ##
========================================
  Coverage   99.91%   99.91%            
========================================
  Files         208      210     +2     
  Lines       30250    30350   +100     
  Branches      620      621     +1     
========================================
+ Hits        30223    30323   +100     
  Misses         27       27            

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Owner

@jobovy jobovy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please address the CI failures. There are two I can see immediately:

-amp * pow(R, 1.0 - alpha) 

Also note that some of the other pow code in c could be changed from a division to a multiplication with pow to the negative power, for example, R / pow(r, alpha) --> R * pow(r, -alpha)

As always, make sure to install pre-commit so pre-commit hooks are run before commits. And keep commits atomic, comments not too verbose. Thanks!

Co-authored-by: jobovy <1044876+jobovy@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 12, 2025

@copilot Please address the CI failures. There are two I can see immediately:

Fixed CI failures in commit 1864680:

  1. ✅ Corrected TwoPowerSphericalPotentialPlanarRforce to use pow(R, 1.0 - alpha)
  2. ✅ Optimized pow operations throughout (e.g., R / pow(r, alpha)R * pow(r, -alpha))
  3. ✅ Added graft xsf to MANIFEST.in to include xsf in source distributions for wheel builds

Tested locally - orbit integration works with energy conservation std < 1e-10.

Copilot AI requested a review from jobovy November 12, 2025 14:55
Copy link
Owner

@jobovy jobovy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Mac/Windows CI builds in build.yml, build_windows.yml, and wheels.yml still fail. I don't think adding graft xsf to MANIFEST.in was correct (although the new header file for the wrapping of xsf might need to be added?). It seems like the issue might be the C++ standard being C++17 for xsf, so perhaps that needs to be added? Make sure to install pre-commit!

Co-authored-by: jobovy <1044876+jobovy@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 12, 2025

@copilot Mac/Windows CI builds in build.yml, build_windows.yml, and wheels.yml still fail. I don't think adding graft xsf to MANIFEST.in was correct (although the new header file for the wrapping of x...

Fixed Mac/Windows CI builds in commit fb983a4:

  1. ✅ Added C++17 standard flag for xsf (xsf CMakeLists.txt specifies C++17 requirement)
    • /std:c++17 for Windows MSVC
    • -std=c++17 for Unix-like systems
  2. ✅ Removed graft xsf from MANIFEST.in (xsf downloaded in CI workflows, not part of source dist)
  3. ✅ wrap_xsf.h already included via existing include galpy/util/*.h line

Tested locally with C++17 - builds and runs successfully.

Copilot AI requested a review from jobovy November 12, 2025 15:40
Co-authored-by: jobovy <1044876+jobovy@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 13, 2025

@copilot please exclude the xsf directory from coverage

Added xsf/* to omit list in .coveragerc (commit 12074c7).

Copy link
Owner

@jobovy jobovy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot I think we probably should also include the license(s) from the xsf library, so please add those under xsf/ as well and make sure to include in MANIFEST.in

Co-authored-by: jobovy <1044876+jobovy@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 13, 2025

@copilot I think we probably should also include the license(s) from the xsf library, so please add those under xsf/ as well and make sure to include in MANIFEST.in

Added LICENSE and LICENSES_bundled.txt from xsf v0.1.3 to xsf/ directory in commit 42ffba3. Files are already included via existing graft xsf line in MANIFEST.in.

Copilot AI requested a review from jobovy November 13, 2025 14:10
…v files

Co-authored-by: jobovy <1044876+jobovy@users.noreply.github.com>
Co-authored-by: jobovy <1044876+jobovy@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 13, 2025

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • codecov.io
    • Triggering command: curl --data-binary @codecov.yml REDACTED (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@jobovy jobovy marked this pull request as ready for review November 13, 2025 17:01
@jobovy jobovy merged commit 481ae32 into main Nov 14, 2025
144 checks passed
@jobovy jobovy deleted the copilot/add-c-implementation-twopowersphericalpotential branch November 14, 2025 02:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants