From 6672129deaa01f9be3fa707747999b06736ff0e5 Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Thu, 14 May 2026 16:13:10 -0400 Subject: [PATCH 01/24] Update list of publically installed headers necessary for a Cuda compilation --- expui/CMakeLists.txt | 4 ++++ include/BiorthCube.H | 10 +++------- include/BiorthCyl.H | 10 +++------- include/EmpCylSL.H | 4 ++-- include/SLGridMP2.H | 4 ++-- include/cudaMappingConstants.cuH | 6 +++--- include/cudaParticle.cuH | 12 +++++------- 7 files changed, 22 insertions(+), 28 deletions(-) diff --git a/expui/CMakeLists.txt b/expui/CMakeLists.txt index f25d0d7b7..7428bf796 100644 --- a/expui/CMakeLists.txt +++ b/expui/CMakeLists.txt @@ -97,11 +97,15 @@ target_sources(expui PUBLIC FILE_SET HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../include/DiskWithHalo.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/EmpCyl2d.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/EXPmath.H + ${CMAKE_CURRENT_SOURCE_DIR}/../include/EXPversion.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/libvars.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/Timer.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/coef.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/Covariance.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/ExpDeproj.H + ${CMAKE_CURRENT_SOURCE_DIR}/../include/cudaUtil.cuH + ${CMAKE_CURRENT_SOURCE_DIR}/../include/cudaParticle.cuH + ${CMAKE_CURRENT_SOURCE_DIR}/../include/cudaMappingConstants.cuH ) install(TARGETS expui FILE_SET HEADERS DESTINATION include/EXP) diff --git a/include/BiorthCube.H b/include/BiorthCube.H index a89ebb87d..808ed7f49 100644 --- a/include/BiorthCube.H +++ b/include/BiorthCube.H @@ -17,8 +17,9 @@ #include #if HAVE_LIBCUDA==1 -#include -#include +#include "cudaUtil.cuH" +#include "cudaParticle.cuH" +#include "cudaMappingConstants.cuH" #endif // For reading and writing cache file @@ -28,11 +29,6 @@ #include #include -#if HAVE_LIBCUDA==1 -#include -#include -#endif - #include "EmpCyl2d.H" //!! BiorthCube grid class diff --git a/include/BiorthCyl.H b/include/BiorthCyl.H index 687433586..226120441 100644 --- a/include/BiorthCyl.H +++ b/include/BiorthCyl.H @@ -17,8 +17,9 @@ #include #if HAVE_LIBCUDA==1 -#include -#include +#include "cudaUtil.cuH" +#include "cudaParticle.cuH" +#include "cudaMappingConstants.cuH" #endif // For reading and writing cache file @@ -28,11 +29,6 @@ #include #include -#if HAVE_LIBCUDA==1 -#include -#include -#endif - #include "EmpCyl2d.H" //!! BiorthCyl grid class diff --git a/include/EmpCylSL.H b/include/EmpCylSL.H index 9811a0059..1bd993e10 100644 --- a/include/EmpCylSL.H +++ b/include/EmpCylSL.H @@ -24,8 +24,8 @@ #include "coef.H" #if HAVE_LIBCUDA==1 -#include -#include +#include "cudaParticle.cuH" +#include "cudaMappingConstants.cuH" #endif #include "libvars.H" diff --git a/include/SLGridMP2.H b/include/SLGridMP2.H index da209403c..dd46e28cf 100644 --- a/include/SLGridMP2.H +++ b/include/SLGridMP2.H @@ -19,8 +19,8 @@ using namespace __EXP__; #if HAVE_LIBCUDA==1 -#include -#include +#include "cudaUtil.cuH" +#include "cudaMappingConstants.cuH" #endif diff --git a/include/cudaMappingConstants.cuH b/include/cudaMappingConstants.cuH index 067d299b6..3e845436d 100644 --- a/include/cudaMappingConstants.cuH +++ b/include/cudaMappingConstants.cuH @@ -1,9 +1,7 @@ -// -*- C++ -*- - #ifndef CUDA_MAPPING_CONSTANTS_H #define CUDA_MAPPING_CONSTANTS_H -#include +#include "cudaUtil.cuH" struct cudaMappingConstants { @@ -23,3 +21,5 @@ struct cudaMappingConstants }; #endif + +// -*- C++ -*- diff --git a/include/cudaParticle.cuH b/include/cudaParticle.cuH index 5147b01dd..ccc2102b1 100644 --- a/include/cudaParticle.cuH +++ b/include/cudaParticle.cuH @@ -1,5 +1,3 @@ -// -*- C++ -*- - #ifndef PARTICLE_CUH #define PARTICLE_CUH @@ -16,11 +14,9 @@ #include #include -#include - -#include - -#include +#include "config_exp.h" +#include "cudaUtil.cuH" +#include "Particle.H" //! Simplified particle structure for use in CUDA kernel code struct cudaParticle @@ -125,3 +121,5 @@ struct cuPartToChange }; #endif + +// -*- C++ -*- From 8760ca1e783b8344e09c3be500479624ca2fe166 Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Thu, 14 May 2026 16:38:41 -0400 Subject: [PATCH 02/24] Implement coefficient defined origin by default for getAccel and getFields. Origin for getFields can be (0, 0, 0) with an optional toggle. --- expui/BasisFactory.H | 8 ++++--- expui/BasisFactory.cc | 21 ++++++++++++++-- expui/BiorthBasis.cc | 32 ++++++++++++++++++++++++- pyEXP/BasisWrappers.cc | 54 +++++++++++++++++++++++------------------- 4 files changed, 85 insertions(+), 30 deletions(-) diff --git a/expui/BasisFactory.H b/expui/BasisFactory.H index e270fae1e..f0520d524 100644 --- a/expui/BasisFactory.H +++ b/expui/BasisFactory.H @@ -197,17 +197,19 @@ namespace BasisClasses const Coord ctype=Coord::Spherical); //! Evaluate fields at a point - virtual std::vector getFields(double x, double y, double z); + virtual std::vector getFields(double x, double y, double z, + bool origin=false); //! Evaluate fields at a point for all coefficients sets virtual std::tuple, Eigen::VectorXd> getFieldsCoefs - (double x, double y, double z, std::shared_ptr coefs); + (double x, double y, double z, std::shared_ptr coefs, + bool origin=false); //! Evaluate fields at a point, and provide field lables virtual std::tuple, std::vector> evaluate(double x, double y, double z) - { return {getFields(x, y, z), getFieldLabels(coordinates)}; } + { return {getFields(x, y, z, true), getFieldLabels(coordinates)}; } //! Retrieve the coefficients virtual CoefClasses::CoefStrPtr getCoefficients() diff --git a/expui/BasisFactory.cc b/expui/BasisFactory.cc index aba544cc3..9ae2d2fa5 100644 --- a/expui/BasisFactory.cc +++ b/expui/BasisFactory.cc @@ -228,14 +228,21 @@ namespace BasisClasses }; } - std::vector Basis::getFields(double x, double y, double z) + std::vector Basis::getFields(double x, double y, double z, + bool origin) { + if (not origin) { + x -= coefctr(0); + y -= coefctr(1); + z -= coefctr(2); + } return crt_eval(x, y, z); } std::tuple, Eigen::VectorXd> Basis::getFieldsCoefs - (double x, double y, double z, std::shared_ptr coefs) + (double x, double y, double z, std::shared_ptr coefs, + bool origin) { // Python dictonary for return std::map ret; @@ -249,9 +256,19 @@ namespace BasisClasses // Make the return dictionary of arrays for (int i=0; igetCoefStruct(times[i])); + + // Apply centering if requested + if (not origin) { + x -= coefctr(0); + y -= coefctr(1); + z -= coefctr(2); + } + // The field evaluation auto v = crt_eval(x, y, z); + // Pack the fields into the dictionary for (int j=0; j acc) { + // Shift to center + x -= coefctr(0); + y -= coefctr(1); + z -= coefctr(2); + // Get polar coordinates double R2 = x*x + y*y; double r2 = R2 + z*z; @@ -1804,6 +1809,11 @@ namespace BasisClasses void Cylindrical::computeAccel(double x, double y, double z, Eigen::Ref acc) { + // Shift to center + x -= coefctr(0); + y -= coefctr(1); + z -= coefctr(2); + double R = sqrt(x*x + y*y); double phi = atan2(y, x); @@ -2481,6 +2491,11 @@ namespace BasisClasses void FlatDisk::computeAccel(double x, double y, double z, Eigen::Ref acc) { + // Shift to center + x -= coefctr(0); + y -= coefctr(1); + z -= coefctr(2); + // Get thread id int tid = omp_get_thread_num(); @@ -3270,6 +3285,11 @@ namespace BasisClasses void CBDisk::computeAccel(double x, double y, double z, Eigen::Ref acc) { + // Shift to center + x -= coefctr(0); + y -= coefctr(1); + z -= coefctr(2); + // Get thread id int tid = omp_get_thread_num(); @@ -3756,6 +3776,11 @@ namespace BasisClasses void Slab::computeAccel(double x, double y, double z, Eigen::Ref acc) { + // Shift to center + x -= coefctr(0); + y -= coefctr(1); + z -= coefctr(2); + // Loop indices // int ix, iy, iz; @@ -4328,6 +4353,11 @@ namespace BasisClasses void Cube::computeAccel(double x, double y, double z, Eigen::Ref acc) { + // Shift to center + x -= coefctr(0); + y -= coefctr(1); + z -= coefctr(2); + // Get thread id int tid = omp_get_thread_num(); @@ -4781,7 +4811,7 @@ namespace BasisClasses for (int k=0; k<3; k++) pp(k) = ps(n, k) - ctr(k); pp = rot * pp; - auto v = basis->getFields(pp(0), pp(1), pp(2)); + auto v = basis->getFields(pp(0), pp(1), pp(2), true); // First 6 fields are density and potential, followed by acceleration for (int k=0; k<3; k++) accel(n, k) += v[6+k] - basis->pseudo(k); diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index 1429c6249..0ed0247d4 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -330,18 +330,18 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using BasisClasses::Basis::Basis; - std::vector getFields(double x, double y, double z) override + std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, Basis, getFields, x, y, z); + PYBIND11_OVERRIDE(std::vector, Basis, getFields, x, y, z, origin); } using FCReturn = std::tuple, Eigen::VectorXd>; FCReturn getFieldsCoefs - (double x, double y, double z, CoefClasses::CoefsPtr coefs) override + (double x, double y, double z, CoefClasses::CoefsPtr coefs, bool origin) override { - PYBIND11_OVERRIDE(FCReturn, Basis, getFieldsCoefs, x, y, z, coefs); + PYBIND11_OVERRIDE(FCReturn, Basis, getFieldsCoefs, x, y, z, coefs, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override { @@ -434,9 +434,9 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using FieldBasis::FieldBasis; - std::vector getFields(double x, double y, double z) override + std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, FieldBasis, getFields, x, y, z); + PYBIND11_OVERRIDE(std::vector, FieldBasis, getFields, x, y, z, origin); } void accumulate(double m, double x, double y, double z, @@ -561,8 +561,8 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using Spherical::Spherical; - std::vector getFields(double x, double y, double z) override { - PYBIND11_OVERRIDE(std::vector, Spherical, getFields, x, y, z); + std::vector getFields(double x, double y, double z, bool origin) override { + PYBIND11_OVERRIDE(std::vector, Spherical, getFields, x, y, z, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override { @@ -627,8 +627,8 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using Cylindrical::Cylindrical; - std::vector getFields(double x, double y, double z) override { - PYBIND11_OVERRIDE(std::vector, Cylindrical, getFields, x, y, z); + std::vector getFields(double x, double y, double z, bool origin) override { + PYBIND11_OVERRIDE(std::vector, Cylindrical, getFields, x, y, z, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override { @@ -705,9 +705,9 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using FlatDisk::FlatDisk; - std::vector getFields(double x, double y, double z) override + std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, FlatDisk, getFields, x, y, z); + PYBIND11_OVERRIDE(std::vector, FlatDisk, getFields, x, y, z, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override @@ -787,9 +787,9 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using CBDisk::CBDisk; - std::vector getFields(double x, double y, double z) override + std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, CBDisk, getFields, x, y, z); + PYBIND11_OVERRIDE(std::vector, CBDisk, getFields, x, y, z, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override @@ -861,9 +861,9 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using Slab::Slab; - std::vector getFields(double x, double y, double z) override + std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, Slab, getFields, x, y, z); + PYBIND11_OVERRIDE(std::vector, Slab, getFields, x, y, z, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override @@ -935,9 +935,9 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using Cube::Cube; - std::vector getFields(double x, double y, double z) override + std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, Cube, getFields, x, y, z); + PYBIND11_OVERRIDE(std::vector, Cube, getFields, x, y, z, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override @@ -1534,6 +1534,9 @@ void BasisFactoryClasses(py::module &m) y-axis position z : float z-axis position + origin : bool + If true, the origin for field evaluations are is (0, 0, 0). + If false, the default, we use the frame defined by the coefficients. Returns ------- @@ -1544,10 +1547,10 @@ void BasisFactoryClasses(py::module &m) getFieldsCoefs : get fields for each coefficient set __call__ : same as getFields() but provides field labels in a tuple )", - py::arg("x"), py::arg("y"), py::arg("z")) + py::arg("x"), py::arg("y"), py::arg("z"), py::arg("origin") = false) .def("getAccel", py::overload_cast(&BasisClasses::BiorthBasis::getAccel), R"( - Return the acceleration for a given Cartesian position + Return the acceleration for a given Cartesian position in the frame defined by the coeffients. Parameters ---------- @@ -1571,7 +1574,7 @@ void BasisFactoryClasses(py::module &m) py::arg("x"), py::arg("y"), py::arg("z")) .def("getAccel", py::overload_cast, Eigen::Ref, Eigen::Ref>(&BasisClasses::BiorthBasis::getAccel), R"( - Return the acceleration for a given Cartesian position + Return the acceleration for a given Cartesian position in the frame defined by the coeffients. Parameters ---------- @@ -1595,7 +1598,7 @@ void BasisFactoryClasses(py::module &m) py::arg("x"), py::arg("y"), py::arg("z")) .def("getAccel", py::overload_cast>(&BasisClasses::BiorthBasis::getAccel), R"( - Return the acceleration for an array of Cartesian positions + Return the acceleration for an array of Cartesian positions in the frame defined by the coeffients. Parameters ---------- @@ -1615,7 +1618,7 @@ void BasisFactoryClasses(py::module &m) py::arg("pos")) .def("getAccelArray", py::overload_cast, Eigen::Ref, Eigen::Ref>(&BasisClasses::BiorthBasis::getAccel), R"( - Return the acceleration for a given Cartesian position + Return the acceleration for a given Cartesian position in the frame defined by the coeffients. Parameters ---------- @@ -1657,6 +1660,9 @@ void BasisFactoryClasses(py::module &m) z-axis position coefs: CoefClasses::Coefs the coefficient set + origin : bool + If true, the origin for field evaluations are is (0, 0, 0). + If false, the default, we use the frame defined by the coefficients. Returns ------- @@ -1668,7 +1674,7 @@ void BasisFactoryClasses(py::module &m) getFields : get fields for the currently assigned coefficients __call__ : same getFields() but provides field labels in a tuple )", - py::arg("x"), py::arg("y"), py::arg("z"), py::arg("coefs")) + py::arg("x"), py::arg("y"), py::arg("z"), py::arg("coefs"), py::arg("origin") = false) .def("setFieldType", &BasisClasses::BiorthBasis::setFieldType, R"( Set the coordinate system for force evaluations. The natural From 36bccc864d9e94d6db22cd5f4d614d14b700a575 Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Thu, 14 May 2026 16:57:02 -0400 Subject: [PATCH 03/24] Comment out downstream change for now --- expui/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expui/CMakeLists.txt b/expui/CMakeLists.txt index 7428bf796..15d7e4509 100644 --- a/expui/CMakeLists.txt +++ b/expui/CMakeLists.txt @@ -97,7 +97,7 @@ target_sources(expui PUBLIC FILE_SET HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../include/DiskWithHalo.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/EmpCyl2d.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/EXPmath.H - ${CMAKE_CURRENT_SOURCE_DIR}/../include/EXPversion.H + # ${CMAKE_CURRENT_SOURCE_DIR}/../include/EXPversion.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/libvars.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/Timer.H ${CMAKE_CURRENT_SOURCE_DIR}/../include/coef.H From c4124826f9bd5eae5283b19ba1052672b883002a Mon Sep 17 00:00:00 2001 From: Martin Weinberg Date: Thu, 14 May 2026 17:22:13 -0400 Subject: [PATCH 04/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- expui/BasisFactory.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/expui/BasisFactory.cc b/expui/BasisFactory.cc index 9ae2d2fa5..c90213378 100644 --- a/expui/BasisFactory.cc +++ b/expui/BasisFactory.cc @@ -259,15 +259,19 @@ namespace BasisClasses // Load the coefficients for the current time set_coefs(coefs->getCoefStruct(times[i])); - // Apply centering if requested + // Apply centering if requested without modifying the input + // coordinates so each time step is evaluated from the same point. + auto xc = x; + auto yc = y; + auto zc = z; if (not origin) { - x -= coefctr(0); - y -= coefctr(1); - z -= coefctr(2); + xc -= coefctr(0); + yc -= coefctr(1); + zc -= coefctr(2); } // The field evaluation - auto v = crt_eval(x, y, z); + auto v = crt_eval(xc, yc, zc); // Pack the fields into the dictionary for (int j=0; j Date: Thu, 14 May 2026 17:22:28 -0400 Subject: [PATCH 05/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- expui/BasisFactory.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expui/BasisFactory.H b/expui/BasisFactory.H index f0520d524..4868831f7 100644 --- a/expui/BasisFactory.H +++ b/expui/BasisFactory.H @@ -209,7 +209,7 @@ namespace BasisClasses //! Evaluate fields at a point, and provide field lables virtual std::tuple, std::vector> evaluate(double x, double y, double z) - { return {getFields(x, y, z, true), getFieldLabels(coordinates)}; } + { return {getFields(x, y, z), getFieldLabels(coordinates)}; } //! Retrieve the coefficients virtual CoefClasses::CoefStrPtr getCoefficients() From 84318e7f2bfe65c206c6775b84372b1ed7855733 Mon Sep 17 00:00:00 2001 From: Martin Weinberg Date: Thu, 14 May 2026 17:22:47 -0400 Subject: [PATCH 06/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- pyEXP/BasisWrappers.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index 0ed0247d4..d9477de1e 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -1535,7 +1535,7 @@ void BasisFactoryClasses(py::module &m) z : float z-axis position origin : bool - If true, the origin for field evaluations are is (0, 0, 0). + If true, the origin for field evaluations is (0, 0, 0). If false, the default, we use the frame defined by the coefficients. Returns From 41f1baa2fb1479f5db018cdb1e8c0c13ab56721a Mon Sep 17 00:00:00 2001 From: Martin Weinberg Date: Thu, 14 May 2026 17:23:01 -0400 Subject: [PATCH 07/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- pyEXP/BasisWrappers.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index d9477de1e..c38ec96af 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -1661,7 +1661,7 @@ void BasisFactoryClasses(py::module &m) coefs: CoefClasses::Coefs the coefficient set origin : bool - If true, the origin for field evaluations are is (0, 0, 0). + If true, the origin for field evaluations is (0, 0, 0). If false, the default, we use the frame defined by the coefficients. Returns From f41e050c108974ab9428f2c08fe587818418ee0d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 May 2026 21:41:35 +0000 Subject: [PATCH 08/24] fix pyexp getAccel docstring typo Agent-Logs-Url: https://github.com/EXP-code/EXP/sessions/5f75bca1-eb95-4f51-8ab6-9272eb114eca Co-authored-by: The9Cat <25960766+The9Cat@users.noreply.github.com> --- pyEXP/BasisWrappers.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index c38ec96af..94c5fe3da 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -1550,7 +1550,7 @@ void BasisFactoryClasses(py::module &m) py::arg("x"), py::arg("y"), py::arg("z"), py::arg("origin") = false) .def("getAccel", py::overload_cast(&BasisClasses::BiorthBasis::getAccel), R"( - Return the acceleration for a given Cartesian position in the frame defined by the coeffients. + Return the acceleration for a given Cartesian position in the frame defined by the coefficients. Parameters ---------- From fc5a60af2f1b466bfa9fa3a973c599f2cfe6bb6f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 May 2026 21:44:45 +0000 Subject: [PATCH 09/24] fix remaining getAccel docstring typos Agent-Logs-Url: https://github.com/EXP-code/EXP/sessions/56a9b4d8-bfcc-4bf8-9b5d-ccaa48888105 Co-authored-by: The9Cat <25960766+The9Cat@users.noreply.github.com> --- extern/yaml-cpp | 2 +- pyEXP/BasisWrappers.cc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extern/yaml-cpp b/extern/yaml-cpp index da82fd982..4861d0495 160000 --- a/extern/yaml-cpp +++ b/extern/yaml-cpp @@ -1 +1 @@ -Subproject commit da82fd982c260e7f335ce5acbceff24b270544d1 +Subproject commit 4861d049534ed6f2c51c45b01d7c2926022e5f3f diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index 94c5fe3da..ef8b56ed4 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -1574,7 +1574,7 @@ void BasisFactoryClasses(py::module &m) py::arg("x"), py::arg("y"), py::arg("z")) .def("getAccel", py::overload_cast, Eigen::Ref, Eigen::Ref>(&BasisClasses::BiorthBasis::getAccel), R"( - Return the acceleration for a given Cartesian position in the frame defined by the coeffients. + Return the acceleration for a given Cartesian position in the frame defined by the coefficients. Parameters ---------- @@ -1598,7 +1598,7 @@ void BasisFactoryClasses(py::module &m) py::arg("x"), py::arg("y"), py::arg("z")) .def("getAccel", py::overload_cast>(&BasisClasses::BiorthBasis::getAccel), R"( - Return the acceleration for an array of Cartesian positions in the frame defined by the coeffients. + Return the acceleration for an array of Cartesian positions in the frame defined by the coefficients. Parameters ---------- @@ -1618,7 +1618,7 @@ void BasisFactoryClasses(py::module &m) py::arg("pos")) .def("getAccelArray", py::overload_cast, Eigen::Ref, Eigen::Ref>(&BasisClasses::BiorthBasis::getAccel), R"( - Return the acceleration for a given Cartesian position in the frame defined by the coeffients. + Return the acceleration for a given Cartesian position in the frame defined by the coefficients. Parameters ---------- From 5592209cb7169085a39396c33ca6205ac01c214b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 May 2026 21:45:31 +0000 Subject: [PATCH 10/24] doc: add ABI-breaking change notes to getFields methods Agent-Logs-Url: https://github.com/EXP-code/EXP/sessions/56a9b4d8-bfcc-4bf8-9b5d-ccaa48888105 Co-authored-by: The9Cat <25960766+The9Cat@users.noreply.github.com> --- expui/BasisFactory.H | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/expui/BasisFactory.H b/expui/BasisFactory.H index 4868831f7..74dc72cfc 100644 --- a/expui/BasisFactory.H +++ b/expui/BasisFactory.H @@ -197,10 +197,16 @@ namespace BasisClasses const Coord ctype=Coord::Spherical); //! Evaluate fields at a point + //! @note API change in v7.10.3: Added 'origin' parameter (default=false). + //! This is an ABI-breaking change for external C++ code that + //! subclasses Basis or calls these methods via vtable. virtual std::vector getFields(double x, double y, double z, bool origin=false); //! Evaluate fields at a point for all coefficients sets + //! @note API change in v7.10.3: Added 'origin' parameter (default=false). + //! This is an ABI-breaking change for external C++ code that + //! subclasses Basis or calls these methods via vtable. virtual std::tuple, Eigen::VectorXd> getFieldsCoefs (double x, double y, double z, std::shared_ptr coefs, From 86337c3c6271a43755f827fb999a11c8f03255ed Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Thu, 14 May 2026 18:57:40 -0400 Subject: [PATCH 11/24] Minor simplyfing updates and improved doctstrings --- expui/BasisFactory.cc | 20 ++++++++------------ extern/yaml-cpp | 2 +- pyEXP/BasisWrappers.cc | 12 ++++++++++-- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/expui/BasisFactory.cc b/expui/BasisFactory.cc index c90213378..dd536f94d 100644 --- a/expui/BasisFactory.cc +++ b/expui/BasisFactory.cc @@ -254,24 +254,20 @@ namespace BasisClasses auto fields = getFieldLabels(coordinates); for (auto s : fields) ret[s].resize(times.size()); + // Apply centering + if (not origin) { + x -= coefctr(0); + y -= coefctr(1); + z -= coefctr(2); + } + // Make the return dictionary of arrays for (int i=0; igetCoefStruct(times[i])); - // Apply centering if requested without modifying the input - // coordinates so each time step is evaluated from the same point. - auto xc = x; - auto yc = y; - auto zc = z; - if (not origin) { - xc -= coefctr(0); - yc -= coefctr(1); - zc -= coefctr(2); - } - // The field evaluation - auto v = crt_eval(xc, yc, zc); + auto v = crt_eval(x, y, z); // Pack the fields into the dictionary for (int j=0; j Date: Thu, 14 May 2026 22:51:54 -0400 Subject: [PATCH 12/24] Fix time varying centering; evaluate() should use (0, 0, 0) as origin --- expui/BasisFactory.H | 2 +- expui/BasisFactory.cc | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/expui/BasisFactory.H b/expui/BasisFactory.H index 74dc72cfc..20d10b1e5 100644 --- a/expui/BasisFactory.H +++ b/expui/BasisFactory.H @@ -215,7 +215,7 @@ namespace BasisClasses //! Evaluate fields at a point, and provide field lables virtual std::tuple, std::vector> evaluate(double x, double y, double z) - { return {getFields(x, y, z), getFieldLabels(coordinates)}; } + { return {getFields(x, y, z, true), getFieldLabels(coordinates)}; } //! Retrieve the coefficients virtual CoefClasses::CoefStrPtr getCoefficients() diff --git a/expui/BasisFactory.cc b/expui/BasisFactory.cc index dd536f94d..04d483285 100644 --- a/expui/BasisFactory.cc +++ b/expui/BasisFactory.cc @@ -254,20 +254,21 @@ namespace BasisClasses auto fields = getFieldLabels(coordinates); for (auto s : fields) ret[s].resize(times.size()); - // Apply centering - if (not origin) { - x -= coefctr(0); - y -= coefctr(1); - z -= coefctr(2); - } - // Make the return dictionary of arrays for (int i=0; igetCoefStruct(times[i])); + double xc = x, yc = y, zc = z; + // Apply centering + if (not origin) { + xc -= coefctr(0); + yc -= coefctr(1); + zc -= coefctr(2); + } + // The field evaluation - auto v = crt_eval(x, y, z); + auto v = crt_eval(xc, yc, zc); // Pack the fields into the dictionary for (int j=0; j Date: Fri, 15 May 2026 03:02:11 +0000 Subject: [PATCH 13/24] Add backward-compatible dispatch in PyBasis trampoline for getFields/getFieldsCoefs Agent-Logs-Url: https://github.com/EXP-code/EXP/sessions/48c9ee4b-35ac-4a63-b3cb-8ecac31ecc71 Co-authored-by: The9Cat <25960766+The9Cat@users.noreply.github.com> --- pyEXP/BasisWrappers.cc | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index 7d42b322f..bef77aaab 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -332,7 +332,24 @@ void BasisFactoryClasses(py::module &m) std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, Basis, getFields, x, y, z, origin); + pybind11::gil_scoped_acquire gil; + pybind11::function override_func = + pybind11::get_override(static_cast(this), "getFields"); + if (override_func) { + try { + auto result = override_func(x, y, z, origin); + return result.cast>(); + } catch (pybind11::error_already_set& e) { + if (e.matches(PyExc_TypeError)) { + // Backward-compatible fallback for subclasses with 3-arg signature + PyErr_Clear(); + auto result = override_func(x, y, z); + return result.cast>(); + } + throw; + } + } + return Basis::getFields(x, y, z, origin); } using FCReturn = std::tuple, @@ -341,7 +358,24 @@ void BasisFactoryClasses(py::module &m) FCReturn getFieldsCoefs (double x, double y, double z, CoefClasses::CoefsPtr coefs, bool origin) override { - PYBIND11_OVERRIDE(FCReturn, Basis, getFieldsCoefs, x, y, z, coefs, origin); + pybind11::gil_scoped_acquire gil; + pybind11::function override_func = + pybind11::get_override(static_cast(this), "getFieldsCoefs"); + if (override_func) { + try { + auto result = override_func(x, y, z, coefs, origin); + return result.cast(); + } catch (pybind11::error_already_set& e) { + if (e.matches(PyExc_TypeError)) { + // Backward-compatible fallback for subclasses with 4-arg signature + PyErr_Clear(); + auto result = override_func(x, y, z, coefs); + return result.cast(); + } + throw; + } + } + return Basis::getFieldsCoefs(x, y, z, coefs, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override { From 080818a1ec645cce069983fd16bdf479e7906bde Mon Sep 17 00:00:00 2001 From: Martin Weinberg Date: Fri, 15 May 2026 08:25:26 -0400 Subject: [PATCH 14/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- expui/BasisFactory.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expui/BasisFactory.H b/expui/BasisFactory.H index 20d10b1e5..38623af6a 100644 --- a/expui/BasisFactory.H +++ b/expui/BasisFactory.H @@ -212,7 +212,7 @@ namespace BasisClasses (double x, double y, double z, std::shared_ptr coefs, bool origin=false); - //! Evaluate fields at a point, and provide field lables + //! Evaluate fields at a point, and provide field labels virtual std::tuple, std::vector> evaluate(double x, double y, double z) { return {getFields(x, y, z, true), getFieldLabels(coordinates)}; } From b0f76704fcccaadc5a98ab4b5c4f61bb0bda128a Mon Sep 17 00:00:00 2001 From: Martin Weinberg Date: Fri, 15 May 2026 08:26:15 -0400 Subject: [PATCH 15/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- pyEXP/BasisWrappers.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index bef77aaab..f6dcfcf19 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -470,7 +470,20 @@ void BasisFactoryClasses(py::module &m) std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, FieldBasis, getFields, x, y, z, origin); + py::gil_scoped_acquire gil; + py::function override = py::get_override(static_cast(this), "getFields"); + + if (override) { + try { + return override(x, y, z, origin).cast>(); + } catch (py::error_already_set &e) { + if (!e.matches(PyExc_TypeError)) throw; + e.clear(); + return override(x, y, z).cast>(); + } + } + + return FieldBasis::getFields(x, y, z, origin); } void accumulate(double m, double x, double y, double z, From f91be483733724d14b2827a8fa8ddc389dc576bd Mon Sep 17 00:00:00 2001 From: Martin Weinberg Date: Fri, 15 May 2026 08:26:54 -0400 Subject: [PATCH 16/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- pyEXP/BasisWrappers.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index f6dcfcf19..ffdbbcf44 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -609,7 +609,16 @@ void BasisFactoryClasses(py::module &m) using Spherical::Spherical; std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, Spherical, getFields, x, y, z, origin); + py::function override = py::get_override(static_cast(this), "getFields"); + if (override) { + try { + return py::cast>(override(x, y, z, origin)); + } catch (py::error_already_set &e) { + if (!e.matches(PyExc_TypeError)) throw; + } + return py::cast>(override(x, y, z)); + } + return Spherical::getFields(x, y, z, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override { From be7160ba6b406ffd4316c034fa6a76bb9e98fe1a Mon Sep 17 00:00:00 2001 From: Martin Weinberg Date: Fri, 15 May 2026 08:27:16 -0400 Subject: [PATCH 17/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- pyEXP/BasisWrappers.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index ffdbbcf44..d3e798a4e 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -845,7 +845,18 @@ void BasisFactoryClasses(py::module &m) std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, CBDisk, getFields, x, y, z, origin); + py::gil_scoped_acquire gil; + py::function override = py::get_override(this, "getFields"); + if (override) { + try { + return override(x, y, z, origin).cast>(); + } catch (py::error_already_set &e) { + if (!e.matches(PyExc_TypeError)) throw; + PyErr_Clear(); + return override(x, y, z).cast>(); + } + } + return CBDisk::getFields(x, y, z, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override From a368b1192b4a610eb82935ce6e576411543e7374 Mon Sep 17 00:00:00 2001 From: Martin Weinberg Date: Fri, 15 May 2026 08:28:18 -0400 Subject: [PATCH 18/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- pyEXP/BasisWrappers.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index d3e798a4e..0e0f144ce 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -930,7 +930,19 @@ void BasisFactoryClasses(py::module &m) std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, Slab, getFields, x, y, z, origin); + py::gil_scoped_acquire gil; + py::function overload = py::get_overload(static_cast(this), "getFields"); + if (overload) { + try { + return overload(x, y, z, origin).cast>(); + } catch (py::error_already_set &e) { + if (!e.matches(PyExc_TypeError)) throw; + } + + return overload(x, y, z).cast>(); + } + + return Slab::getFields(x, y, z, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override From 50ebb05c9a2fe3ca01e3c758536accb366a91c70 Mon Sep 17 00:00:00 2001 From: Martin Weinberg Date: Fri, 15 May 2026 08:28:36 -0400 Subject: [PATCH 19/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- pyEXP/BasisWrappers.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index 0e0f144ce..7d519c203 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -1016,7 +1016,19 @@ void BasisFactoryClasses(py::module &m) std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, Cube, getFields, x, y, z, origin); + py::function override = py::get_override(this, "getFields"); + if (override) { + try { + return override(x, y, z, origin).cast>(); + } catch (py::error_already_set &e) { + if (e.matches(PyExc_TypeError)) { + e.clear(); + return override(x, y, z).cast>(); + } + throw; + } + } + return Cube::getFields(x, y, z, origin); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override From d650ae1d78d088d814f227170d95ad88310e3f58 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 12:28:48 +0000 Subject: [PATCH 20/24] Guard Cylindrical::computeAccel against R=0 at coefficient center Agent-Logs-Url: https://github.com/EXP-code/EXP/sessions/588ca0c8-f717-4041-8cf3-86e2c5314792 Co-authored-by: The9Cat <25960766+The9Cat@users.noreply.github.com> --- expui/BiorthBasis.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/expui/BiorthBasis.cc b/expui/BiorthBasis.cc index fee2ccc54..caa7db062 100644 --- a/expui/BiorthBasis.cc +++ b/expui/BiorthBasis.cc @@ -1823,8 +1823,12 @@ namespace BasisClasses tdens = sl->accumulated_dens_eval(R, z, phi, tdens0); - double tpotx = tpotR*x/R - tpotp*y/R ; - double tpoty = tpotR*y/R + tpotp*x/R ; + double tpotx = 0.0; + double tpoty = 0.0; + if (R > 0.0) { + tpotx = tpotR*x/R - tpotp*y/R; + tpoty = tpotR*y/R + tpotp*x/R; + } // Apply G to forces on return acc << tpotx*G, tpoty*G, tpotz*G; From 83ee34e5f1c4037f2abb83bc18743148d77964ab Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Fri, 15 May 2026 08:32:34 -0400 Subject: [PATCH 21/24] Flip defaults to retain previous behavior in 'getFields' calls --- expui/BasisFactory.H | 8 ++++---- pyEXP/BasisWrappers.cc | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/expui/BasisFactory.H b/expui/BasisFactory.H index 20d10b1e5..a16dfaf64 100644 --- a/expui/BasisFactory.H +++ b/expui/BasisFactory.H @@ -197,20 +197,20 @@ namespace BasisClasses const Coord ctype=Coord::Spherical); //! Evaluate fields at a point - //! @note API change in v7.10.3: Added 'origin' parameter (default=false). + //! @note API change in v7.10.3: Added 'origin' parameter (default=true). //! This is an ABI-breaking change for external C++ code that //! subclasses Basis or calls these methods via vtable. virtual std::vector getFields(double x, double y, double z, - bool origin=false); + bool origin=true); //! Evaluate fields at a point for all coefficients sets - //! @note API change in v7.10.3: Added 'origin' parameter (default=false). + //! @note API change in v7.10.3: Added 'origin' parameter (default=true). //! This is an ABI-breaking change for external C++ code that //! subclasses Basis or calls these methods via vtable. virtual std::tuple, Eigen::VectorXd> getFieldsCoefs (double x, double y, double z, std::shared_ptr coefs, - bool origin=false); + bool origin=true); //! Evaluate fields at a point, and provide field lables virtual std::tuple, std::vector> diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index bef77aaab..e16da744f 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -1556,9 +1556,9 @@ void BasisFactoryClasses(py::module &m) potential evaluations are separated into full, axisymmetric and non-axisymmetric contributions. - The origin for field evaluations is the frame defined by the - coefficients by default. Setting 'origin=True' will use the - origin (0, 0, 0) for field evaluations instead. + The origin for field evaluations is the expansion origin by + default ('origin=True') Setting 'origin=False' will use the + origin defined by the coefficients for field evaluations instead. You can get the field labels by using the __call__ method of the basis object. This is equivalent to a tuple of the getFields() @@ -1573,8 +1573,8 @@ void BasisFactoryClasses(py::module &m) z : float z-axis position origin : bool - If true, the origin for field evaluations is (0, 0, 0). - If false, the default, we use the frame defined by the coefficients. + If true, the default, origin for field evaluations is (0, 0, 0). + If false, we use the frame defined by the coefficients. Returns ------- @@ -1585,7 +1585,7 @@ void BasisFactoryClasses(py::module &m) getFieldsCoefs : get fields for each coefficient set __call__ : same as getFields() but provides field labels in a tuple )", - py::arg("x"), py::arg("y"), py::arg("z"), py::arg("origin") = false) + py::arg("x"), py::arg("y"), py::arg("z"), py::arg("origin") = true) .def("getAccel", py::overload_cast(&BasisClasses::BiorthBasis::getAccel), R"( Return the acceleration for a given Cartesian position in the frame defined by the coefficients. @@ -1684,9 +1684,9 @@ void BasisFactoryClasses(py::module &m) for every frame in a coefficient set. The field evaluations are produced by a call to getFields(). - The origin for field evaluations is the frame defined by the - coefficients by default. Setting 'origin=True' will use the - origin (0, 0, 0) for field evaluations instead. + The origin for field evaluations is the expansion origin by + default ('origin=True') Setting 'origin=False' will use the + origin defined by the coefficients for field evaluations instead. You get a dictionary of fields keyed by field name and an array of evaluation times for convenience. These times will be the same @@ -1703,8 +1703,8 @@ void BasisFactoryClasses(py::module &m) coefs: CoefClasses::Coefs the coefficient set origin : bool - If true, the origin for field evaluations is (0, 0, 0). - If false, the default, we use the frame defined by the coefficients. + If true, the default, origin for field evaluations is (0, 0, 0). + If false, we use the frame defined by the coefficients. Returns ------- @@ -1716,7 +1716,7 @@ void BasisFactoryClasses(py::module &m) getFields : get fields for the currently assigned coefficients __call__ : same getFields() but provides field labels in a tuple )", - py::arg("x"), py::arg("y"), py::arg("z"), py::arg("coefs"), py::arg("origin") = false) + py::arg("x"), py::arg("y"), py::arg("z"), py::arg("coefs"), py::arg("origin") = true) .def("setFieldType", &BasisClasses::BiorthBasis::setFieldType, R"( Set the coordinate system for force evaluations. The natural From 161b06029950b6269acb52de97a943a65e36f281 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 12:40:34 +0000 Subject: [PATCH 22/24] Guard FlatDisk and CBDisk computeAccel against R=0 at coefficient center Agent-Logs-Url: https://github.com/EXP-code/EXP/sessions/5de301ef-07d4-4d2c-8595-cf3fe1b35194 Co-authored-by: The9Cat <25960766+The9Cat@users.noreply.github.com> --- expui/BiorthBasis.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/expui/BiorthBasis.cc b/expui/BiorthBasis.cc index caa7db062..b5fbe4870 100644 --- a/expui/BiorthBasis.cc +++ b/expui/BiorthBasis.cc @@ -2584,8 +2584,12 @@ namespace BasisClasses zpot *= -G; ppot *= -G; - double potx = rpot*x/R - ppot*y/R; - double poty = rpot*y/R + ppot*x/R; + double potx = 0.0; + double poty = 0.0; + if (R > 0.0) { + potx = rpot*x/R - ppot*y/R; + poty = rpot*y/R + ppot*x/R; + } acc << potx, poty, zpot; } @@ -3354,8 +3358,12 @@ namespace BasisClasses rpot *= -G; ppot *= -G; - double potx = rpot*x/R - ppot*y/R; - double poty = rpot*y/R + ppot*x/R; + double potx = 0.0; + double poty = 0.0; + if (R > 0.0) { + potx = rpot*x/R - ppot*y/R; + poty = rpot*y/R + ppot*x/R; + } acc << potx, poty, zpot; } From d85e94f1547e25cbab75890362c34688b79c39db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 14:40:27 +0000 Subject: [PATCH 23/24] Refactor getFields API and add getFieldsOrigin methods Agent-Logs-Url: https://github.com/EXP-code/EXP/sessions/fe07195b-408a-42d0-b748-e96ed78bf175 Co-authored-by: The9Cat <25960766+The9Cat@users.noreply.github.com> --- expui/BasisFactory.H | 28 +++--- expui/BasisFactory.cc | 61 ++++++++---- expui/BiorthBasis.cc | 10 +- pyEXP/BasisWrappers.cc | 204 ++++++++++++++++------------------------- 4 files changed, 143 insertions(+), 160 deletions(-) diff --git a/expui/BasisFactory.H b/expui/BasisFactory.H index 052bfe536..6f3351497 100644 --- a/expui/BasisFactory.H +++ b/expui/BasisFactory.H @@ -196,26 +196,28 @@ namespace BasisClasses operator()(double x1, double x2, double x3, const Coord ctype=Coord::Spherical); - //! Evaluate fields at a point - //! @note API change in v7.10.3: Added 'origin' parameter (default=true). - //! This is an ABI-breaking change for external C++ code that - //! subclasses Basis or calls these methods via vtable. - virtual std::vector getFields(double x, double y, double z, - bool origin=true); + //! Evaluate fields at a point in the expansion-origin frame + virtual std::vector getFields(double x, double y, double z); + + //! Evaluate fields at a point in the coefficient-origin frame + virtual std::vector getFieldsOrigin(double x, double y, double z); - //! Evaluate fields at a point for all coefficients sets - //! @note API change in v7.10.3: Added 'origin' parameter (default=true). - //! This is an ABI-breaking change for external C++ code that - //! subclasses Basis or calls these methods via vtable. + //! Evaluate fields at a point for all coefficients sets in the + //! expansion-origin frame virtual std::tuple, Eigen::VectorXd> getFieldsCoefs - (double x, double y, double z, std::shared_ptr coefs, - bool origin=true); + (double x, double y, double z, std::shared_ptr coefs); + + //! Evaluate fields at a point for all coefficients sets in the + //! coefficient-origin frame + virtual std::tuple, + Eigen::VectorXd> getFieldsCoefsOrigin + (double x, double y, double z, std::shared_ptr coefs); //! Evaluate fields at a point, and provide field labels virtual std::tuple, std::vector> evaluate(double x, double y, double z) - { return {getFields(x, y, z, true), getFieldLabels(coordinates)}; } + { return {getFields(x, y, z), getFieldLabels(coordinates)}; } //! Retrieve the coefficients virtual CoefClasses::CoefStrPtr getCoefficients() diff --git a/expui/BasisFactory.cc b/expui/BasisFactory.cc index 04d483285..77a0cd875 100644 --- a/expui/BasisFactory.cc +++ b/expui/BasisFactory.cc @@ -228,21 +228,54 @@ namespace BasisClasses }; } - std::vector Basis::getFields(double x, double y, double z, - bool origin) + std::vector Basis::getFields(double x, double y, double z) + { return crt_eval(x, y, z); } + + std::vector Basis::getFieldsOrigin(double x, double y, double z) { - if (not origin) { - x -= coefctr(0); - y -= coefctr(1); - z -= coefctr(2); - } + x -= coefctr(0); + y -= coefctr(1); + z -= coefctr(2); return crt_eval(x, y, z); } std::tuple, Eigen::VectorXd> Basis::getFieldsCoefs - (double x, double y, double z, std::shared_ptr coefs, - bool origin) + (double x, double y, double z, std::shared_ptr coefs) + { + // Python dictonary for return + std::map ret; + + // Times for the coefficients + auto times = coefs->Times(); + + // Initialize the dictionary/map + auto fields = getFieldLabels(coordinates); + for (auto s : fields) ret[s].resize(times.size()); + + // Make the return dictionary of arrays + for (int i=0; igetCoefStruct(times[i])); + + // The field evaluation + auto v = crt_eval(x, y, z); + + // Pack the fields into the dictionary + for (int j=0; j(times.data(), times.size()); + + // Return the dictionary and the time array + return {ret, T}; + } + + std::tuple, Eigen::VectorXd> + Basis::getFieldsCoefsOrigin + (double x, double y, double z, std::shared_ptr coefs) { // Python dictonary for return std::map ret; @@ -259,16 +292,8 @@ namespace BasisClasses // Load the coefficients for the current time set_coefs(coefs->getCoefStruct(times[i])); - double xc = x, yc = y, zc = z; - // Apply centering - if (not origin) { - xc -= coefctr(0); - yc -= coefctr(1); - zc -= coefctr(2); - } - // The field evaluation - auto v = crt_eval(xc, yc, zc); + auto v = getFieldsOrigin(x, y, z); // Pack the fields into the dictionary for (int j=0; jaccumulated_dens_eval(R, z, phi, tdens0); - double tpotx = tpotR*x/R - tpotp*y/R ; - double tpoty = tpotR*y/R + tpotp*x/R ; + double tpotx = 0.0; + double tpoty = 0.0; + if (R > 0.0) { + tpotx = tpotR*x/R - tpotp*y/R; + tpoty = tpotR*y/R + tpotp*x/R; + } return {tdens0, tdens - tdens0, tdens, @@ -4823,7 +4827,7 @@ namespace BasisClasses for (int k=0; k<3; k++) pp(k) = ps(n, k) - ctr(k); pp = rot * pp; - auto v = basis->getFields(pp(0), pp(1), pp(2), true); + auto v = basis->getFields(pp(0), pp(1), pp(2)); // First 6 fields are density and potential, followed by acceleration for (int k=0; k<3; k++) accel(n, k) += v[6+k] - basis->pseudo(k); diff --git a/pyEXP/BasisWrappers.cc b/pyEXP/BasisWrappers.cc index 43f8bc185..6da222c1a 100644 --- a/pyEXP/BasisWrappers.cc +++ b/pyEXP/BasisWrappers.cc @@ -330,52 +330,18 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using BasisClasses::Basis::Basis; - std::vector getFields(double x, double y, double z, bool origin) override - { - pybind11::gil_scoped_acquire gil; - pybind11::function override_func = - pybind11::get_override(static_cast(this), "getFields"); - if (override_func) { - try { - auto result = override_func(x, y, z, origin); - return result.cast>(); - } catch (pybind11::error_already_set& e) { - if (e.matches(PyExc_TypeError)) { - // Backward-compatible fallback for subclasses with 3-arg signature - PyErr_Clear(); - auto result = override_func(x, y, z); - return result.cast>(); - } - throw; - } - } - return Basis::getFields(x, y, z, origin); + std::vector getFields(double x, double y, double z) override + { + PYBIND11_OVERRIDE(std::vector, Basis, getFields, x, y, z); } using FCReturn = std::tuple, Eigen::VectorXd>; FCReturn getFieldsCoefs - (double x, double y, double z, CoefClasses::CoefsPtr coefs, bool origin) override - { - pybind11::gil_scoped_acquire gil; - pybind11::function override_func = - pybind11::get_override(static_cast(this), "getFieldsCoefs"); - if (override_func) { - try { - auto result = override_func(x, y, z, coefs, origin); - return result.cast(); - } catch (pybind11::error_already_set& e) { - if (e.matches(PyExc_TypeError)) { - // Backward-compatible fallback for subclasses with 4-arg signature - PyErr_Clear(); - auto result = override_func(x, y, z, coefs); - return result.cast(); - } - throw; - } - } - return Basis::getFieldsCoefs(x, y, z, coefs, origin); + (double x, double y, double z, CoefClasses::CoefsPtr coefs) override + { + PYBIND11_OVERRIDE(FCReturn, Basis, getFieldsCoefs, x, y, z, coefs); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override { @@ -468,22 +434,9 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using FieldBasis::FieldBasis; - std::vector getFields(double x, double y, double z, bool origin) override + std::vector getFields(double x, double y, double z) override { - py::gil_scoped_acquire gil; - py::function override = py::get_override(static_cast(this), "getFields"); - - if (override) { - try { - return override(x, y, z, origin).cast>(); - } catch (py::error_already_set &e) { - if (!e.matches(PyExc_TypeError)) throw; - e.clear(); - return override(x, y, z).cast>(); - } - } - - return FieldBasis::getFields(x, y, z, origin); + PYBIND11_OVERRIDE(std::vector, FieldBasis, getFields, x, y, z); } void accumulate(double m, double x, double y, double z, @@ -608,17 +561,12 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using Spherical::Spherical; - std::vector getFields(double x, double y, double z, bool origin) override { + std::vector getFields(double x, double y, double z) override { py::function override = py::get_override(static_cast(this), "getFields"); if (override) { - try { - return py::cast>(override(x, y, z, origin)); - } catch (py::error_already_set &e) { - if (!e.matches(PyExc_TypeError)) throw; - } return py::cast>(override(x, y, z)); } - return Spherical::getFields(x, y, z, origin); + return Spherical::getFields(x, y, z); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override { @@ -683,8 +631,8 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using Cylindrical::Cylindrical; - std::vector getFields(double x, double y, double z, bool origin) override { - PYBIND11_OVERRIDE(std::vector, Cylindrical, getFields, x, y, z, origin); + std::vector getFields(double x, double y, double z) override { + PYBIND11_OVERRIDE(std::vector, Cylindrical, getFields, x, y, z); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override { @@ -761,9 +709,9 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using FlatDisk::FlatDisk; - std::vector getFields(double x, double y, double z, bool origin) override + std::vector getFields(double x, double y, double z) override { - PYBIND11_OVERRIDE(std::vector, FlatDisk, getFields, x, y, z, origin); + PYBIND11_OVERRIDE(std::vector, FlatDisk, getFields, x, y, z); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override @@ -843,20 +791,9 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using CBDisk::CBDisk; - std::vector getFields(double x, double y, double z, bool origin) override + std::vector getFields(double x, double y, double z) override { - py::gil_scoped_acquire gil; - py::function override = py::get_override(this, "getFields"); - if (override) { - try { - return override(x, y, z, origin).cast>(); - } catch (py::error_already_set &e) { - if (!e.matches(PyExc_TypeError)) throw; - PyErr_Clear(); - return override(x, y, z).cast>(); - } - } - return CBDisk::getFields(x, y, z, origin); + PYBIND11_OVERRIDE(std::vector, CBDisk, getFields, x, y, z); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override @@ -928,21 +865,9 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using Slab::Slab; - std::vector getFields(double x, double y, double z, bool origin) override + std::vector getFields(double x, double y, double z) override { - py::gil_scoped_acquire gil; - py::function overload = py::get_overload(static_cast(this), "getFields"); - if (overload) { - try { - return overload(x, y, z, origin).cast>(); - } catch (py::error_already_set &e) { - if (!e.matches(PyExc_TypeError)) throw; - } - - return overload(x, y, z).cast>(); - } - - return Slab::getFields(x, y, z, origin); + PYBIND11_OVERRIDE(std::vector, Slab, getFields, x, y, z); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override @@ -1014,21 +939,9 @@ void BasisFactoryClasses(py::module &m) // Inherit the constructors using Cube::Cube; - std::vector getFields(double x, double y, double z, bool origin) override + std::vector getFields(double x, double y, double z) override { - py::function override = py::get_override(this, "getFields"); - if (override) { - try { - return override(x, y, z, origin).cast>(); - } catch (py::error_already_set &e) { - if (e.matches(PyExc_TypeError)) { - e.clear(); - return override(x, y, z).cast>(); - } - throw; - } - } - return Cube::getFields(x, y, z, origin); + PYBIND11_OVERRIDE(std::vector, Cube, getFields, x, y, z); } void accumulate(double x, double y, double z, double mass, unsigned long int indx) override @@ -1613,13 +1526,9 @@ void BasisFactoryClasses(py::module &m) potential evaluations are separated into full, axisymmetric and non-axisymmetric contributions. - The origin for field evaluations is the expansion origin by - default ('origin=True') Setting 'origin=False' will use the - origin defined by the coefficients for field evaluations instead. - You can get the field labels by using the __call__ method of the basis object. This is equivalent to a tuple of the getFields() - output with a list of field labels with 'origin=True'. + output with a list of field labels. Parameters ---------- @@ -1629,9 +1538,6 @@ void BasisFactoryClasses(py::module &m) y-axis position z : float z-axis position - origin : bool - If true, the default, origin for field evaluations is (0, 0, 0). - If false, we use the frame defined by the coefficients. Returns ------- @@ -1639,10 +1545,35 @@ void BasisFactoryClasses(py::module &m) See also -------- + getFieldsOrigin: get fields in coefficient-origin frame getFieldsCoefs : get fields for each coefficient set __call__ : same as getFields() but provides field labels in a tuple )", - py::arg("x"), py::arg("y"), py::arg("z"), py::arg("origin") = true) + py::arg("x"), py::arg("y"), py::arg("z")) + .def("getFieldsOrigin", &BasisClasses::BiorthBasis::getFieldsOrigin, + R"( + Return the field evaluations for a given Cartesian position in + the frame defined by the current coefficients. + + Parameters + ---------- + x : float + x-axis position + y : float + y-axis position + z : float + z-axis position + + Returns + ------- + fields: numpy.ndarray + + See also + -------- + getFields : get fields in expansion-origin frame + getFieldsCoefs : get fields for each coefficient set + )", + py::arg("x"), py::arg("y"), py::arg("z")) .def("getAccel", py::overload_cast(&BasisClasses::BiorthBasis::getAccel), R"( Return the acceleration for a given Cartesian position in the frame defined by the coefficients. @@ -1741,10 +1672,6 @@ void BasisFactoryClasses(py::module &m) for every frame in a coefficient set. The field evaluations are produced by a call to getFields(). - The origin for field evaluations is the expansion origin by - default ('origin=True') Setting 'origin=False' will use the - origin defined by the coefficients for field evaluations instead. - You get a dictionary of fields keyed by field name and an array of evaluation times for convenience. These times will be the same as Times() for the coefficient object. @@ -1759,9 +1686,6 @@ void BasisFactoryClasses(py::module &m) z-axis position coefs: CoefClasses::Coefs the coefficient set - origin : bool - If true, the default, origin for field evaluations is (0, 0, 0). - If false, we use the frame defined by the coefficients. Returns ------- @@ -1770,10 +1694,38 @@ void BasisFactoryClasses(py::module &m) See also -------- - getFields : get fields for the currently assigned coefficients - __call__ : same getFields() but provides field labels in a tuple + getFields : get fields for the currently assigned coefficients + getFieldsOrigin : get fields in coefficient-origin frame + __call__ : same getFields() but provides field labels in a tuple + )", + py::arg("x"), py::arg("y"), py::arg("z"), py::arg("coefs")) + .def("getFieldsCoefsOrigin", &BasisClasses::BiorthBasis::getFieldsCoefsOrigin, + R"( + Return the field evaluations for a given Cartesian position + for every frame in a coefficient set in the frame defined by + each coefficient structure. + + Parameters + ---------- + x : float + x-axis position + y : float + y-axis position + z : float + z-axis position + coefs: CoefClasses::Coefs + the coefficient set + + Returns + ------- + tuple of a dictionary of fields of array values, and an + array of evaluation times + + See also + -------- + getFieldsCoefs : get fields in expansion-origin frame )", - py::arg("x"), py::arg("y"), py::arg("z"), py::arg("coefs"), py::arg("origin") = true) + py::arg("x"), py::arg("y"), py::arg("z"), py::arg("coefs")) .def("setFieldType", &BasisClasses::BiorthBasis::setFieldType, R"( Set the coordinate system for force evaluations. The natural From cb7f33368188e5509135cec5f8fefe304b395784 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 14:44:06 +0000 Subject: [PATCH 24/24] Fix comment typo in BasisFactory dictionary notes Agent-Logs-Url: https://github.com/EXP-code/EXP/sessions/fe07195b-408a-42d0-b748-e96ed78bf175 Co-authored-by: The9Cat <25960766+The9Cat@users.noreply.github.com> --- expui/BasisFactory.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/expui/BasisFactory.cc b/expui/BasisFactory.cc index 77a0cd875..0830656b6 100644 --- a/expui/BasisFactory.cc +++ b/expui/BasisFactory.cc @@ -243,7 +243,7 @@ namespace BasisClasses Basis::getFieldsCoefs (double x, double y, double z, std::shared_ptr coefs) { - // Python dictonary for return + // Python dictionary for return std::map ret; // Times for the coefficients @@ -277,7 +277,7 @@ namespace BasisClasses Basis::getFieldsCoefsOrigin (double x, double y, double z, std::shared_ptr coefs) { - // Python dictonary for return + // Python dictionary for return std::map ret; // Times for the coefficients