Skip to content

Commit d4f5ed0

Browse files
johnwez1pre-commit-ci[bot]jobovy
authored
Add IAS15 high-precision integrator (#643)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Jo Bovy <bovy@astro.utoronto.ca>
1 parent bb31762 commit d4f5ed0

11 files changed

+745
-21
lines changed

HISTORY.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
v1.10.2 (expected around 2025-03-01)
22
====================
33

4+
- Implemented the IAS15 integrator of Rein & Spiegel 2015.
5+
46
- Combine the drift calculations in the Python leapfrog integrator (#365).
57

68
- Move the checks for non-axisymmetric and dissipative potentials from internal to

doc/source/orbit.rst

+7-2
Original file line numberDiff line numberDiff line change
@@ -1014,9 +1014,11 @@ the ``orbit.integrate`` method. Currently available integrators are
10141014
* rk6_c
10151015
* dopr54_c
10161016
* dop853_c
1017+
* ias15_c
10171018

1018-
which are Runge-Kutta and Dormand-Prince methods. There are also a
1019-
number of symplectic integrators available
1019+
which are Runge-Kutta, Dormand-Prince methods and the IAS15
1020+
integrator in `Rein & Spiegel (2014) <https://doi.org/10.1093/mnras/stu2164>`_.
1021+
There are also a number of symplectic integrators available
10201022

10211023
* leapfrog_c
10221024
* symplec4_c
@@ -1045,6 +1047,9 @@ which are speedy and reliable. For example, compare
10451047
>>> timeit(o.integrate(ts,mp,method='dop853_c'))
10461048
# 4.65 ms ± 86.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
10471049

1050+
The ``ias15_c`` method uses adaptive timestepping under the hood, and
1051+
can be used in cases where very high precision is required during orbit integration.
1052+
10481053
If the C extensions are unavailable for some reason, I recommend using
10491054
the ``odeint`` pure-Python integrator, as it is the fastest. Using the
10501055
same example as above

galpy/orbit/Orbits.py

+5
Original file line numberDiff line numberDiff line change
@@ -1287,13 +1287,15 @@ def check_integrator(method, no_symplec=False):
12871287
"rk6_c",
12881288
"dopr54_c",
12891289
"dop853_c",
1290+
"ias15_c",
12901291
]
12911292
if no_symplec:
12921293
symplec_methods = [
12931294
"leapfrog",
12941295
"leapfrog_c",
12951296
"symplec4_c",
12961297
"symplec6_c",
1298+
"ias15_c", # practically speaking, ias15 has the same limitations as symplectic integrators in galpy
12971299
]
12981300
[valid_methods.remove(symplec_method) for symplec_method in symplec_methods]
12991301
if method.lower() not in valid_methods:
@@ -1385,6 +1387,7 @@ def integrate(
13851387
- 'dopr54_c' for a 5-4 Dormand-Prince integrator in C
13861388
- 'dop853' for a 8-5-3 Dormand-Prince integrator in Python
13871389
- 'dop853_c' for a 8-5-3 Dormand-Prince integrator in C
1390+
- 'ias15_c' for an adaptive 15th order integrator using Gauß-Radau quadrature (see IAS15 paper) in C
13881391
13891392
- 2018-10-13 - Written as parallel_map applied to regular Orbit integration - Mathew Bub (UofT)
13901393
- 2018-12-26 - Written to use OpenMP C implementation - Bovy (UofT)
@@ -5153,6 +5156,7 @@ def bruteSOS(
51535156
- 'dopr54_c' for a 5-4 Dormand-Prince integrator in C
51545157
- 'dop853' for a 8-5-3 Dormand-Prince integrator in Python
51555158
- 'dop853_c' for a 8-5-3 Dormand-Prince integrator in C
5159+
- 'ias15_c' for an adaptive 15th order integrator using Gauß-Radau quadrature (see IAS15 paper) in C
51565160
51575161
- 2023-05-31 - Written - Bovy (UofT)
51585162
@@ -5895,6 +5899,7 @@ def plotBruteSOS(
58955899
- 'dopr54_c' for a 5-4 Dormand-Prince integrator in C
58965900
- 'dop853' for a 8-5-3 Dormand-Prince integrator in Python
58975901
- 'dop853_c' for a 8-5-3 Dormand-Prince integrator in C
5902+
- 'ias15_c' for an adaptive 15th order integrator using Gauß-Radau quadrature (see IAS15 paper) in C
58985903
58995904
- 2023-05-31 - Written - Bovy (UofT)
59005905

galpy/orbit/integratePlanarOrbit.py

+2
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,8 @@ def _parse_integrator(int_method):
618618
int_method_c = 5
619619
elif int_method.lower() == "dop853_c":
620620
int_method_c = 6
621+
elif int_method.lower() == "ias15_c":
622+
int_method_c = 7
621623
else:
622624
int_method_c = 0
623625
return int_method_c

galpy/orbit/orbit_c_ext/integrateFullOrbit.c

+11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <bovy_symplecticode.h>
1515
#include <leung_dop853.h>
1616
#include <bovy_rk.h>
17+
#include <wez_ias15.h>
1718
#include <integrateFullOrbit.h>
1819
//Potentials
1920
#include <galpy_potentials.h>
@@ -717,6 +718,11 @@ EXPORT void integrateFullOrbit(int nobj,
717718
odeint_deriv_func= &evalRectDeriv;
718719
dim= 6;
719720
break;
721+
case 7: //ias15
722+
odeint_func= &wez_ias15;
723+
odeint_deriv_func= &evalRectForce;
724+
dim= 3;
725+
break;
720726
}
721727
#pragma omp parallel for schedule(dynamic,ORBITS_CHUNKSIZE) private(ii,jj) num_threads(max_threads)
722728
for (ii=0; ii < nobj; ii++) {
@@ -883,6 +889,11 @@ void integrateOrbit_dxdv(double *yo,
883889
odeint_deriv_func= &evalRectDeriv_dxdv;
884890
dim= 12;
885891
break;
892+
case 7: //ias15
893+
odeint_func= &wez_ias15;
894+
odeint_deriv_func= &evalRectForce;
895+
dim= 6;
896+
break;
886897
}
887898
odeint_func(odeint_deriv_func,dim,yo,nt,-9999.99,t,npot,potentialArgs,
888899
rtol,atol,result,err);

galpy/orbit/orbit_c_ext/integrateLinearOrbit.c

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <math.h>
88
#include <bovy_symplecticode.h>
99
#include <bovy_rk.h>
10+
#include <wez_ias15.h>
1011
#include <leung_dop853.h>
1112
#include <integrateFullOrbit.h>
1213
//Potentials
@@ -192,6 +193,11 @@ EXPORT void integrateLinearOrbit(int nobj,
192193
odeint_deriv_func= &evalLinearDeriv;
193194
dim= 2;
194195
break;
196+
case 7: //ias15
197+
odeint_func= &wez_ias15;
198+
odeint_deriv_func= &evalLinearForce;
199+
dim= 1;
200+
break;
195201
}
196202
#pragma omp parallel for schedule(dynamic,ORBITS_CHUNKSIZE) private(ii) num_threads(max_threads)
197203
for (ii=0; ii < nobj; ii++) {

galpy/orbit/orbit_c_ext/integratePlanarOrbit.c

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <bovy_coords.h>
99
#include <bovy_symplecticode.h>
1010
#include <bovy_rk.h>
11+
#include <wez_ias15.h>
1112
#include <leung_dop853.h>
1213
#include <integrateFullOrbit.h>
1314
//Potentials
@@ -674,6 +675,11 @@ EXPORT void integratePlanarOrbit(int nobj,
674675
odeint_deriv_func= &evalPlanarRectDeriv;
675676
dim= 4;
676677
break;
678+
case 7: //ias15
679+
odeint_func= &wez_ias15;
680+
odeint_deriv_func= &evalPlanarRectForce;
681+
dim= 2;
682+
break;
677683
}
678684
#pragma omp parallel for schedule(dynamic,ORBITS_CHUNKSIZE) private(ii,jj) num_threads(max_threads)
679685
for (ii=0; ii < nobj; ii++) {

0 commit comments

Comments
 (0)