Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 24, 2025

CompositePotential Implementation - Complete

This PR implements CompositePotential and planarCompositePotential classes that allow combinations of potentials to be called with method functions like individual potentials.

Final Summary of All Changes

Core CompositePotential Implementation

  • Created CompositePotential class inheriting from Potential
  • Implemented all derivative methods by summing over components
  • Added support for __add__, __mul__, __div__, __setitem__, __getitem__ (with slicing)
  • Proper unit handling with _roSet/_voSet from first potential
  • Unit compatibility checks using physical_compatible

planarCompositePotential Implementation

  • Created planarCompositePotential class in galpy/potential/planarCompositePotential.py
  • Inherits from planarPotential, implements all derivative methods (_evaluate, _Rforce, _phitorque, _R2deriv, _phi2deriv, _Rphideriv)
  • Updated planarForce.__add__ and __radd__ to return planarCompositePotential
  • Updated toPlanarPotential and RZToplanarPotential to return planarCompositePotential for multiple potentials
  • Updated _parse_pot in integratePlanarOrbit.py for C orbit integration

Code Review Refinements

  • Removed unnecessary isinstance checks and redundant code
  • Simplified __add__ to not support lists directly
  • Added tests for explicit ro/vo, setitem errors, add errors, repr method
  • Added SpiralArmsPotential error tests
  • Simplified evaluateSurfaceDensities and evaluaterforces
  • Added # pragma: no cover to unreachable code

Decorator Refactoring

  • Applied @potential_list_of_potentials_input decorator to:
    • integrateFullOrbit and integrateFullOrbit_sos
    • epifreq, verticalfreq, flattening, omegac, rtide, ttensor, zvc, tdyn
  • Removed manual list-to-CompositePotential conversions
  • Consistent deprecation warnings across all functions

Key Features

✅ 3D Addition: pot1 + pot2 returns CompositePotential
✅ 2D Addition: planar1 + planar2 returns planarCompositePotential
toPlanarPotential([pot1, pot2]) returns planarCompositePotential
toPlanarPotential(MWPotential2014) returns planarCompositePotential
✅ Method calls: combined.Rforce(R, z) works like individual potentials
✅ Multiplication/division: combined * 2.0 applies to all components
✅ Item assignment: MWPotential2014[2] *= 1.5 modifies individual component
✅ Slicing: MWPotential2014[1:] returns CompositePotential
✅ Backward compatible: combined == [pot1, pot2] returns True
✅ List deprecation: All functions emit DeprecationWarning for lists
✅ C integration: Works with C orbit integration via _parse_pot

Testing

  • 12+ CompositePotential-specific tests
  • 4 planarCompositePotential tests (basic, addition, conversion, slicing)
  • Complete SpiralArmsPotential error tests (all methods covered)
  • All existing potential and orbit tests pass
  • Pre-commit hooks pass
Original prompt

Please implement a CompositePotential class under galpy.potential that contains combinations of potentials and allows combinations of potentials to be called with method functions in the same way as current single potentials can be called (e.g., pot.Rforce for the radial force for both an individual pot potential but also now if pot is a combination of potentials in a CompositePotential object). This class should inherit from Force and support all the usual Potential functions like _evaluate, _Rforce, _zforce, _R2deriv, _Rzderiv, _phitorque, _z2deriv, _phi2deriv, _Rphideriv, _phizderiv, _dens, _mass (and maybe others?) All of these should essentially follow an implementation like in the function evaluatePotentials in Potential.py and _evaluateRforces etc. CompositePotential should keep the combined potential internally as a list and should be instantiated with a list of potentials (_flatten it like this is done elsewhere in the code before storing internally). The main way that users would instantiate a CompositePotential, though, would be through addition of individual potentials or CompositePotentials already. So implement add to do this, covering cases where an individual potential is added to an existing CompositePotential or the other way around, or where a list is added. Implement the basic structure in a commit, then re-write functions like _evaluatePotentials to internally use the CompositePotential class (for now checking whether input potential is a list rather than a CompositePotential and instantiating a CompositePotential if necessary). Also make sure to re-write the current Force.py add and radd. Make sure to install pre-commit! And keep commits atomic so it’s clear what’s going on. Thanks!


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Add CompositePotential class to handle combined potentials Implement CompositePotential class for unified potential combination interface Nov 24, 2025
Copilot AI requested a review from jobovy November 24, 2025 21:08
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 also change MWPotential2014's definition to a CompositePotential and also those of all of the MW potentials in mwpotentials.py to CompositePotentials.

To support C integration, we'll also have to adjust _parse_pot in the integrateFullOrbit.py code, which now goes through a list but will have to go through the CompositePotential list as well in the future (and similarly, lists should be deprecated in versions beyond 1.13.x, maybe we can use the same decorator as mentioned in my review?)

Copy link
Contributor Author

Copilot AI commented Nov 24, 2025

@copilot Please also change MWPotential2014's definition to a CompositePotential and also those of all of the MW potentials in mwpotentials.py to CompositePotentials.

To support C integration, ...

Done in commit 1bc3edd. Changed MWPotential2014 and _MWPotential to CompositePotential instances in mwpotentials.py. The other MW potentials (McMillan17, Cautun20, Irrgang13*, DehnenBinney98*) are lazily loaded and already use the + operator, so they automatically return CompositePotential now.

For the _parse_pot changes in integrateFullOrbit.py, I'll work on that in a follow-up commit once we confirm this approach works correctly.

Copilot AI requested a review from jobovy November 24, 2025 22:02
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 Also implement the handling of CompositePotential in _parse_pot in integrateFullOrbit.py, so these can be passed to C for orbit integration properly

Copy link
Contributor Author

Copilot AI commented Nov 24, 2025

@copilot Also implement the handling of CompositePotential in _parse_pot in integrateFullOrbit.py, so these can be passed to C for orbit integration properly

Implemented in commit 8dea636. Added CompositePotential handling at the start of _parse_pot:

if isinstance(pot, potential.CompositePotential.CompositePotential):
    pot = list(pot)

This extracts the internal list from CompositePotential so the rest of the parsing logic works unchanged. Tested successfully with MWPotential2014.

Copilot AI requested a review from jobovy November 24, 2025 22:36
@jobovy
Copy link
Owner

jobovy commented Nov 25, 2025

@copilot Please also implement the mul and div functions for CompositePotential in the way that makes sense (should apply to each component potential). And please test (maybe add a test) that all methods of Force and Potential can be called on a CompositePotential using MWPotential2014 as an example.

Copy link
Contributor Author

Copilot AI commented Nov 25, 2025

@copilot Please also implement the mul and div functions for CompositePotential in the way that makes sense (should apply to each component potential). And please test (maybe add a test) that ...

Implemented in commit e6313e2. Added __mul__, __rmul__, __div__, and __truediv__ methods to CompositePotential that apply the operation to each component potential. Also added test_CompositePotential_mul_div and test_CompositePotential_all_methods tests that verify multiplication/division and that all Force and Potential methods can be called on MWPotential2014.

@codecov
Copy link

codecov bot commented Nov 25, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.91%. Comparing base (ea8033c) to head (2205a9b).
⚠️ Report is 16 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #794   +/-   ##
=======================================
  Coverage   99.91%   99.91%           
=======================================
  Files         209      213    +4     
  Lines       30659    30740   +81     
  Branches      627      627           
=======================================
+ Hits        30632    30713   +81     
  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.

@jobovy jobovy force-pushed the copilot/add-composite-potential-class branch from 04ae321 to 178674b Compare November 25, 2025 21:02
@jobovy
Copy link
Owner

jobovy commented Nov 25, 2025

@copilot Lots of tests are failing, some at least because the new CompositePotential objects are not being converted to planarPotentials correctly. So please edit the code in planarPotential.py to also handle CompositePotential objects in the different routines to create a planarPotential (there's a routine for RZPotentials and one for general potentials I believe). In general, it may be worthwhile to see where lists are mentioned in galpy and check whether these are lists of potentials, because in that case CompositePotential objects will now also have to be handled.

Also implement item assignment for CompositePotential so things like

MWPotential2014[2]*= 1.5

work as expected (that is, the new CompositePotential has the same components as the input MWPotential2014, but with the amplitude of the second entry raised by 50%).

Remember to install pre-commit!

Thanks!

Copy link
Contributor Author

Copilot AI commented Nov 25, 2025

@copilot Lots of tests are failing, some at least because the new CompositePotential objects are not being converted to planarPotentials correctly. So please edit the code in planarPotential.py to als...

Implemented in commit 1684841:

Planar/Vertical Potential Conversion:

  • Updated toPlanarPotential and toVerticalPotential to handle CompositePotential by converting to list first
  • All planar/vertical conversion tests pass

Item Assignment:

  • Implemented __setitem__ for CompositePotential
  • MWPotential2014[2] *= 1.5 now works as expected, modifying the amplitude of the second component

Tests Added:

  • test_CompositePotential_setitem - verifies item assignment works correctly
  • test_CompositePotential_planar_conversion - verifies planar potential conversion works

All CompositePotential tests pass (8/8).

@jobovy jobovy changed the title Implement CompositePotential and planarCompositePotential classes for unified potential combination interface Implement CompositePotential, planarCompositePotential, and linearCompositePotential classes for unified potential combination interface Dec 1, 2025
@jobovy jobovy force-pushed the copilot/add-composite-potential-class branch 7 times, most recently from f3912ac to 2502279 Compare December 14, 2025 04:12
Copilot AI and others added 12 commits December 29, 2025 20:45
…nternally (#799)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: jobovy <[email protected]>
Co-authored-by: Jo Bovy <[email protected]>
…800)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: jobovy <[email protected]>
Co-authored-by: Jo Bovy <[email protected]>
…of potentials with combinations (#802)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: jobovy <[email protected]>
Co-authored-by: Jo Bovy <[email protected]>
…onversion to planarForces when necessary (#805)

Co-authored-by: Jo Bovy <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: jobovy <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
…ically deal with planar conversions. Abstract out the list deprecation and conversion so it can be used outside of the decorator and apply it to Orbit methods
@jobovy jobovy force-pushed the copilot/add-composite-potential-class branch from e437b26 to 154c37b Compare December 30, 2025 01:45
…with the switch to CompositePotential and add some further tests
@jobovy jobovy marked this pull request as ready for review December 30, 2025 23:30
@jobovy jobovy merged commit 06943f2 into main Dec 31, 2025
98 checks passed
@jobovy jobovy deleted the copilot/add-composite-potential-class branch December 31, 2025 03:46
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