Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
pyShamphys.cpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
21#include "shamcomm/logs.hpp"
23#include "shamphys/Dust.hpp"
25#include "shamphys/Planets.hpp"
27#include "shamphys/SodTube.hpp"
28#include "shamphys/collapse.hpp"
29#include "shamphys/eos.hpp"
35#include "shamphys/orbits.hpp"
36#include <pybind11/complex.h>
37#include <complex>
38#include <utility>
39
40Register_pymod(shamphyslibinit) {
41
42 py::module shamphys_module = m.def_submodule("phys", "Physics Library");
43
44 // Planets.hpp
45
46 shamphys_module.def(
47 "hill_radius",
48 &shamphys::hill_radius<f64>,
49 py::kw_only(),
50 py::arg("R"),
51 py::arg("m"),
52 py::arg("M"),
53 R"pbdoc(
54 Compute the hill radius of a planet
55 R : Orbit radius
56 m : planet mass
57 M : Star mass
58 )pbdoc");
59
60 shamphys_module.def(
61 "keplerian_speed",
62 [](f64 G, f64 M, f64 R) {
63 return shamphys::keplerian_speed(G, M, R);
64 },
65 py::kw_only(),
66 py::arg("G"),
67 py::arg("M"),
68 py::arg("R"),
69 R"pbdoc(
70 Compute the keplerian orbit speed
71 G : Gravitational constant
72 M : planet mass
73 R : orbit radius
74 )pbdoc");
75
76 shamphys_module.def(
77 "keplerian_speed",
78 [](f64 M, f64 R, shamunits::UnitSystem<f64> usys) {
79 return shamphys::keplerian_speed(M, R, usys);
80 },
81 py::kw_only(),
82 py::arg("M"),
83 py::arg("R"),
84 py::arg("units"),
85 R"pbdoc(
86 Compute the keplerian orbit speed
87 M : planet mass
88 R : orbit radius
89 units : unit system
90 )pbdoc");
91
92 // BlackHole.hpp
93
94 shamphys_module.def(
95 "schwarzschild_radius",
96 [](f64 M, f64 G, f64 c) {
97 return shamphys::schwarzschild_radius(M, G, c);
98 },
99 py::kw_only(),
100 py::arg("M"),
101 py::arg("G"),
102 py::arg("c"),
103 R"pbdoc(
104 Compute the schwarzschild radius
105 M : Black hole mass
106 G : Gravitational constant
107 c : Speed of light
108 )pbdoc");
109
110 shamphys_module.def(
111 "schwarzschild_radius",
112 [](f64 M, shamunits::UnitSystem<f64> usys) {
113 return shamphys::schwarzschild_radius(M, usys);
114 },
115 py::kw_only(),
116 py::arg("M"),
117 py::arg("units"),
118 R"pbdoc(
119 Compute the schwarzschild radius
120 M : Black hole mass
121 units : unit system
122 )pbdoc");
123
124 shamphys_module.def(
125 "get_binary_pair",
126 [](double m1, double m2, double a, double e, double nu, double G) {
127 return shamphys::get_binary_pair(m1, m2, a, e, nu, G);
128 },
129 py::kw_only(),
130 py::arg("m1"),
131 py::arg("m2"),
132 py::arg("a"),
133 py::arg("e"),
134 py::arg("nu"),
135 py::arg("G"),
136 R"pbdoc(
137 Compute the positions and velocities of two objects in a binary system
138 m1 : Mass of the first object
139 m2 : Mass of the second object
140 a : Semi-major axis of the system
141 e : Eccentricity of the system
142 nu : True anomaly of the system (in radians)
143 G : Gravitational constant
144 )pbdoc");
145
146 shamphys_module.def(
147 "get_binary_pair",
148 [](double m1,
149 double m2,
150 double a,
151 double e,
152 double nu,
154 return shamphys::get_binary_pair(m1, m2, a, e, nu, usys);
155 },
156 py::kw_only(),
157 py::arg("m1"),
158 py::arg("m2"),
159 py::arg("a"),
160 py::arg("e"),
161 py::arg("nu"),
162 py::arg("units"),
163 R"pbdoc(
164 Compute the positions and velocities of two objects in a binary system
165 m1 : Mass of the first object
166 m2 : Mass of the second object
167 a : Semi-major axis of the system
168 e : Eccentricity of the system
169 nu : True anomaly of the system (in radians)
170 units : unit system
171 )pbdoc");
172
173 shamphys_module.def(
174 "rotate_point",
175 [](f64_3 point, double roll, double pitch, double yaw) {
176 return shamphys::rotate_point(point, roll, pitch, yaw);
177 },
178 py::kw_only(),
179 py::arg("point"),
180 py::arg("roll"),
181 py::arg("pitch"),
182 py::arg("yaw"),
183 R"pbdoc(
184 Rotate a 3D point using Euler angles.
185 point : 3D point as a f64_3
186 roll : Rotation about the X-axis (in radians)
187 pitch : Rotation about the Y-axis (in radians)
188 yaw : Rotation about the Z-axis (in radians)
189 )pbdoc");
190
191 shamphys_module.def(
192 "get_binary_rotated",
193 [](double m1,
194 double m2,
195 double a,
196 double e,
197 double nu,
198 double G,
199 double roll,
200 double pitch,
201 double yaw) {
202 return shamphys::get_binary_rotated(m1, m2, a, e, nu, G, roll, pitch, yaw);
203 },
204 py::kw_only(),
205 py::arg("m1"),
206 py::arg("m2"),
207 py::arg("a"),
208 py::arg("e"),
209 py::arg("nu"),
210 py::arg("G"),
211 py::arg("roll"),
212 py::arg("pitch"),
213 py::arg("yaw"),
214 R"pbdoc(
215 Rotate a binary orbit by Euler angles and return the positions and
216 velocities of the two objects.
217 m1 : Mass of the first object
218 m2 : Mass of the second object
219 a : Semi-major axis of the system
220 e : Eccentricity of the system
221 nu : True anomaly of the system (in radians)
222 G : Gravitational constant
223 roll : Rotation about the X-axis (in radians)
224 pitch : Rotation about the Y-axis (in radians)
225 yaw : Rotation about the Z-axis (in radians)
226 )pbdoc");
227
228 shamphys_module.def(
229 "get_binary_rotated",
230 [](double m1,
231 double m2,
232 double a,
233 double e,
234 double nu,
236 double roll,
237 double pitch,
238 double yaw) {
239 return shamphys::get_binary_rotated(m1, m2, a, e, nu, usys, roll, pitch, yaw);
240 },
241 py::kw_only(),
242 py::arg("m1"),
243 py::arg("m2"),
244 py::arg("a"),
245 py::arg("e"),
246 py::arg("nu"),
247 py::arg("units"),
248 py::arg("roll"),
249 py::arg("pitch"),
250 py::arg("yaw"));
251
252 shamphys_module.def(
253 "free_fall_time",
254 [](f64 rho, f64 G) {
255 return shamphys::free_fall_time(rho, G);
256 },
257 py::arg("rho"),
258 py::arg("G"),
259 R"pbdoc(
260 Compute the free fall time
261 rho : Density
262 G : Gravitational constant
263 )pbdoc");
264
265 shamphys_module.def(
266 "free_fall_time",
267 [](f64 rho, const shamunits::UnitSystem<f64> usys) {
268 return shamphys::free_fall_time(rho, usys);
269 },
270 py::arg("rho"),
271 py::arg("units"),
272 R"pbdoc(
273 Compute the free fall time
274 rho : Density
275 units : unit system
276 )pbdoc");
277
278 shamphys_module.def(
279 "epstein_supersonic_correction",
280 [](double delta_v, double cs) {
281 return shamphys::epstein_supersonic_correction<double>(delta_v, cs);
282 },
283 py::kw_only(),
284 py::arg("delta_v"),
285 py::arg("cs"),
286 R"pbdoc(
287 Epstein drag supersonic correction factor for spherical dust grains.
288
289 Corrects the Epstein drag force when the drift speed between dust
290 and gas exceeds the thermal speed.
291
292 \f$f(\Delta v, c_s) = \sqrt{1 + \frac{9\pi}{128} \frac{\Delta v^2}{c_s^2}}\f$
293
294 Args:
295 delta_v: Drift speed between dust and gas
296 cs: Gas sound speed
297
298 Returns:
299 The supersonic correction factor f(delta_v, cs)
300 )pbdoc");
301
302 shamphys_module.def(
303 "epstein_stopping_time",
304 [](double rho_grain, double s_grain, double rho, double cs, double gamma, double f) {
305 return shamphys::epstein_stopping_time(rho_grain, s_grain, rho, cs, gamma, f);
306 },
307 py::kw_only(),
308 py::arg("rho_grain"),
309 py::arg("s_grain"),
310 py::arg("rho"),
311 py::arg("cs"),
312 py::arg("gamma"),
313 py::arg("f") = 1.0,
314 R"pbdoc(
315 Epstein drag stopping time for spherical dust grains.
316
317 \f[t_s = \frac{\rho_{\rm grain} \, s_{\rm grain}}{\rho \, c_s \, f} \sqrt{\frac{\pi \gamma}{8}}\f]
318
319 where \f$\rho = \rho_{\rm g} + \rho_{\rm d}\f$ is the total density and \f$f\f$
320 is the supersonic correction factor.
321
322 Args:
323 rho_grain: Internal density of the dust grain
324 s_grain: Radius of the dust grain
325 rho: Total density (\f$\rho_{\rm g} + \rho_{\rm d}\f$)
326 cs: Gas sound speed
327 gamma: Adiabatic index
328 f: Supersonic correction factor (1.0 for subsonic)
329
330 Returns:
331 The stopping time
332 )pbdoc");
333
334 shamcomm::logs::debug_ln("[Py]", "registering shamrock.phys.HydroSoundwave");
335 py::class_<shamphys::HydroSoundwave>(shamphys_module, "HydroSoundwave")
336 .def(
337 py::init([](f64 cs, f64 k, std::complex<f64> rho_tilde, std::complex<f64> v_tilde) {
338 return std::make_unique<shamphys::HydroSoundwave>(
339 shamphys::HydroSoundwave{cs, k, rho_tilde, v_tilde});
340 }),
341 py::kw_only(),
342 py::arg("cs"),
343 py::arg("k"),
344 py::arg("rho_tilde"),
345 py::arg("v_tilde"))
346 .def("get_omega", &shamphys::HydroSoundwave::get_omega)
347 .def("get_value", [](shamphys::HydroSoundwave &self, f64 t, f64 x) {
348 auto ret = self.get_value(t, x);
349 return std::pair<f64, f64>{ret.rho, ret.v};
350 });
351
352 shamcomm::logs::debug_ln("[Py]", "registering shamrock.phys.SodTube");
353 py::class_<shamphys::SodTube>(shamphys_module, "SodTube")
354 .def(
355 py::init([](f64 gamma, f64 rho_1, f64 P_1, f64 rho_5, f64 P_5) {
356 return std::make_unique<shamphys::SodTube>(
357 shamphys::SodTube{gamma, rho_1, P_1, rho_5, P_5});
358 }),
359 py::kw_only(),
360 py::arg("gamma"),
361 py::arg("rho_1"),
362 py::arg("P_1"),
363 py::arg("rho_5"),
364 py::arg("P_5"))
365 .def("get_value", [](shamphys::SodTube &self, f64 t, f64 x) {
366 auto ret = self.get_value(t, x);
367 return std::tuple<f64, f64, f64>{ret.rho, ret.vx, ret.P};
368 });
369
370 shamcomm::logs::debug_ln("[Py]", "registering shamrock.phys.SedovTaylor");
371 py::class_<shamphys::SedovTaylor>(shamphys_module, "SedovTaylor")
372 .def(py::init([]() {
373 return std::make_unique<shamphys::SedovTaylor>(shamphys::SedovTaylor{});
374 }))
375 .def("get_value", [](shamphys::SedovTaylor &self, f64 x) {
376 auto ret = self.get_value(x);
377 return std::tuple<f64, f64, f64>{ret.rho, ret.vx, ret.P};
378 });
379
380 shamcomm::logs::debug_ln("[Py]", "registering shamrock.phys.green_func_grav_cartesian");
381 shamphys_module.def(
382 "green_func_grav_cartesian_0_5", &shamphys::green_func_grav_cartesian<f64, 0, 5>);
383 shamphys_module.def(
384 "green_func_grav_cartesian_0_4", &shamphys::green_func_grav_cartesian<f64, 0, 4>);
385 shamphys_module.def(
386 "green_func_grav_cartesian_0_3", &shamphys::green_func_grav_cartesian<f64, 0, 3>);
387 shamphys_module.def(
388 "green_func_grav_cartesian_0_2", &shamphys::green_func_grav_cartesian<f64, 0, 2>);
389 shamphys_module.def(
390 "green_func_grav_cartesian_0_1", &shamphys::green_func_grav_cartesian<f64, 0, 1>);
391 shamphys_module.def(
392 "green_func_grav_cartesian_0_0", &shamphys::green_func_grav_cartesian<f64, 0, 0>);
393 shamphys_module.def(
394 "green_func_grav_cartesian_1_5", &shamphys::green_func_grav_cartesian<f64, 1, 5>);
395 shamphys_module.def(
396 "green_func_grav_cartesian_1_4", &shamphys::green_func_grav_cartesian<f64, 1, 4>);
397 shamphys_module.def(
398 "green_func_grav_cartesian_1_3", &shamphys::green_func_grav_cartesian<f64, 1, 3>);
399 shamphys_module.def(
400 "green_func_grav_cartesian_1_2", &shamphys::green_func_grav_cartesian<f64, 1, 2>);
401 shamphys_module.def(
402 "green_func_grav_cartesian_1_1", &shamphys::green_func_grav_cartesian<f64, 1, 1>);
403
404 shamcomm::logs::debug_ln("[Py]", "registering shamrock.phys.grav_moments");
405 shamphys_module.def("get_M_mat_5", &shamphys::get_M_mat<f64, 0, 5>);
406 shamphys_module.def("get_M_mat_4", &shamphys::get_M_mat<f64, 0, 4>);
407 shamphys_module.def("get_M_mat_3", &shamphys::get_M_mat<f64, 0, 3>);
408 shamphys_module.def("get_M_mat_2", &shamphys::get_M_mat<f64, 0, 2>);
409 shamphys_module.def("get_M_mat_1", &shamphys::get_M_mat<f64, 0, 1>);
410 shamphys_module.def("get_M_mat_0", &shamphys::get_M_mat<f64, 0, 0>);
411 shamphys_module.def("get_dM_mat_5", &shamphys::get_dM_mat<f64, 4>);
412 shamphys_module.def("get_dM_mat_4", &shamphys::get_dM_mat<f64, 3>);
413 shamphys_module.def("get_dM_mat_3", &shamphys::get_dM_mat<f64, 2>);
414 shamphys_module.def("get_dM_mat_2", &shamphys::get_dM_mat<f64, 1>);
415 shamphys_module.def("get_dM_mat_1", &shamphys::get_dM_mat<f64, 0>);
416
417 shamcomm::logs::debug_ln("[Py]", "registering shamrock.phys.contract_grav_moment_to_force");
418 shamphys_module.def(
419 "contract_grav_moment_to_force_5", &shamphys::contract_grav_moment_to_force<f64, 5>);
420 shamphys_module.def(
421 "contract_grav_moment_to_force_4", &shamphys::contract_grav_moment_to_force<f64, 4>);
422 shamphys_module.def(
423 "contract_grav_moment_to_force_3", &shamphys::contract_grav_moment_to_force<f64, 3>);
424 shamphys_module.def(
425 "contract_grav_moment_to_force_2", &shamphys::contract_grav_moment_to_force<f64, 2>);
426 shamphys_module.def(
427 "contract_grav_moment_to_force_1", &shamphys::contract_grav_moment_to_force<f64, 1>);
428
429 shamcomm::logs::debug_ln("[Py]", "registering shamrock.phys.offset_multipole");
430 shamphys_module.def(
431 "offset_multipole_5",
432 &shamphys::offset_multipole<f64, 0, 5>,
433 py::arg("Q"),
434 py::arg("from"),
435 py::arg("to"));
436 shamphys_module.def(
437 "offset_multipole_4",
438 &shamphys::offset_multipole<f64, 0, 4>,
439 py::arg("Q"),
440 py::arg("from"),
441 py::arg("to"));
442 shamphys_module.def(
443 "offset_multipole_3",
444 &shamphys::offset_multipole<f64, 0, 3>,
445 py::arg("Q"),
446 py::arg("from"),
447 py::arg("to"));
448 shamphys_module.def(
449 "offset_multipole_2",
450 &shamphys::offset_multipole<f64, 0, 2>,
451 py::arg("Q"),
452 py::arg("from"),
453 py::arg("to"));
454 shamphys_module.def(
455 "offset_multipole_1",
456 &shamphys::offset_multipole<f64, 0, 1>,
457 py::arg("Q"),
458 py::arg("from"),
459 py::arg("to"));
460 shamphys_module.def(
461 "offset_multipole_0",
462 &shamphys::offset_multipole<f64, 0, 0>,
463 py::arg("Q"),
464 py::arg("from"),
465 py::arg("to"));
466
467 shamcomm::logs::debug_ln("[Py]", "registering shamrock.phys.offset_dM_mat");
468 shamphys_module.def(
469 "offset_dM_mat_5",
470 &shamphys::offset_dM_mat<f64, 1, 5>,
471 py::arg("dM"),
472 py::arg("from"),
473 py::arg("to"));
474 shamphys_module.def(
475 "offset_dM_mat_4",
476 &shamphys::offset_dM_mat<f64, 1, 4>,
477 py::arg("dM"),
478 py::arg("from"),
479 py::arg("to"));
480 shamphys_module.def(
481 "offset_dM_mat_3",
482 &shamphys::offset_dM_mat<f64, 1, 3>,
483 py::arg("dM"),
484 py::arg("from"),
485 py::arg("to"));
486 shamphys_module.def(
487 "offset_dM_mat_2",
488 &shamphys::offset_dM_mat<f64, 1, 2>,
489 py::arg("dM"),
490 py::arg("from"),
491 py::arg("to"));
492 shamphys_module.def(
493 "offset_dM_mat_1",
494 &shamphys::offset_dM_mat<f64, 1, 1>,
495 py::arg("dM"),
496 py::arg("from"),
497 py::arg("to"));
498
499 // EOS
500
501 py::module eos_module = shamphys_module.def_submodule("eos");
502
503 eos_module.def(
504 "eos_Machida06",
505 [](f64 cs, f64 rho, f64 rho_c1, f64 rho_c2, f64 rho_c3, f64 mu, f64 mh, f64 kb) {
506 auto P = shamphys::EOS_Machida06<f64>::pressure(cs, rho, rho_c1, rho_c2, rho_c3);
507 auto _cs = shamphys::EOS_Machida06<f64>::soundspeed(P, rho, rho_c1, rho_c2, rho_c3);
508 auto T = shamphys::EOS_Machida06<f64>::temperature(P, rho, mu, mh, kb);
509 return std::tuple<f64, f64, f64>{P, _cs, T};
510 },
511 py::kw_only(),
512 py::arg("cs"),
513 py::arg("rho"),
514 py::arg("rho_c1"),
515 py::arg("rho_c2"),
516 py::arg("rho_c3"),
517 py::arg("mu"),
518 py::arg("mh"),
519 py::arg("kb"));
520
521 eos_module.def(
522 "eos_Fermi",
523 [](f64 mu_e, f64 rho) {
525 return std::tuple<f64, f64>{P_cs.pressure, P_cs.soundspeed};
526 },
527 py::kw_only(),
528 py::arg("mu_e"),
529 py::arg("rho"));
530}
Epstein drag stopping time for spherical dust grains.
T epstein_stopping_time(T rho_grain, T s_grain, T rho, T cs, T gamma, T f=T(1.0)) noexcept
Epstein drag stopping time for spherical dust grains.
Definition Dust.hpp:75
double f64
Alias for double.
Represents a Sedov-Taylor solution, a self-similar solution to the hydrodynamic equations describing ...
field_val get_value(f64 x)
Compute field values at radial distance x.
Defines a unit system.
Functions for gravitational collapse calculations.
auto get_binary_pair(double m1, double m2, double a, double e, double nu, double G)
Convert a binary system from Keplerian to Cartesian coordinates.
Definition orbits.hpp:40
auto get_binary_rotated(double m1, double m2, double a, double e, double nu, double G, double roll, double pitch, double yaw)
Rotate a binary orbit by Euler angles and return the positions and velocities of the two objects.
Definition orbits.hpp:152
Pybind11 include and definitions.
#define Register_pymod(placeholdername)
Register a python module init function using static initialisation.
void debug_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:133
static constexpr PressureAndCs< T > pressure_and_soundspeed(T mu_e, T rho)
EOS_Fermi::pressure_and_soundspeed Returns pressure and sound speed from the given value of density i...
Definition eos.hpp:205
Piecewise polytropic EOS from Machida et al. (2006)
Definition eos.hpp:133