pybhpt 0.9.4__tar.gz → 0.9.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pybhpt might be problematic. Click here for more details.
- pybhpt-0.9.8/.readthedocs.yml +13 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/PKG-INFO +14 -4
- {pybhpt-0.9.4 → pybhpt-0.9.8}/README.md +13 -3
- {pybhpt-0.9.4 → pybhpt-0.9.8}/build_gsl.sh +7 -4
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/geo.hpp +6 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/swsh.hpp +0 -1
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/geo.cpp +22 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/metriccoeffs.cpp +2 -2
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/swsh.cpp +4 -1
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cython/geo_wrap.pyx +153 -16
- pybhpt-0.9.8/cython/swsh_wrap.pyx +70 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cython/teukolsky_wrap.pyx +1 -0
- pybhpt-0.9.8/docs/Makefile +12 -0
- pybhpt-0.9.8/docs/about.md +26 -0
- pybhpt-0.9.8/docs/background/geo.md +76 -0
- pybhpt-0.9.8/docs/background/radial.md +38 -0
- pybhpt-0.9.8/docs/background/swsh.md +42 -0
- pybhpt-0.9.8/docs/background/teuk.md +42 -0
- pybhpt-0.9.8/docs/conf.py +51 -0
- pybhpt-0.9.8/docs/index.md +67 -0
- pybhpt-0.9.8/docs/installation.md +88 -0
- pybhpt-0.9.8/docs/notebooks/fluxes.ipynb +323 -0
- pybhpt-0.9.8/docs/notebooks/geodesics.ipynb +416 -0
- pybhpt-0.9.8/docs/notebooks/radial.ipynb +185 -0
- pybhpt-0.9.8/docs/notebooks/swsh.ipynb +311 -0
- pybhpt-0.9.8/docs/notebooks/teuk.ipynb +380 -0
- pybhpt-0.9.8/docs/notebooks/waveform.ipynb +465 -0
- pybhpt-0.9.8/docs/pybhpt.flux.md +24 -0
- pybhpt-0.9.8/docs/pybhpt.geo.md +18 -0
- pybhpt-0.9.8/docs/pybhpt.hertz.md +11 -0
- pybhpt-0.9.8/docs/pybhpt.metric.md +11 -0
- pybhpt-0.9.8/docs/pybhpt.radial.md +25 -0
- pybhpt-0.9.8/docs/pybhpt.redshift.md +11 -0
- pybhpt-0.9.8/docs/pybhpt.swsh.md +20 -0
- pybhpt-0.9.8/docs/pybhpt.teuk.md +19 -0
- pybhpt-0.9.8/docs/requirements.txt +7 -0
- pybhpt-0.9.8/pybhpt/geo.py +767 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/pybhpt/radial.py +70 -7
- pybhpt-0.9.8/pybhpt/swsh.py +484 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/pybhpt/teuk.py +197 -6
- {pybhpt-0.9.4 → pybhpt-0.9.8}/pyproject.toml +1 -1
- pybhpt-0.9.4/pybhpt/geo.py +0 -407
- pybhpt-0.9.4/pybhpt/swsh.py +0 -347
- {pybhpt-0.9.4 → pybhpt-0.9.8}/.gitmodules +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/CMakeLists.txt +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/LICENSE +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/bessel.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/cf.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/fluxes.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/gsn_asymp.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/hertz.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/hypergeo_f.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/hypergeo_u.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/kerr.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/metric.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/metriccoeffs.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/monodromy.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/mst.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/nusolver.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/radialsolver.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/redshift.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/regularization.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/resflux.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/sourceintegration.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/specialfunc.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/teukolsky.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/include/utils.hpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/bessel.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/cf.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/fluxes.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/gsn_asymp.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/hertz.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/hypergeo_f.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/hypergeo_u.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/kerr.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/metric.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/monodromy.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/mst.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/nusolver.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/radialsolver.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/redshift.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/regularization.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/resflux.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/sourceintegration.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/specialfunc.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/teukolsky.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cpp/src/utils.cpp +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cython/flux_wrap.pyx +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cython/radialsolver_wrap.pyx +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/cython/redshift_wrap.pyx +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/environment-extended.yml +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/environment.yml +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/notebooks/flux-example.ipynb +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/pybhpt/__init__.py +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/pybhpt/flux.py +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/pybhpt/hertz.py +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/pybhpt/metric.py +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/pybhpt/redshift.py +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/tests/test_geo.py +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/tests/test_radial.py +0 -0
- {pybhpt-0.9.4 → pybhpt-0.9.8}/tests/test_teuk.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: pybhpt
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.8
|
|
4
4
|
Summary: Black Hole Perturbation Theory and Self-Force Algorithms in Python
|
|
5
5
|
Author-Email: Zach Nasipak <znasipak@gmail.com>
|
|
6
6
|
License: GPL
|
|
@@ -30,11 +30,11 @@ Description-Content-Type: text/markdown
|
|
|
30
30
|
|
|
31
31
|
# pybhpt
|
|
32
32
|
|
|
33
|
-
A python package for solving problems in black hole perturbation theory
|
|
33
|
+
A python package for solving problems in black hole perturbation theory.
|
|
34
34
|
|
|
35
35
|
`pybhpt` is a collection of numerical tools for analyzing perturbations of Kerr spacetime, particularly the self-forces and metric-perturbations experienced by small bodies moving in a Kerr background. Subpackages include:
|
|
36
36
|
|
|
37
|
-
- `pybhpt.geodesic`: a module that generates bound timelike geodesics in Kerr spacetime
|
|
37
|
+
- `pybhpt.geodesic`: a module that generates bound periodic timelike geodesics in Kerr spacetime
|
|
38
38
|
- `pybhpt.radial`: a module that calculates homogeneous solutions of the radial Teukolsky equation
|
|
39
39
|
- `pybhpt.swsh`: a module that constructs the spin-weighted spheroidal harmonics
|
|
40
40
|
- `pybhpt.teuk`: a module that evaluates the inhomogeneous solutions (Teukolsky amplitudes) of the radial Teukolsky equation due to a point-particle on a bound timelike Kerr geodesic
|
|
@@ -43,9 +43,11 @@ A python package for solving problems in black hole perturbation theory
|
|
|
43
43
|
- `pybhpt.metric`: a module that produces the coefficients needed to reconstruct the metric from the Hertz potentials
|
|
44
44
|
- `pybhpt.redshift`: a module that computes the generalized Detweiler redshift invariant in a variety of gauges
|
|
45
45
|
|
|
46
|
+
See the [Documentation](https://pybhpt.readthedocs.io/en/latest/) pages for more information about the package, including User Guides and API. References and author information can be found at the bottom of the README.
|
|
47
|
+
|
|
46
48
|
## Quick Installation
|
|
47
49
|
|
|
48
|
-
Tagged releases of `pybhpt` are available as wheel packages for macOS and 64-bit Linux on [PyPI](https://pypi.org/project/
|
|
50
|
+
Tagged releases of `pybhpt` are available as wheel packages for macOS and 64-bit Linux on [PyPI](https://pypi.org/project/pybhpt). Install using `pip`:
|
|
49
51
|
```
|
|
50
52
|
python3 -m pip install pybhpt
|
|
51
53
|
```
|
|
@@ -130,6 +132,14 @@ To include the necessary compiler on Linux:
|
|
|
130
132
|
conda install gcc_linux-64 gxx_linux-64
|
|
131
133
|
```
|
|
132
134
|
|
|
135
|
+
## References
|
|
136
|
+
|
|
137
|
+
Theoretical background for the code and explanations of the numerical methods used within are summarized in the references below:
|
|
138
|
+
|
|
139
|
+
- Z. Nasipak, *Metric reconstruction and the Hamiltonian for eccentric, precessing binaries in the small-mass-ratio limit* (2025) [arXiv:2507.07746](https://arxiv.org/abs/2507.07746)
|
|
140
|
+
- Z. Nasipak, *An adiabatic gravitational waveform model for compact objects undergoing quasi-circular inspirals into rotating massive black holes*, Phys. Rev. D 109, 044020 (2024) [arXiv:2310.19706](https://arxiv.org/abs/2310.19706)
|
|
141
|
+
- Z. Nasipak, *Adiabatic evolution due to the conservative scalar self-force during orbital resonances*, Phys. Rev. D 106, 064042 (2022) [arXiv:2207.02224](https://arxiv.org/abs/2207.02224)
|
|
142
|
+
|
|
133
143
|
## Authors
|
|
134
144
|
|
|
135
145
|
Zachary Nasipak
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# pybhpt
|
|
2
2
|
|
|
3
|
-
A python package for solving problems in black hole perturbation theory
|
|
3
|
+
A python package for solving problems in black hole perturbation theory.
|
|
4
4
|
|
|
5
5
|
`pybhpt` is a collection of numerical tools for analyzing perturbations of Kerr spacetime, particularly the self-forces and metric-perturbations experienced by small bodies moving in a Kerr background. Subpackages include:
|
|
6
6
|
|
|
7
|
-
- `pybhpt.geodesic`: a module that generates bound timelike geodesics in Kerr spacetime
|
|
7
|
+
- `pybhpt.geodesic`: a module that generates bound periodic timelike geodesics in Kerr spacetime
|
|
8
8
|
- `pybhpt.radial`: a module that calculates homogeneous solutions of the radial Teukolsky equation
|
|
9
9
|
- `pybhpt.swsh`: a module that constructs the spin-weighted spheroidal harmonics
|
|
10
10
|
- `pybhpt.teuk`: a module that evaluates the inhomogeneous solutions (Teukolsky amplitudes) of the radial Teukolsky equation due to a point-particle on a bound timelike Kerr geodesic
|
|
@@ -13,9 +13,11 @@ A python package for solving problems in black hole perturbation theory
|
|
|
13
13
|
- `pybhpt.metric`: a module that produces the coefficients needed to reconstruct the metric from the Hertz potentials
|
|
14
14
|
- `pybhpt.redshift`: a module that computes the generalized Detweiler redshift invariant in a variety of gauges
|
|
15
15
|
|
|
16
|
+
See the [Documentation](https://pybhpt.readthedocs.io/en/latest/) pages for more information about the package, including User Guides and API. References and author information can be found at the bottom of the README.
|
|
17
|
+
|
|
16
18
|
## Quick Installation
|
|
17
19
|
|
|
18
|
-
Tagged releases of `pybhpt` are available as wheel packages for macOS and 64-bit Linux on [PyPI](https://pypi.org/project/
|
|
20
|
+
Tagged releases of `pybhpt` are available as wheel packages for macOS and 64-bit Linux on [PyPI](https://pypi.org/project/pybhpt). Install using `pip`:
|
|
19
21
|
```
|
|
20
22
|
python3 -m pip install pybhpt
|
|
21
23
|
```
|
|
@@ -100,6 +102,14 @@ To include the necessary compiler on Linux:
|
|
|
100
102
|
conda install gcc_linux-64 gxx_linux-64
|
|
101
103
|
```
|
|
102
104
|
|
|
105
|
+
## References
|
|
106
|
+
|
|
107
|
+
Theoretical background for the code and explanations of the numerical methods used within are summarized in the references below:
|
|
108
|
+
|
|
109
|
+
- Z. Nasipak, *Metric reconstruction and the Hamiltonian for eccentric, precessing binaries in the small-mass-ratio limit* (2025) [arXiv:2507.07746](https://arxiv.org/abs/2507.07746)
|
|
110
|
+
- Z. Nasipak, *An adiabatic gravitational waveform model for compact objects undergoing quasi-circular inspirals into rotating massive black holes*, Phys. Rev. D 109, 044020 (2024) [arXiv:2310.19706](https://arxiv.org/abs/2310.19706)
|
|
111
|
+
- Z. Nasipak, *Adiabatic evolution due to the conservative scalar self-force during orbital resonances*, Phys. Rev. D 106, 064042 (2022) [arXiv:2207.02224](https://arxiv.org/abs/2207.02224)
|
|
112
|
+
|
|
103
113
|
## Authors
|
|
104
114
|
|
|
105
115
|
Zachary Nasipak
|
|
@@ -12,12 +12,15 @@ else
|
|
|
12
12
|
CORES=$(sysctl -n hw.ncpu)
|
|
13
13
|
fi
|
|
14
14
|
|
|
15
|
-
# Download source
|
|
15
|
+
# Download source (use mirror redirector + retries)
|
|
16
16
|
mkdir -p /tmp/gsl-src
|
|
17
17
|
cd /tmp/gsl-src
|
|
18
|
-
curl -
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
curl --fail --location --retry 5 --retry-delay 5 \
|
|
19
|
+
"https://ftpmirror.gnu.org/gsl/gsl-${GSL_VERSION}.tar.gz" \
|
|
20
|
+
-o "gsl-${GSL_VERSION}.tar.gz"
|
|
21
|
+
|
|
22
|
+
tar -xzf "gsl-${GSL_VERSION}.tar.gz"
|
|
23
|
+
cd "gsl-${GSL_VERSION}"
|
|
21
24
|
|
|
22
25
|
# Build & install
|
|
23
26
|
echo "Configuring GSL ${GSL_VERSION}..."
|
|
@@ -97,11 +97,17 @@ public:
|
|
|
97
97
|
double getPolarPosition(int pos);
|
|
98
98
|
double getAzimuthalAccumulation(int j, int pos);
|
|
99
99
|
|
|
100
|
+
double getPsiRadialOfMinoTime(double lambda);
|
|
101
|
+
double getPsiPolarOfMinoTime(double lambda);
|
|
102
|
+
|
|
100
103
|
double getTimePositionOfMinoTime(double lambda);
|
|
101
104
|
double getRadialPositionOfMinoTime(double lambda);
|
|
102
105
|
double getPolarPositionOfMinoTime(double lambda);
|
|
103
106
|
double getAzimuthalPositionOfMinoTime(double lambda);
|
|
104
107
|
|
|
108
|
+
Vector getPsiRadialOfMinoTime(Vector lambda);
|
|
109
|
+
Vector getPsiPolarOfMinoTime(Vector lambda);
|
|
110
|
+
|
|
105
111
|
Vector getTimePositionOfMinoTime(Vector lambda);
|
|
106
112
|
Vector getRadialPositionOfMinoTime(Vector lambda);
|
|
107
113
|
Vector getPolarPositionOfMinoTime(Vector lambda);
|
|
@@ -86,7 +86,6 @@ int spectral_matrix(const int &s, const int &lmin, const int &m, const double &g
|
|
|
86
86
|
int spectral_matrix_sparse_init(const int &s, const int &lmin, const int &m, const double &g, gsl_spmatrix* mat);
|
|
87
87
|
int spectral_matrix_sparse(const int &s, const int &lmin, const int &m, const double &g, gsl_spmatrix* mat, const size_t &nmax);
|
|
88
88
|
|
|
89
|
-
|
|
90
89
|
// Solve eigensystem of spectral matrix
|
|
91
90
|
int spectral_solver(const int &s, const int &l, const int &m, const double &g, double& la, Vector& bvec);
|
|
92
91
|
|
|
@@ -329,6 +329,12 @@ double GeodesicSource::getAzimuthalAccumulation(int j, int pos){
|
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
double GeodesicSource::getPsiRadialOfMinoTime(double lambda){
|
|
333
|
+
return kepler_phase_of_angle(lambda*_geoConstants.upsilonR, _geoCoefficients.r);
|
|
334
|
+
}
|
|
335
|
+
double GeodesicSource::getPsiPolarOfMinoTime(double lambda){
|
|
336
|
+
return kepler_phase_of_angle(lambda*_geoConstants.upsilonTheta, _geoCoefficients.theta);
|
|
337
|
+
}
|
|
332
338
|
double GeodesicSource::getTimePositionOfMinoTime(double lambda){
|
|
333
339
|
return lambda*_geoConstants.upsilonT + phip_of_angle(lambda*_geoConstants.upsilonR, _geoCoefficients.tR) + phip_of_angle(lambda*_geoConstants.upsilonTheta, _geoCoefficients.tTheta);
|
|
334
340
|
}
|
|
@@ -350,6 +356,22 @@ Vector GeodesicSource::getPositionOfMinoTime(double lambda){
|
|
|
350
356
|
return xp;
|
|
351
357
|
}
|
|
352
358
|
|
|
359
|
+
Vector GeodesicSource::getPsiRadialOfMinoTime(Vector lambda){
|
|
360
|
+
Vector xp(lambda.size());
|
|
361
|
+
for(size_t i = 0; i < xp.size(); i++){
|
|
362
|
+
xp[i] = getPsiRadialOfMinoTime(lambda[i]);
|
|
363
|
+
}
|
|
364
|
+
return xp;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
Vector GeodesicSource::getPsiPolarOfMinoTime(Vector lambda){
|
|
368
|
+
Vector xp(lambda.size());
|
|
369
|
+
for(size_t i = 0; i < xp.size(); i++){
|
|
370
|
+
xp[i] = getPsiPolarOfMinoTime(lambda[i]);
|
|
371
|
+
}
|
|
372
|
+
return xp;
|
|
373
|
+
}
|
|
374
|
+
|
|
353
375
|
Vector GeodesicSource::getTimePositionOfMinoTime(Vector lambda){
|
|
354
376
|
Vector xp(lambda.size());
|
|
355
377
|
for(size_t i = 0; i < xp.size(); i++){
|
|
@@ -3217,7 +3217,7 @@ ComplexMatrix tetrad_velocity_radial(Complex (*subfunc)(double, double, double,
|
|
|
3217
3217
|
for(size_t jr = 1; jr < r.size() - 1; jr++){
|
|
3218
3218
|
rp = r[jr];
|
|
3219
3219
|
zp = z[0];
|
|
3220
|
-
double deltaUr = sqrt(kerr_geo_Vr(a, En, Lz, Qc, rp));
|
|
3220
|
+
double deltaUr = std::sqrt(std::abs(kerr_geo_Vr(a, En, Lz, Qc, rp)));
|
|
3221
3221
|
// take into account when the radial velocity is positive
|
|
3222
3222
|
ua[jr][0] = subfunc(a, En, Lz, Qc, rp, zp, deltaUr);
|
|
3223
3223
|
ua[u1rSize - jr][0] = subfunc(a, En, Lz, Qc, rp, zp, -deltaUr);
|
|
@@ -3234,7 +3234,7 @@ ComplexMatrix tetrad_velocity_radial(Complex (*subfunc)(double, double, double,
|
|
|
3234
3234
|
for(size_t jz = 1; jz < z.size() - 1; jz++){
|
|
3235
3235
|
rp = r[jr];
|
|
3236
3236
|
zp = z[jz];
|
|
3237
|
-
double deltaUr = sqrt(kerr_geo_Vr(a, En, Lz, Qc, rp));
|
|
3237
|
+
double deltaUr = std::sqrt(std::abs(kerr_geo_Vr(a, En, Lz, Qc, rp)));
|
|
3238
3238
|
// take into account when the radial velocity is positive
|
|
3239
3239
|
ua[jr][jz] = subfunc(a, En, Lz, Qc, rp, zp, deltaUr);
|
|
3240
3240
|
ua[jr][u1zSize - jz] = subfunc(a, En, Lz, Qc, rp, zp, deltaUr);
|
|
@@ -718,7 +718,10 @@ Complex Yslm(const int &s, const int &l, const int &m, const double &th, const d
|
|
|
718
718
|
|
|
719
719
|
double Yslm(const int &s, const int &l, const int &m, const double &th){
|
|
720
720
|
if( s == 0 ) return Ylm(l, m, th);
|
|
721
|
-
|
|
721
|
+
if( th == 0. ){
|
|
722
|
+
if (m != -s) return 0.;
|
|
723
|
+
else return pow(-1, s)*Yslm(0, l, 0, 0.);
|
|
724
|
+
}
|
|
722
725
|
int lmin = std::max(std::abs(m), l - std::abs(s));
|
|
723
726
|
int lmax = l + std::abs(s);
|
|
724
727
|
double yslm = 0;
|
|
@@ -54,11 +54,17 @@ cdef extern from "geo.hpp":
|
|
|
54
54
|
double getPolarPosition(int pos)
|
|
55
55
|
double getAzimuthalAccumulation(int j, int pos)
|
|
56
56
|
|
|
57
|
+
double getPsiRadialOfMinoTime(double la)
|
|
58
|
+
double getPsiPolarOfMinoTime(double la)
|
|
59
|
+
|
|
57
60
|
double getTimePositionOfMinoTime(double la)
|
|
58
61
|
double getRadialPositionOfMinoTime(double la)
|
|
59
62
|
double getPolarPositionOfMinoTime(double la)
|
|
60
63
|
double getAzimuthalPositionOfMinoTime(double la)
|
|
61
64
|
|
|
65
|
+
vector[double] getPsiRadialOfMinoTime(vector[double] la)
|
|
66
|
+
vector[double] getPsiPolarOfMinoTime(vector[double] la)
|
|
67
|
+
|
|
62
68
|
vector[double] getTimePositionOfMinoTime(vector[double] la)
|
|
63
69
|
vector[double] getRadialPositionOfMinoTime(vector[double] la)
|
|
64
70
|
vector[double] getPolarPositionOfMinoTime(vector[double] la)
|
|
@@ -187,6 +193,24 @@ cdef class KerrGeodesic:
|
|
|
187
193
|
def mode_carter_frequency(self, np.ndarray[ndim=1, dtype=np.int64_t] kvec):
|
|
188
194
|
return np.dot(kvec,(self.carterfrequencies))
|
|
189
195
|
|
|
196
|
+
cdef void getPsiRadialOfMinoTimeArray(self, np.float64_t *psi, np.float64_t *la, int n):
|
|
197
|
+
for i in range(n):
|
|
198
|
+
psi[i] = self.geocpp.getPsiRadialOfMinoTime(la[i])
|
|
199
|
+
cdef void getPsiPolarOfMinoTimeArray(self, np.float64_t *psi, np.float64_t *la, int n):
|
|
200
|
+
for i in range(n):
|
|
201
|
+
psi[i] = self.geocpp.getPsiPolarOfMinoTime(la[i])
|
|
202
|
+
|
|
203
|
+
cdef void getPsiRadialOfTimeArray(self, np.float64_t *psi, np.float64_t *t, int n):
|
|
204
|
+
cdef double tmp
|
|
205
|
+
for i in range(n):
|
|
206
|
+
tmp = self.geocpp.getMinoTimeOfTime(t[i])
|
|
207
|
+
psi[i] = self.geocpp.getPsiRadialOfMinoTime(tmp)
|
|
208
|
+
cdef void getPsiPolarOfTimeArray(self, np.float64_t *psi, np.float64_t *t, int n):
|
|
209
|
+
cdef double tmp
|
|
210
|
+
for i in range(n):
|
|
211
|
+
tmp = self.geocpp.getMinoTimeOfTime(t[i])
|
|
212
|
+
psi[i] = self.geocpp.getPsiPolarOfMinoTime(tmp)
|
|
213
|
+
|
|
190
214
|
cdef void getTimePositionOfMinoTimeArray(self, np.float64_t *t, np.float64_t *la, int n):
|
|
191
215
|
for i in range(n):
|
|
192
216
|
t[i] = self.geocpp.getTimePositionOfMinoTime(la[i])
|
|
@@ -199,8 +223,86 @@ cdef class KerrGeodesic:
|
|
|
199
223
|
cdef void getAzimuthalPositionOfMinoTimeArray(self, np.float64_t *t, np.float64_t *la, int n):
|
|
200
224
|
for i in range(n):
|
|
201
225
|
t[i] = self.geocpp.getAzimuthalPositionOfMinoTime(la[i])
|
|
226
|
+
|
|
227
|
+
cdef void getRadialPositionOfTimeArray(self, np.float64_t *r, np.float64_t *t, int n):
|
|
228
|
+
cdef double tmp
|
|
229
|
+
for i in range(n):
|
|
230
|
+
tmp = self.geocpp.getMinoTimeOfTime(t[i])
|
|
231
|
+
r[i] = self.geocpp.getRadialPositionOfMinoTime(tmp)
|
|
232
|
+
cdef void getPolarPositionOfTimeArray(self, np.float64_t *th, np.float64_t *t, int n):
|
|
233
|
+
cdef double tmp
|
|
234
|
+
for i in range(n):
|
|
235
|
+
tmp = self.geocpp.getMinoTimeOfTime(t[i])
|
|
236
|
+
th[i] = self.geocpp.getPolarPositionOfMinoTime(tmp)
|
|
237
|
+
cdef void getAzimuthalPositionOfTimeArray(self, np.float64_t *ph, np.float64_t *t, int n):
|
|
238
|
+
cdef double tmp
|
|
239
|
+
for i in range(n):
|
|
240
|
+
tmp = self.geocpp.getMinoTimeOfTime(t[i])
|
|
241
|
+
ph[i] = self.geocpp.getAzimuthalPositionOfMinoTime(tmp)
|
|
242
|
+
|
|
243
|
+
def psi_radial(self, double la):
|
|
244
|
+
return self.geocpp.getPsiRadialOfMinoTime(la)
|
|
245
|
+
|
|
246
|
+
def psi_polar(self, double la):
|
|
247
|
+
return self.geocpp.getPsiPolarOfMinoTime(la)
|
|
248
|
+
|
|
249
|
+
def psi_radial_time(self, double t):
|
|
250
|
+
cdef double tmp = self.geocpp.getMinoTimeOfTime(t)
|
|
251
|
+
return self.geocpp.getPsiRadialOfMinoTime(tmp)
|
|
252
|
+
|
|
253
|
+
def psi_polar_time(self, double t):
|
|
254
|
+
cdef double tmp = self.geocpp.getMinoTimeOfTime(t)
|
|
255
|
+
return self.geocpp.getPsiPolarOfMinoTime(tmp)
|
|
256
|
+
|
|
257
|
+
def psi_radial_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] la):
|
|
258
|
+
cdef int n = la.shape[0]
|
|
259
|
+
cdef np.ndarray[ndim=1, dtype=np.float64_t] psi = np.empty(n, dtype = np.float64)
|
|
260
|
+
self.getPsiRadialOfMinoTimeArray(&psi[0], &la[0], n)
|
|
261
|
+
return psi
|
|
262
|
+
|
|
263
|
+
def psi_polar_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] la):
|
|
264
|
+
cdef int n = la.shape[0]
|
|
265
|
+
cdef np.ndarray[ndim=1, dtype=np.float64_t] psi = np.empty(n, dtype = np.float64)
|
|
266
|
+
self.getPsiPolarOfMinoTimeArray(&psi[0], &la[0], n)
|
|
267
|
+
return psi
|
|
268
|
+
|
|
269
|
+
def psi_radial_time_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] t):
|
|
270
|
+
cdef int n = t.shape[0]
|
|
271
|
+
cdef np.ndarray[ndim=1, dtype=np.float64_t] psi = np.empty(n, dtype = np.float64)
|
|
272
|
+
self.getPsiRadialOfTimeArray(&psi[0], &t[0], n)
|
|
273
|
+
return psi
|
|
274
|
+
|
|
275
|
+
def psi_polar_time_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] t):
|
|
276
|
+
cdef int n = t.shape[0]
|
|
277
|
+
cdef np.ndarray[ndim=1, dtype=np.float64_t] psi = np.empty(n, dtype = np.float64)
|
|
278
|
+
self.getPsiPolarOfTimeArray(&psi[0], &t[0], n)
|
|
279
|
+
return psi
|
|
280
|
+
|
|
281
|
+
def time_position(self, double la):
|
|
282
|
+
return self.geocpp.getTimePositionOfMinoTime(la)
|
|
283
|
+
|
|
284
|
+
def radial_position(self, double la):
|
|
285
|
+
return self.geocpp.getRadialPositionOfMinoTime(la)
|
|
202
286
|
|
|
203
|
-
def
|
|
287
|
+
def polar_position(self, double la):
|
|
288
|
+
return self.geocpp.getPolarPositionOfMinoTime(la)
|
|
289
|
+
|
|
290
|
+
def azimuthal_position(self, double la):
|
|
291
|
+
return self.geocpp.getAzimuthalPositionOfMinoTime(la)
|
|
292
|
+
|
|
293
|
+
def radial_position_time(self, double t):
|
|
294
|
+
cdef double tmp = self.geocpp.getMinoTimeOfTime(t)
|
|
295
|
+
return self.geocpp.getRadialPositionOfMinoTime(tmp)
|
|
296
|
+
|
|
297
|
+
def polar_position_time(self, double t):
|
|
298
|
+
cdef double tmp = self.geocpp.getMinoTimeOfTime(t)
|
|
299
|
+
return self.geocpp.getPolarPositionOfMinoTime(tmp)
|
|
300
|
+
|
|
301
|
+
def azimuthal_position_time(self, double t):
|
|
302
|
+
cdef double tmp = self.geocpp.getMinoTimeOfTime(t)
|
|
303
|
+
return self.geocpp.getAzimuthalPositionOfMinoTime(tmp)
|
|
304
|
+
|
|
305
|
+
def time_position_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] la):
|
|
204
306
|
cdef int n = la.shape[0]
|
|
205
307
|
cdef np.ndarray[ndim=1, dtype=np.float64_t] t = np.empty(n, dtype = np.float64)
|
|
206
308
|
self.getTimePositionOfMinoTimeArray(&t[0], &la[0], n)
|
|
@@ -209,23 +311,70 @@ cdef class KerrGeodesic:
|
|
|
209
311
|
# t[i] = self.geocpp.getTimePositionOfMinoTime(la[i])
|
|
210
312
|
return t
|
|
211
313
|
|
|
212
|
-
def
|
|
314
|
+
def radial_position_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] la):
|
|
213
315
|
cdef int n = la.shape[0]
|
|
214
316
|
cdef np.ndarray[ndim=1, dtype=np.float64_t] x = np.empty(n, dtype = np.float64)
|
|
215
317
|
self.getRadialPositionOfMinoTimeArray(&x[0], &la[0], n)
|
|
216
318
|
return x
|
|
217
319
|
|
|
218
|
-
def
|
|
320
|
+
def polar_position_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] la):
|
|
219
321
|
cdef int n = la.shape[0]
|
|
220
322
|
cdef np.ndarray[ndim=1, dtype=np.float64_t] x = np.empty(n, dtype = np.float64)
|
|
221
323
|
self.getPolarPositionOfMinoTimeArray(&x[0], &la[0], n)
|
|
222
324
|
return x
|
|
223
325
|
|
|
224
|
-
def
|
|
326
|
+
def azimuthal_position_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] la):
|
|
225
327
|
cdef int n = la.shape[0]
|
|
226
328
|
cdef np.ndarray[ndim=1, dtype=np.float64_t] x = np.empty(n, dtype = np.float64)
|
|
227
329
|
self.getAzimuthalPositionOfMinoTimeArray(&x[0], &la[0], n)
|
|
228
330
|
return x
|
|
331
|
+
|
|
332
|
+
def radial_position_time_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] t):
|
|
333
|
+
cdef int n = t.shape[0]
|
|
334
|
+
cdef np.ndarray[ndim=1, dtype=np.float64_t] x = np.empty(n, dtype = np.float64)
|
|
335
|
+
self.getRadialPositionOfTimeArray(&x[0], &t[0], n)
|
|
336
|
+
return x
|
|
337
|
+
|
|
338
|
+
def polar_position_time_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] t):
|
|
339
|
+
cdef int n = t.shape[0]
|
|
340
|
+
cdef np.ndarray[ndim=1, dtype=np.float64_t] x = np.empty(n, dtype = np.float64)
|
|
341
|
+
self.getPolarPositionOfTimeArray(&x[0], &t[0], n)
|
|
342
|
+
return x
|
|
343
|
+
|
|
344
|
+
def azimuthal_position_time_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] t):
|
|
345
|
+
cdef int n = t.shape[0]
|
|
346
|
+
cdef np.ndarray[ndim=1, dtype=np.float64_t] x = np.empty(n, dtype = np.float64)
|
|
347
|
+
self.getAzimuthalPositionOfTimeArray(&x[0], &t[0], n)
|
|
348
|
+
return x
|
|
349
|
+
|
|
350
|
+
def position(self, double la):
|
|
351
|
+
return np.array([self.geocpp.getTimePositionOfMinoTime(la), self.geocpp.getRadialPositionOfMinoTime(la), self.geocpp.getPolarPositionOfMinoTime(la), self.geocpp.getAzimuthalPositionOfMinoTime(la)])
|
|
352
|
+
|
|
353
|
+
def position_time(self, double t):
|
|
354
|
+
cdef double tmp = self.geocpp.getMinoTimeOfTime(t)
|
|
355
|
+
return np.array([self.geocpp.getRadialPositionOfMinoTime(tmp), self.geocpp.getPolarPositionOfMinoTime(tmp), self.geocpp.getAzimuthalPositionOfMinoTime(tmp)])
|
|
356
|
+
|
|
357
|
+
def position_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] la):
|
|
358
|
+
cdef np.ndarray[ndim=2, dtype=np.float64_t] xp = np.empty((la.shape[0], 4), dtype=np.float64)
|
|
359
|
+
for i in range(la.shape[0]):
|
|
360
|
+
xp[i] = self.position(la[i])
|
|
361
|
+
return xp.T
|
|
362
|
+
|
|
363
|
+
def position_time_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] t):
|
|
364
|
+
cdef np.ndarray[ndim=2, dtype=np.float64_t] xp = np.empty((t.shape[0], 3), dtype=np.float64)
|
|
365
|
+
for i in range(t.shape[0]):
|
|
366
|
+
xp[i] = self.position_time(t[i])
|
|
367
|
+
return xp.T
|
|
368
|
+
|
|
369
|
+
def mino_time(self, double t):
|
|
370
|
+
return self.geocpp.getMinoTimeOfTime(t)
|
|
371
|
+
|
|
372
|
+
def mino_time_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] t):
|
|
373
|
+
cdef int n = t.shape[0]
|
|
374
|
+
cdef np.ndarray[ndim=1, dtype=np.float64_t] la = np.empty(n, dtype = np.float64)
|
|
375
|
+
for i in range(n):
|
|
376
|
+
la[i] = self.mino_time(t[i])
|
|
377
|
+
return la
|
|
229
378
|
|
|
230
379
|
def get_time_accumulation(self, int j):
|
|
231
380
|
cdef vector[double] deltaX_cpp = self.geocpp.getTimeAccumulation(j)
|
|
@@ -259,18 +408,6 @@ cdef class KerrGeodesic:
|
|
|
259
408
|
deltaX[i] = deltaX_cpp[i]
|
|
260
409
|
return deltaX
|
|
261
410
|
|
|
262
|
-
def position(self, double la):
|
|
263
|
-
return np.array([self.geocpp.getTimePositionOfMinoTime(la), self.geocpp.getRadialPositionOfMinoTime(la), self.geocpp.getPolarPositionOfMinoTime(la), self.geocpp.getAzimuthalPositionOfMinoTime(la)])
|
|
264
|
-
|
|
265
|
-
def position_vec(self, np.ndarray[ndim=1, dtype=np.float64_t] la):
|
|
266
|
-
cdef np.ndarray[ndim=2, dtype=np.float64_t] xp = np.empty((la.shape[0], 4), dtype=np.float64)
|
|
267
|
-
for i in range(la.shape[0]):
|
|
268
|
-
xp[i] = self.position(la[i])
|
|
269
|
-
return xp.T
|
|
270
|
-
|
|
271
|
-
def mino_time(self, double t):
|
|
272
|
-
return self.geocpp.getMinoTimeOfTime(t)
|
|
273
|
-
|
|
274
411
|
def get_time_coefficients(self, int j):
|
|
275
412
|
cdef vector[double] deltaX_cpp = self.geocpp.getTimeCoefficients(j)
|
|
276
413
|
cdef int n = deltaX_cpp.size()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from libcpp.vector cimport vector
|
|
2
|
+
from libcpp.complex cimport complex as cpp_complex
|
|
3
|
+
import numpy as np
|
|
4
|
+
cimport numpy as np
|
|
5
|
+
|
|
6
|
+
cdef extern from "gsl/gsl_errno.h":
|
|
7
|
+
void gsl_set_error_handler_off()
|
|
8
|
+
|
|
9
|
+
# If you need to disable GSL error handling, do so in a targeted way within specific functions.
|
|
10
|
+
# gsl_set_error_handler_off() # Removed global call to avoid masking numerical errors.
|
|
11
|
+
|
|
12
|
+
cdef extern from "swsh.hpp":
|
|
13
|
+
cdef cppclass SpinWeightedHarmonic:
|
|
14
|
+
SpinWeightedHarmonic(int s, int L, int m, double gamma, vector[double]& theta)
|
|
15
|
+
|
|
16
|
+
int getSpinWeight()
|
|
17
|
+
int getSpheroidalModeNumber()
|
|
18
|
+
int getAzimuthalModeNumber()
|
|
19
|
+
double getSpheroidicity()
|
|
20
|
+
double getEigenvalue()
|
|
21
|
+
vector[double] getCouplingCoefficient()
|
|
22
|
+
double getCouplingCoefficient(int l)
|
|
23
|
+
int getMinCouplingModeNumber()
|
|
24
|
+
int getMaxCouplingModeNumber()
|
|
25
|
+
|
|
26
|
+
int generateSolutionsAndDerivatives()
|
|
27
|
+
int generateCouplingCoefficients()
|
|
28
|
+
int generateSolutions()
|
|
29
|
+
int generateDerivatives()
|
|
30
|
+
|
|
31
|
+
vector[double] getArguments()
|
|
32
|
+
vector[double] getSolution()
|
|
33
|
+
vector[double] getDerivative()
|
|
34
|
+
vector[double] getSecondDerivative()
|
|
35
|
+
|
|
36
|
+
double getArguments(int pos)
|
|
37
|
+
double getSolution(int pos)
|
|
38
|
+
double getDerivative(int pos)
|
|
39
|
+
double getSecondDerivative(int pos)
|
|
40
|
+
|
|
41
|
+
double Asljm(int &s, int &l, int &j, int &m)
|
|
42
|
+
double dAsljm(int &s, int &l, int &j, int &m)
|
|
43
|
+
|
|
44
|
+
double clebsch(int &j1, int &j2, int &j, int &m1, int &m2, int &m)
|
|
45
|
+
double w3j(int &j1, int &j2, int &j, int &m1, int &m2, int &m)
|
|
46
|
+
|
|
47
|
+
cpp_complex[double] Sslm(int &s, int &l, int &m, double &g, double &th, double &ph)
|
|
48
|
+
double Sslm(int &s, int &l, int &m, double &g, double &th)
|
|
49
|
+
|
|
50
|
+
double Sslm(int &s, int &l, int &m, double &g, vector[double]& bvec, double &th)
|
|
51
|
+
double Sslm_derivative(int &s, int &l, int &m, double &g, vector[double]& bvec, double &th)
|
|
52
|
+
double Sslm_secondDerivative(int &s, int &l, int &m, double &g, double& la, double &th, double &Slm, double &SlmP)
|
|
53
|
+
|
|
54
|
+
double swsh_eigenvalue(int &s, int &l, int &m, double &g)
|
|
55
|
+
|
|
56
|
+
cpp_complex[double] Yslm(int &s, int &l, int &m, double &th, double &ph)
|
|
57
|
+
double Yslm(int &s, int &l, int &m, double &th) except +
|
|
58
|
+
double Yslm_derivative(int &s, int &l, int &m, double &th)
|
|
59
|
+
|
|
60
|
+
def YslmCy(int s, int l, int m, double theta):
|
|
61
|
+
return Yslm(s, l, m, theta)
|
|
62
|
+
|
|
63
|
+
def YslmCy_derivative(int s, int l, int m, double theta):
|
|
64
|
+
return Yslm_derivative(s, l, m, theta)
|
|
65
|
+
|
|
66
|
+
def clebschCy(int j1, int j2, int j, int m1, int m2, int m):
|
|
67
|
+
return clebsch(j1, j2, j, m1, m2, m)
|
|
68
|
+
|
|
69
|
+
def w3jCy(int j1, int j2, int j, int m1, int m2, int m):
|
|
70
|
+
return w3j(j1, j2, j, m1, m2, m)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Clean target to remove build directory
|
|
2
|
+
clean:
|
|
3
|
+
rm -rf _build
|
|
4
|
+
# Minimal Sphinx Makefile
|
|
5
|
+
SPHINXOPTS =
|
|
6
|
+
SPHINXBUILD = sphinx-build
|
|
7
|
+
SOURCEDIR = .
|
|
8
|
+
BUILDDIR = _build
|
|
9
|
+
|
|
10
|
+
.PHONY: html
|
|
11
|
+
html:
|
|
12
|
+
$(SPHINXBUILD) -b html $(SOURCEDIR) $(BUILDDIR)/html $(SPHINXOPTS)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# About
|
|
2
|
+
|
|
3
|
+
`pybhpt` is a collection of numerical tools for analyzing perturbations of Kerr spacetime, particularly the self-forces and metric-perturbations experienced by small bodies moving in a Kerr background.
|
|
4
|
+
|
|
5
|
+
## Subpackages
|
|
6
|
+
- [`pybhpt.geo`](pybhpt.geo): generates bound periodic timelike geodesics in Kerr spacetime
|
|
7
|
+
- [`pybhpt.radial`](pybhpt.radial): calculates homogeneous solutions of the radial Teukolsky equation
|
|
8
|
+
- [`pybhpt.swsh`](pybhpt.swsh): constructs the spin-weighted spheroidal harmonics
|
|
9
|
+
- [`pybhpt.teuk`](pybhpt.teuk): evaluates inhomogeneous solutions (Teukolsky amplitudes) of the radial Teukolsky equation due to a point-particle on a bound timelike Kerr geodesic
|
|
10
|
+
- [`pybhpt.flux`](pybhpt.flux): produces gravitational wave fluxes sourced by a point-particle on a generic bound timelike Kerr geodesic
|
|
11
|
+
- [`pybhpt.hertz`](pybhpt.hertz): solves for the Hertz potentials for the CCK and AAB metric reconstruction procedures
|
|
12
|
+
- [`pybhpt.metric`](pybhpt.metric): produces coefficients needed to reconstruct the metric from the Hertz potentials
|
|
13
|
+
- [`pybhpt.redshift`](pybhpt.redshift): computes the generalized Detweiler redshift invariant in a variety of gauges
|
|
14
|
+
|
|
15
|
+
One can find out more information about each module by exploring the User Guides or clicking on the subpackages, which are linked to the API.
|
|
16
|
+
|
|
17
|
+
## References
|
|
18
|
+
|
|
19
|
+
Theoretical background for the code and explanations of the numerical methods used within are summarized in the references below:
|
|
20
|
+
|
|
21
|
+
- Z. Nasipak, *Metric reconstruction and the Hamiltonian for eccentric, precessing binaries in the small-mass-ratio limit* (2025) [arXiv:2507.07746](https://arxiv.org/abs/2507.07746)
|
|
22
|
+
- Z. Nasipak, *An adiabatic gravitational waveform model for compact objects undergoing quasi-circular inspirals into rotating massive black holes*, Phys. Rev. D 109, 044020 (2024) [arXiv:2310.19706](https://arxiv.org/abs/2310.19706)
|
|
23
|
+
- Z. Nasipak, *Adiabatic evolution due to the conservative scalar self-force during orbital resonances*, Phys. Rev. D 106, 064042 (2022) [arXiv:2207.02224](https://arxiv.org/abs/2207.02224)
|
|
24
|
+
|
|
25
|
+
## Authors
|
|
26
|
+
Zachary Nasipak
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Geodesics in Kerr
|
|
2
|
+
|
|
3
|
+
We work in a Kerr background with angular momentum and mass parameters $(J, M)$ and use Boyer-Lindquist coordinates $(t, r, \theta, \phi)$.
|
|
4
|
+
|
|
5
|
+
Bound periodic timelike geodesics in Kerr spacetime are defined in terms of the turning points of the motion:
|
|
6
|
+
|
|
7
|
+
- $r_\mathrm{min}$ : minimum Boyer-Lindquist radius
|
|
8
|
+
- $r_\mathrm{max}$ : maximum Boyer-Lindquist radius
|
|
9
|
+
- $\theta_\mathrm{min}$ : minimum Boyer-Lindquist polar angle
|
|
10
|
+
- $\pi-\theta_\mathrm{min}$ : maximum Boyer-Lindquist polar angle
|
|
11
|
+
|
|
12
|
+
From these we parametrize the geodesic in terms of the generalized Keplerian parameters:
|
|
13
|
+
|
|
14
|
+
- $a$ : the dimensionless Kerr spin parameter
|
|
15
|
+
- $p$ : the dimensionless semilatus rectum
|
|
16
|
+
- $e$ : the orbital eccentricty
|
|
17
|
+
- $x$ : cosine of the orbital inclination
|
|
18
|
+
|
|
19
|
+
where $a = J/M^2$, $pM = 2r_\mathrm{max}r_\mathrm{min}/(r_\mathrm{min}+r_\mathrm{max})$ and $e = (r_\mathrm{max}-r_\mathrm{min})/(r_\mathrm{min}+r_\mathrm{max})$. The motion can also be described in terms of the conserved orbital constants:
|
|
20
|
+
|
|
21
|
+
- $E$ : the specific orbital energy
|
|
22
|
+
- $L_z$ : the specific orbital angular momentum
|
|
23
|
+
- $Q$ : the Carter constant
|
|
24
|
+
|
|
25
|
+
which have units $\{1, M, M^2\}$, respectively, along with the mass of the small body $\mu$.
|
|
26
|
+
|
|
27
|
+
With these conserved quantities, we obtain four first-order ordinary differential equations (ODEs) for $x_p^\mu$, which decouple when parametrized in terms of the Mino(-Carter) time parameter $\lambda$,
|
|
28
|
+
$$\begin{align}
|
|
29
|
+
\frac{dt_p}{d\lambda} &= V_{tr}(r_p) + V_{t\theta}(\theta_p),
|
|
30
|
+
\\
|
|
31
|
+
\frac{dr_p}{d\lambda} &= \pm \sqrt{V_r(r_p)},
|
|
32
|
+
\\
|
|
33
|
+
\frac{d\theta_p}{d\lambda} &= \pm \sqrt{V_\theta(\theta_p)},
|
|
34
|
+
\\
|
|
35
|
+
\frac{d\phi_p}{d\lambda} &= V_{\phi r}(r_p) + V_{\phi \theta}(\theta_p),
|
|
36
|
+
\end{align}$$
|
|
37
|
+
where $d\lambda = \Sigma^{-1} d\tau$, and the potential functions are given by
|
|
38
|
+
$$\begin{align}
|
|
39
|
+
V_{r}(r) &= { P^2(r) - \Delta\left(r^2 + {K} \right),}
|
|
40
|
+
&
|
|
41
|
+
V_{\theta}(\theta) &= {{Q} - {L}_z^2 \cot^2\theta - a^2 (1 -{E}^2)\cos^2\theta,}
|
|
42
|
+
\\
|
|
43
|
+
V_{tr}(r) &= \frac{r^2+a^2}{\Delta}P(r),
|
|
44
|
+
&
|
|
45
|
+
V_{t\theta}(\theta) &= a{L}_z - a^2 {E} \sin^2\theta,
|
|
46
|
+
\\
|
|
47
|
+
V_{\phi r}(r) &= \frac{a}{\Delta}P(r),
|
|
48
|
+
&
|
|
49
|
+
V_{\phi \theta}(\theta) &= {L}_z \csc^2\theta - a {E},
|
|
50
|
+
\end{align}$$
|
|
51
|
+
|
|
52
|
+
with $P(r) = (r^2+a^2){E} - a {L}_z$.
|
|
53
|
+
|
|
54
|
+
The resulting bound solutions can be separated into terms that are periodic with respect to the Mino time radial and polar frequencies $\Upsilon_r$ and $\Upsilon_\theta$ and terms that grow secularly with the Mino time rates $\Upsilon_t$ and $\Upsilon_\phi$.
|
|
55
|
+
Therefore, the fundamental coordinate time frequencies are given by
|
|
56
|
+
$$\begin{align}
|
|
57
|
+
\Omega_r &= \frac{\Upsilon_r}{\Upsilon_t},
|
|
58
|
+
&
|
|
59
|
+
\Omega_\theta &= \frac{\Upsilon_\theta}{\Upsilon_t},
|
|
60
|
+
&
|
|
61
|
+
\Omega_\phi &= \frac{\Upsilon_\phi}{\Upsilon_t}.
|
|
62
|
+
\end{align}$$
|
|
63
|
+
|
|
64
|
+
We then represent the radial and polar motion by
|
|
65
|
+
$$\begin{align}
|
|
66
|
+
r_p(\lambda) &= \Delta r^{(r)}(\Upsilon_r\lambda) = \Delta r^{(r)}(\Upsilon_r\lambda + 2\pi),
|
|
67
|
+
\\
|
|
68
|
+
\theta_p(\lambda) &= \Delta \theta^{(\theta)}(\Upsilon_\theta\lambda) = \Delta \theta^{(\theta)}(\Upsilon_\theta\lambda + 2\pi),
|
|
69
|
+
\end{align}$$
|
|
70
|
+
while time and azimuthal angle grow as
|
|
71
|
+
$$\begin{align}
|
|
72
|
+
t_p(\lambda) &= \Upsilon_t \lambda + \Delta t^{(r)}(\Upsilon_r\lambda) + \Delta t^{(\theta)}(\Upsilon_\theta\lambda),
|
|
73
|
+
\\
|
|
74
|
+
\phi_p(\lambda) &= \Upsilon_\phi \lambda + \Delta \phi^{(r)}(\Upsilon_r\lambda) + \Delta \phi^{(\theta)}(\Upsilon_\theta\lambda),
|
|
75
|
+
\end{align}$$
|
|
76
|
+
where $\Delta t^{(r)}$, $\Delta \phi^{(r)}$, $\Delta t^{(\theta)}$, and $\Delta \phi^{(\theta)}$ are $2\pi$-periodic odd functions.
|