physicskit 0.1.0__py3-none-any.whl

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.
Files changed (484) hide show
  1. physicskit/__init__.py +51 -0
  2. physicskit/astro/__init__.py +66 -0
  3. physicskit/astro/cosmic_web.py +395 -0
  4. physicskit/astro/galactic_dynamics.py +137 -0
  5. physicskit/astro/nbody.py +208 -0
  6. physicskit/astro/orbital_mechanics.py +220 -0
  7. physicskit/astro/stellar_dynamo.py +628 -0
  8. physicskit/astro/stellar_structure.py +198 -0
  9. physicskit/astro/tests/__init__.py +0 -0
  10. physicskit/astro/tests/conftest.py +7 -0
  11. physicskit/astro/tests/test_cosmic_web.py +159 -0
  12. physicskit/astro/tests/test_galactic_dynamics.py +46 -0
  13. physicskit/astro/tests/test_nbody.py +81 -0
  14. physicskit/astro/tests/test_orbital_mechanics.py +73 -0
  15. physicskit/astro/tests/test_stellar_dynamo.py +198 -0
  16. physicskit/astro/tests/test_stellar_structure.py +52 -0
  17. physicskit/astro/tests/test_visualizers.py +159 -0
  18. physicskit/astro/visualizers.py +628 -0
  19. physicskit/chaos/__init__.py +55 -0
  20. physicskit/chaos/core/__init__.py +3 -0
  21. physicskit/chaos/core/base_system.py +342 -0
  22. physicskit/chaos/core/integrators.py +40 -0
  23. physicskit/chaos/exceptions.py +24 -0
  24. physicskit/chaos/quantum/__init__.py +38 -0
  25. physicskit/chaos/quantum/billiards.py +274 -0
  26. physicskit/chaos/quantum/husimi.py +85 -0
  27. physicskit/chaos/quantum/maps.py +366 -0
  28. physicskit/chaos/systems/__init__.py +38 -0
  29. physicskit/chaos/systems/billiards.py +1131 -0
  30. physicskit/chaos/systems/continuous.py +1276 -0
  31. physicskit/chaos/systems/maps.py +557 -0
  32. physicskit/chaos/tests/__init__.py +0 -0
  33. physicskit/chaos/tests/test_basins.py +76 -0
  34. physicskit/chaos/tests/test_bifurcation.py +132 -0
  35. physicskit/chaos/tests/test_billiards.py +115 -0
  36. physicskit/chaos/tests/test_continuous.py +224 -0
  37. physicskit/chaos/tests/test_dimension.py +69 -0
  38. physicskit/chaos/tests/test_divergence.py +90 -0
  39. physicskit/chaos/tests/test_dynamic_plots.py +269 -0
  40. physicskit/chaos/tests/test_integrators.py +96 -0
  41. physicskit/chaos/tests/test_io.py +41 -0
  42. physicskit/chaos/tests/test_maps.py +110 -0
  43. physicskit/chaos/tests/test_metrics.py +115 -0
  44. physicskit/chaos/tests/test_phase_space.py +73 -0
  45. physicskit/chaos/tests/test_properties.py +116 -0
  46. physicskit/chaos/tests/test_quantum_billiards.py +94 -0
  47. physicskit/chaos/tests/test_quantum_maps.py +144 -0
  48. physicskit/chaos/tests/test_recurrence.py +51 -0
  49. physicskit/chaos/tests/test_repr_and_api_consistency.py +134 -0
  50. physicskit/chaos/tests/test_section.py +49 -0
  51. physicskit/chaos/tests/test_spectral.py +48 -0
  52. physicskit/chaos/tests/test_streamlit_app.py +45 -0
  53. physicskit/chaos/tests/test_timeseries.py +131 -0
  54. physicskit/chaos/tests/test_viewer3d.py +41 -0
  55. physicskit/chaos/utils/__init__.py +46 -0
  56. physicskit/chaos/utils/dimension.py +139 -0
  57. physicskit/chaos/utils/io.py +95 -0
  58. physicskit/chaos/utils/metrics.py +304 -0
  59. physicskit/chaos/utils/recurrence.py +122 -0
  60. physicskit/chaos/utils/spectral.py +69 -0
  61. physicskit/chaos/utils/timeseries.py +303 -0
  62. physicskit/chaos/visualizers/__init__.py +85 -0
  63. physicskit/chaos/visualizers/basins.py +185 -0
  64. physicskit/chaos/visualizers/bifurcation.py +273 -0
  65. physicskit/chaos/visualizers/divergence.py +374 -0
  66. physicskit/chaos/visualizers/dynamic_plots.py +1372 -0
  67. physicskit/chaos/visualizers/phase_space.py +133 -0
  68. physicskit/chaos/visualizers/quantum.py +299 -0
  69. physicskit/chaos/visualizers/recurrence.py +91 -0
  70. physicskit/chaos/visualizers/section.py +161 -0
  71. physicskit/chaos/visualizers/theme.py +31 -0
  72. physicskit/chaos/visualizers/viewer3d.py +82 -0
  73. physicskit/classical/__init__.py +55 -0
  74. physicskit/classical/core/__init__.py +17 -0
  75. physicskit/classical/core/base_system.py +510 -0
  76. physicskit/classical/core/integrators.py +397 -0
  77. physicskit/classical/systems/__init__.py +32 -0
  78. physicskit/classical/systems/chains.py +334 -0
  79. physicskit/classical/systems/hamiltonian.py +215 -0
  80. physicskit/classical/systems/lagrangian.py +308 -0
  81. physicskit/classical/systems/newtonian.py +536 -0
  82. physicskit/classical/systems/rotations.py +614 -0
  83. physicskit/classical/tests/__init__.py +0 -0
  84. physicskit/classical/tests/conftest.py +7 -0
  85. physicskit/classical/tests/test_base_system.py +113 -0
  86. physicskit/classical/tests/test_chains.py +84 -0
  87. physicskit/classical/tests/test_conservation.py +244 -0
  88. physicskit/classical/tests/test_conservation_utils.py +47 -0
  89. physicskit/classical/tests/test_hamiltonian.py +44 -0
  90. physicskit/classical/tests/test_integrators.py +123 -0
  91. physicskit/classical/tests/test_lagrangian.py +69 -0
  92. physicskit/classical/tests/test_newtonian.py +45 -0
  93. physicskit/classical/tests/test_rotations.py +160 -0
  94. physicskit/classical/tests/test_stepsize.py +149 -0
  95. physicskit/classical/tests/test_symbolic.py +125 -0
  96. physicskit/classical/tests/test_visualizers.py +172 -0
  97. physicskit/classical/utils/__init__.py +20 -0
  98. physicskit/classical/utils/conservation.py +126 -0
  99. physicskit/classical/utils/stepsize.py +187 -0
  100. physicskit/classical/utils/symbolic.py +235 -0
  101. physicskit/classical/visualizers/__init__.py +25 -0
  102. physicskit/classical/visualizers/animations.py +508 -0
  103. physicskit/classical/visualizers/interactive.py +113 -0
  104. physicskit/classical/visualizers/modal_analysis.py +97 -0
  105. physicskit/classical/visualizers/phase_space.py +214 -0
  106. physicskit/condensed/__init__.py +122 -0
  107. physicskit/condensed/anderson_localization.py +155 -0
  108. physicskit/condensed/correlated.py +284 -0
  109. physicskit/condensed/ginzburg_landau.py +220 -0
  110. physicskit/condensed/landau_levels.py +246 -0
  111. physicskit/condensed/laughlin.py +229 -0
  112. physicskit/condensed/models.py +627 -0
  113. physicskit/condensed/tests/__init__.py +0 -0
  114. physicskit/condensed/tests/test_condensed.py +518 -0
  115. physicskit/condensed/tests/test_visualizers.py +87 -0
  116. physicskit/condensed/tight_binding.py +445 -0
  117. physicskit/condensed/topological_insulator_3d.py +178 -0
  118. physicskit/condensed/topology.py +217 -0
  119. physicskit/condensed/visualizers.py +296 -0
  120. physicskit/condensed/weyl.py +180 -0
  121. physicskit/constants.py +184 -0
  122. physicskit/fields/__init__.py +111 -0
  123. physicskit/fields/electrodynamics.py +671 -0
  124. physicskit/fields/quantum_fields.py +510 -0
  125. physicskit/fields/solitons.py +527 -0
  126. physicskit/fields/tests/__init__.py +0 -0
  127. physicskit/fields/tests/conftest.py +7 -0
  128. physicskit/fields/tests/test_field_animations.py +154 -0
  129. physicskit/fields/tests/test_fields.py +439 -0
  130. physicskit/fields/tests/test_visualizers.py +101 -0
  131. physicskit/fields/visualizers.py +503 -0
  132. physicskit/fluids/__init__.py +134 -0
  133. physicskit/fluids/core/__init__.py +23 -0
  134. physicskit/fluids/core/grid.py +165 -0
  135. physicskit/fluids/core/timestepping.py +231 -0
  136. physicskit/fluids/exceptions.py +26 -0
  137. physicskit/fluids/systems/__init__.py +70 -0
  138. physicskit/fluids/systems/compressible_flow.py +281 -0
  139. physicskit/fluids/systems/instabilities.py +343 -0
  140. physicskit/fluids/systems/navier_stokes.py +221 -0
  141. physicskit/fluids/systems/potential_flow.py +440 -0
  142. physicskit/fluids/systems/viscous_flow.py +425 -0
  143. physicskit/fluids/systems/vortex_dynamics.py +304 -0
  144. physicskit/fluids/tests/__init__.py +0 -0
  145. physicskit/fluids/tests/conftest.py +7 -0
  146. physicskit/fluids/tests/test_compressible_flow.py +66 -0
  147. physicskit/fluids/tests/test_instabilities.py +115 -0
  148. physicskit/fluids/tests/test_navier_stokes.py +67 -0
  149. physicskit/fluids/tests/test_potential_flow.py +92 -0
  150. physicskit/fluids/tests/test_static_visualizers.py +91 -0
  151. physicskit/fluids/tests/test_utils.py +100 -0
  152. physicskit/fluids/tests/test_viscous_flow.py +110 -0
  153. physicskit/fluids/tests/test_visualizers.py +34 -0
  154. physicskit/fluids/tests/test_vortex_dynamics.py +88 -0
  155. physicskit/fluids/utils/__init__.py +18 -0
  156. physicskit/fluids/utils/dimensionless.py +239 -0
  157. physicskit/fluids/utils/spectral_analysis.py +142 -0
  158. physicskit/fluids/visualizers/__init__.py +14 -0
  159. physicskit/fluids/visualizers/compressible.py +39 -0
  160. physicskit/fluids/visualizers/flow_fields.py +252 -0
  161. physicskit/fluids/visualizers/potential_flow.py +51 -0
  162. physicskit/fluids/visualizers/spectra.py +62 -0
  163. physicskit/fluids/visualizers/theme.py +38 -0
  164. physicskit/integrators/__init__.py +52 -0
  165. physicskit/integrators/adaptive.py +199 -0
  166. physicskit/integrators/fixed_step.py +360 -0
  167. physicskit/integrators/tests/__init__.py +0 -0
  168. physicskit/integrators/tests/test_integrators.py +101 -0
  169. physicskit/optics/__init__.py +124 -0
  170. physicskit/optics/_compat.py +5 -0
  171. physicskit/optics/gaussian.py +382 -0
  172. physicskit/optics/quantum_optics.py +428 -0
  173. physicskit/optics/ray.py +469 -0
  174. physicskit/optics/tests/__init__.py +0 -0
  175. physicskit/optics/tests/test_diffraction_animation.py +38 -0
  176. physicskit/optics/tests/test_gaussian.py +170 -0
  177. physicskit/optics/tests/test_quantum_optics.py +147 -0
  178. physicskit/optics/tests/test_ray.py +177 -0
  179. physicskit/optics/tests/test_visualizers.py +58 -0
  180. physicskit/optics/tests/test_wave.py +146 -0
  181. physicskit/optics/visualizers.py +264 -0
  182. physicskit/optics/wave.py +365 -0
  183. physicskit/particle/__init__.py +152 -0
  184. physicskit/particle/collider.py +382 -0
  185. physicskit/particle/confinement.py +125 -0
  186. physicskit/particle/decays.py +357 -0
  187. physicskit/particle/electroweak.py +300 -0
  188. physicskit/particle/kinematics.py +271 -0
  189. physicskit/particle/neutrinos.py +84 -0
  190. physicskit/particle/nuclear.py +100 -0
  191. physicskit/particle/scattering.py +159 -0
  192. physicskit/particle/tests/__init__.py +0 -0
  193. physicskit/particle/tests/conftest.py +7 -0
  194. physicskit/particle/tests/test_collider.py +119 -0
  195. physicskit/particle/tests/test_confinement.py +42 -0
  196. physicskit/particle/tests/test_decays.py +112 -0
  197. physicskit/particle/tests/test_electroweak.py +97 -0
  198. physicskit/particle/tests/test_kinematics.py +138 -0
  199. physicskit/particle/tests/test_neutrinos.py +36 -0
  200. physicskit/particle/tests/test_nuclear.py +45 -0
  201. physicskit/particle/tests/test_scattering.py +64 -0
  202. physicskit/particle/tests/test_visualizers.py +214 -0
  203. physicskit/particle/visualizers/__init__.py +38 -0
  204. physicskit/particle/visualizers/animations.py +705 -0
  205. physicskit/particle/visualizers/static.py +101 -0
  206. physicskit/plasma/__init__.py +176 -0
  207. physicskit/plasma/acceleration.py +152 -0
  208. physicskit/plasma/instabilities.py +417 -0
  209. physicskit/plasma/kinetic.py +588 -0
  210. physicskit/plasma/mhd.py +463 -0
  211. physicskit/plasma/single_particle.py +562 -0
  212. physicskit/plasma/tests/__init__.py +0 -0
  213. physicskit/plasma/tests/conftest.py +7 -0
  214. physicskit/plasma/tests/test_new_time_domain_features.py +222 -0
  215. physicskit/plasma/tests/test_plasma.py +232 -0
  216. physicskit/plasma/tests/test_visualizers.py +79 -0
  217. physicskit/plasma/turbulence.py +219 -0
  218. physicskit/plasma/visualizers.py +868 -0
  219. physicskit/plasma/waves.py +549 -0
  220. physicskit/quantum/__init__.py +180 -0
  221. physicskit/quantum/_compat.py +20 -0
  222. physicskit/quantum/chapters/__init__.py +0 -0
  223. physicskit/quantum/chapters/entanglement.py +489 -0
  224. physicskit/quantum/chapters/harmonic_spin.py +517 -0
  225. physicskit/quantum/chapters/hydrogen_am.py +292 -0
  226. physicskit/quantum/chapters/perturbation.py +350 -0
  227. physicskit/quantum/chapters/potentials.py +997 -0
  228. physicskit/quantum/chapters/spin.py +306 -0
  229. physicskit/quantum/chapters/wave_packets.py +541 -0
  230. physicskit/quantum/core/__init__.py +0 -0
  231. physicskit/quantum/core/eigensolvers.py +311 -0
  232. physicskit/quantum/core/operators.py +296 -0
  233. physicskit/quantum/core/solvers.py +271 -0
  234. physicskit/quantum/tests/__init__.py +0 -0
  235. physicskit/quantum/tests/conftest.py +7 -0
  236. physicskit/quantum/tests/test_animations.py +225 -0
  237. physicskit/quantum/tests/test_compat.py +43 -0
  238. physicskit/quantum/tests/test_eigensolvers.py +24 -0
  239. physicskit/quantum/tests/test_entanglement.py +127 -0
  240. physicskit/quantum/tests/test_harmonic_spin.py +140 -0
  241. physicskit/quantum/tests/test_hydrogen_am.py +48 -0
  242. physicskit/quantum/tests/test_measure.py +110 -0
  243. physicskit/quantum/tests/test_operators.py +105 -0
  244. physicskit/quantum/tests/test_perturbation.py +112 -0
  245. physicskit/quantum/tests/test_physics_checks.py +131 -0
  246. physicskit/quantum/tests/test_potentials.py +191 -0
  247. physicskit/quantum/tests/test_solvers.py +70 -0
  248. physicskit/quantum/tests/test_spin.py +22 -0
  249. physicskit/quantum/tests/test_unitarity.py +84 -0
  250. physicskit/quantum/tests/test_wave_packets.py +53 -0
  251. physicskit/quantum/utils/__init__.py +0 -0
  252. physicskit/quantum/utils/measure.py +253 -0
  253. physicskit/quantum/visualizers/__init__.py +0 -0
  254. physicskit/quantum/visualizers/bloch_sphere.py +205 -0
  255. physicskit/quantum/visualizers/entanglement.py +58 -0
  256. physicskit/quantum/visualizers/orbitals.py +187 -0
  257. physicskit/quantum/visualizers/phase_space.py +179 -0
  258. physicskit/quantum/visualizers/wavefunctions.py +230 -0
  259. physicskit/relativity/__init__.py +61 -0
  260. physicskit/relativity/chapters/__init__.py +33 -0
  261. physicskit/relativity/chapters/cosmology.py +190 -0
  262. physicskit/relativity/chapters/gw_merger.py +399 -0
  263. physicskit/relativity/chapters/kerr.py +371 -0
  264. physicskit/relativity/chapters/lensing.py +196 -0
  265. physicskit/relativity/chapters/neutron_star.py +149 -0
  266. physicskit/relativity/chapters/schwarzschild.py +412 -0
  267. physicskit/relativity/chapters/timekeeping.py +133 -0
  268. physicskit/relativity/core/__init__.py +12 -0
  269. physicskit/relativity/core/geodesics.py +216 -0
  270. physicskit/relativity/core/kerr_raytracer.py +259 -0
  271. physicskit/relativity/core/raytracer.py +241 -0
  272. physicskit/relativity/core/tensors.py +468 -0
  273. physicskit/relativity/tests/__init__.py +0 -0
  274. physicskit/relativity/tests/test_conservations.py +54 -0
  275. physicskit/relativity/tests/test_constants.py +34 -0
  276. physicskit/relativity/tests/test_cosmology.py +61 -0
  277. physicskit/relativity/tests/test_gw_merger.py +117 -0
  278. physicskit/relativity/tests/test_kerr.py +116 -0
  279. physicskit/relativity/tests/test_kerr_raytracer.py +103 -0
  280. physicskit/relativity/tests/test_lensing.py +75 -0
  281. physicskit/relativity/tests/test_neutron_star.py +48 -0
  282. physicskit/relativity/tests/test_raytracer.py +67 -0
  283. physicskit/relativity/tests/test_schwarzschild.py +126 -0
  284. physicskit/relativity/tests/test_shadow_render.py +81 -0
  285. physicskit/relativity/tests/test_tensors.py +86 -0
  286. physicskit/relativity/tests/test_timekeeping.py +51 -0
  287. physicskit/relativity/tests/test_visualizers_misc.py +115 -0
  288. physicskit/relativity/utils/__init__.py +1 -0
  289. physicskit/relativity/utils/constants.py +232 -0
  290. physicskit/relativity/visualizers/__init__.py +46 -0
  291. physicskit/relativity/visualizers/interactive.py +127 -0
  292. physicskit/relativity/visualizers/shadow_render.py +367 -0
  293. physicskit/relativity/visualizers/spacetime_3d.py +92 -0
  294. physicskit/relativity/visualizers/spacetime_diagrams.py +198 -0
  295. physicskit/relativity/visualizers/wave_plots.py +185 -0
  296. physicskit/rmt/__init__.py +8 -0
  297. physicskit/rmt/ensembles/__init__.py +108 -0
  298. physicskit/rmt/ensembles/banded.py +114 -0
  299. physicskit/rmt/ensembles/base.py +135 -0
  300. physicskit/rmt/ensembles/bdg.py +218 -0
  301. physicskit/rmt/ensembles/chiral.py +308 -0
  302. physicskit/rmt/ensembles/circular.py +104 -0
  303. physicskit/rmt/ensembles/crossover.py +82 -0
  304. physicskit/rmt/ensembles/density_matrix.py +148 -0
  305. physicskit/rmt/ensembles/effective_hamiltonian.py +230 -0
  306. physicskit/rmt/ensembles/embedded.py +207 -0
  307. physicskit/rmt/ensembles/gaussian.py +153 -0
  308. physicskit/rmt/ensembles/ginibre.py +110 -0
  309. physicskit/rmt/ensembles/girko.py +190 -0
  310. physicskit/rmt/ensembles/graph_laplacian.py +92 -0
  311. physicskit/rmt/ensembles/haar.py +57 -0
  312. physicskit/rmt/ensembles/jacobi.py +182 -0
  313. physicskit/rmt/ensembles/poisson.py +77 -0
  314. physicskit/rmt/ensembles/polynomial.py +139 -0
  315. physicskit/rmt/ensembles/pt_symmetric.py +120 -0
  316. physicskit/rmt/ensembles/single_ring.py +170 -0
  317. physicskit/rmt/ensembles/sparse.py +95 -0
  318. physicskit/rmt/ensembles/syk.py +170 -0
  319. physicskit/rmt/ensembles/truncated_unitary.py +80 -0
  320. physicskit/rmt/ensembles/universality.py +92 -0
  321. physicskit/rmt/ensembles/wishart.py +88 -0
  322. physicskit/rmt/py.typed +0 -0
  323. physicskit/rmt/spectrum.py +82 -0
  324. physicskit/rmt/stats/__init__.py +160 -0
  325. physicskit/rmt/stats/characteristic_polynomial.py +77 -0
  326. physicskit/rmt/stats/circular_law.py +54 -0
  327. physicskit/rmt/stats/correlations.py +162 -0
  328. physicskit/rmt/stats/density.py +70 -0
  329. physicskit/rmt/stats/entanglement.py +36 -0
  330. physicskit/rmt/stats/free_probability.py +202 -0
  331. physicskit/rmt/stats/localization.py +338 -0
  332. physicskit/rmt/stats/marchenko_pastur.py +55 -0
  333. physicskit/rmt/stats/pt_symmetric.py +265 -0
  334. physicskit/rmt/stats/ratios.py +110 -0
  335. physicskit/rmt/stats/real_ginibre.py +134 -0
  336. physicskit/rmt/stats/rigidity.py +272 -0
  337. physicskit/rmt/stats/single_ring.py +95 -0
  338. physicskit/rmt/stats/spacing.py +150 -0
  339. physicskit/rmt/stats/tracy_widom.py +175 -0
  340. physicskit/rmt/stats/truncated_unitary.py +40 -0
  341. physicskit/rmt/stats/unfolding.py +37 -0
  342. physicskit/rmt/stats/wachter.py +67 -0
  343. physicskit/rmt/tests/__init__.py +0 -0
  344. physicskit/rmt/tests/cache_utils.py +107 -0
  345. physicskit/rmt/tests/conftest.py +8 -0
  346. physicskit/rmt/tests/test_banded.py +86 -0
  347. physicskit/rmt/tests/test_base.py +29 -0
  348. physicskit/rmt/tests/test_bdg.py +133 -0
  349. physicskit/rmt/tests/test_characteristic_polynomial.py +50 -0
  350. physicskit/rmt/tests/test_chiral.py +273 -0
  351. physicskit/rmt/tests/test_circular.py +225 -0
  352. physicskit/rmt/tests/test_crossover.py +72 -0
  353. physicskit/rmt/tests/test_density.py +23 -0
  354. physicskit/rmt/tests/test_density_matrix.py +181 -0
  355. physicskit/rmt/tests/test_effective_hamiltonian.py +140 -0
  356. physicskit/rmt/tests/test_embedded.py +169 -0
  357. physicskit/rmt/tests/test_free_probability.py +81 -0
  358. physicskit/rmt/tests/test_gaussian_ensembles.py +22 -0
  359. physicskit/rmt/tests/test_gaussian_semicircle.py +127 -0
  360. physicskit/rmt/tests/test_ginibre_circular_law.py +131 -0
  361. physicskit/rmt/tests/test_girko.py +178 -0
  362. physicskit/rmt/tests/test_graph_laplacian.py +102 -0
  363. physicskit/rmt/tests/test_haar.py +118 -0
  364. physicskit/rmt/tests/test_jacobi_wachter.py +136 -0
  365. physicskit/rmt/tests/test_localization.py +240 -0
  366. physicskit/rmt/tests/test_poisson.py +149 -0
  367. physicskit/rmt/tests/test_polynomial.py +107 -0
  368. physicskit/rmt/tests/test_pt_symmetric.py +178 -0
  369. physicskit/rmt/tests/test_random_state.py +19 -0
  370. physicskit/rmt/tests/test_real_ginibre.py +112 -0
  371. physicskit/rmt/tests/test_rigidity_universality.py +167 -0
  372. physicskit/rmt/tests/test_single_ring.py +132 -0
  373. physicskit/rmt/tests/test_spacing_and_ratios.py +122 -0
  374. physicskit/rmt/tests/test_sparse.py +71 -0
  375. physicskit/rmt/tests/test_spectrum.py +27 -0
  376. physicskit/rmt/tests/test_syk.py +136 -0
  377. physicskit/rmt/tests/test_tracy_widom.py +113 -0
  378. physicskit/rmt/tests/test_tridiagonal.py +41 -0
  379. physicskit/rmt/tests/test_truncated_unitary.py +80 -0
  380. physicskit/rmt/tests/test_validation_base.py +25 -0
  381. physicskit/rmt/tests/test_validation_misc.py +67 -0
  382. physicskit/rmt/tests/test_wishart_marchenko_pastur.py +120 -0
  383. physicskit/rmt/utils/__init__.py +0 -0
  384. physicskit/rmt/utils/haar.py +128 -0
  385. physicskit/rmt/utils/random_state.py +24 -0
  386. physicskit/rmt/utils/tridiagonal.py +167 -0
  387. physicskit/rmt/validation/__init__.py +36 -0
  388. physicskit/rmt/validation/base.py +126 -0
  389. physicskit/rmt/validation/circular_law.py +80 -0
  390. physicskit/rmt/validation/marchenko_pastur.py +53 -0
  391. physicskit/rmt/validation/ratio_distribution.py +53 -0
  392. physicskit/rmt/validation/real_ginibre.py +60 -0
  393. physicskit/rmt/validation/sine_kernel.py +57 -0
  394. physicskit/rmt/validation/single_ring.py +68 -0
  395. physicskit/rmt/validation/tracy_widom.py +89 -0
  396. physicskit/rmt/validation/universality.py +100 -0
  397. physicskit/rmt/validation/wachter.py +52 -0
  398. physicskit/rmt/validation/wigner_semicircle.py +40 -0
  399. physicskit/rmt/validation/wigner_surmise.py +58 -0
  400. physicskit/semiclassical/__init__.py +94 -0
  401. physicskit/semiclassical/_compat.py +5 -0
  402. physicskit/semiclassical/core/__init__.py +41 -0
  403. physicskit/semiclassical/core/gutzwiller.py +215 -0
  404. physicskit/semiclassical/core/path_integral.py +594 -0
  405. physicskit/semiclassical/core/propagators.py +579 -0
  406. physicskit/semiclassical/core/wkb.py +308 -0
  407. physicskit/semiclassical/systems/__init__.py +13 -0
  408. physicskit/semiclassical/systems/scarring.py +278 -0
  409. physicskit/semiclassical/tests/__init__.py +0 -0
  410. physicskit/semiclassical/tests/test_gutzwiller.py +35 -0
  411. physicskit/semiclassical/tests/test_path_integral.py +194 -0
  412. physicskit/semiclassical/tests/test_propagators.py +82 -0
  413. physicskit/semiclassical/tests/test_scarring.py +43 -0
  414. physicskit/semiclassical/tests/test_visualizers.py +89 -0
  415. physicskit/semiclassical/tests/test_wkb.py +30 -0
  416. physicskit/semiclassical/visualizers/__init__.py +17 -0
  417. physicskit/semiclassical/visualizers/gutzwiller.py +55 -0
  418. physicskit/semiclassical/visualizers/path_integral.py +195 -0
  419. physicskit/semiclassical/visualizers/propagators.py +89 -0
  420. physicskit/semiclassical/visualizers/scarring.py +146 -0
  421. physicskit/semiclassical/visualizers/wkb.py +55 -0
  422. physicskit/statphys/__init__.py +80 -0
  423. physicskit/statphys/chapters/__init__.py +43 -0
  424. physicskit/statphys/chapters/ehrenfest_urn.py +112 -0
  425. physicskit/statphys/chapters/ising_lattice.py +431 -0
  426. physicskit/statphys/chapters/kpz_growth.py +129 -0
  427. physicskit/statphys/chapters/molecular_dynamics.py +258 -0
  428. physicskit/statphys/chapters/nonequilibrium_work.py +146 -0
  429. physicskit/statphys/chapters/percolation.py +305 -0
  430. physicskit/statphys/chapters/random_walk.py +142 -0
  431. physicskit/statphys/chapters/renormalization.py +148 -0
  432. physicskit/statphys/chapters/sandpile.py +109 -0
  433. physicskit/statphys/chapters/spin_glass.py +275 -0
  434. physicskit/statphys/core/__init__.py +10 -0
  435. physicskit/statphys/core/kpz_engine.py +53 -0
  436. physicskit/statphys/core/md_engine.py +157 -0
  437. physicskit/statphys/core/monte_carlo.py +462 -0
  438. physicskit/statphys/core/random_walk_engine.py +68 -0
  439. physicskit/statphys/core/sandpile_engine.py +52 -0
  440. physicskit/statphys/tests/__init__.py +0 -0
  441. physicskit/statphys/tests/test_dynamics.py +66 -0
  442. physicskit/statphys/tests/test_ehrenfest_urn.py +44 -0
  443. physicskit/statphys/tests/test_finite_size_scaling.py +62 -0
  444. physicskit/statphys/tests/test_interactive.py +33 -0
  445. physicskit/statphys/tests/test_ising.py +68 -0
  446. physicskit/statphys/tests/test_kpz.py +55 -0
  447. physicskit/statphys/tests/test_landau_theory.py +49 -0
  448. physicskit/statphys/tests/test_md_engine.py +31 -0
  449. physicskit/statphys/tests/test_molecular_dynamics.py +72 -0
  450. physicskit/statphys/tests/test_nonequilibrium_work.py +33 -0
  451. physicskit/statphys/tests/test_partition_function.py +26 -0
  452. physicskit/statphys/tests/test_percolation.py +116 -0
  453. physicskit/statphys/tests/test_potts_model.py +46 -0
  454. physicskit/statphys/tests/test_random_walk.py +50 -0
  455. physicskit/statphys/tests/test_renormalization.py +44 -0
  456. physicskit/statphys/tests/test_sandpile.py +44 -0
  457. physicskit/statphys/tests/test_spin_glass.py +73 -0
  458. physicskit/statphys/tests/test_thermodynamics.py +121 -0
  459. physicskit/statphys/tests/test_xy_model.py +45 -0
  460. physicskit/statphys/utils/__init__.py +1 -0
  461. physicskit/statphys/utils/dynamics.py +100 -0
  462. physicskit/statphys/utils/finite_size_scaling.py +171 -0
  463. physicskit/statphys/utils/landau_theory.py +151 -0
  464. physicskit/statphys/utils/partition_function.py +109 -0
  465. physicskit/statphys/utils/thermodynamics.py +356 -0
  466. physicskit/statphys/visualizers/__init__.py +87 -0
  467. physicskit/statphys/visualizers/interactive.py +161 -0
  468. physicskit/statphys/visualizers/jarzynski_render.py +44 -0
  469. physicskit/statphys/visualizers/kpz_render.py +65 -0
  470. physicskit/statphys/visualizers/lattice_render.py +212 -0
  471. physicskit/statphys/visualizers/particle_render.py +121 -0
  472. physicskit/statphys/visualizers/random_walk_render.py +106 -0
  473. physicskit/statphys/visualizers/rg_render.py +45 -0
  474. physicskit/statphys/visualizers/sandpile_render.py +65 -0
  475. physicskit/statphys/visualizers/spin_glass_render.py +40 -0
  476. physicskit/statphys/visualizers/urn_render.py +38 -0
  477. physicskit/statphys/visualizers/vortex_render.py +84 -0
  478. physicskit/tests/__init__.py +0 -0
  479. physicskit/tests/test_constants.py +38 -0
  480. physicskit-0.1.0.dist-info/METADATA +196 -0
  481. physicskit-0.1.0.dist-info/RECORD +484 -0
  482. physicskit-0.1.0.dist-info/WHEEL +5 -0
  483. physicskit-0.1.0.dist-info/licenses/LICENSE +21 -0
  484. physicskit-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,149 @@
1
+ """Neutron star structure: the Tolman-Oppenheimer-Volkoff equations.
2
+
3
+ A black hole is not the only fate of a massive star's core: below about
4
+ :math:`3 M_\\odot`, degenerate neutron pressure can halt gravitational
5
+ collapse entirely, leaving behind a neutron star -- matter compressed to
6
+ nuclear density and held up against its own gravity by quantum degeneracy
7
+ pressure. Oppenheimer and Volkoff (1939), building on Tolman's earlier work,
8
+ derived the relativistic generalization of the Newtonian hydrostatic
9
+ equilibrium equation for a self-gravitating fluid sphere. Unlike the
10
+ Newtonian case, the TOV equation predicts a maximum possible neutron star
11
+ mass: add too much matter and pressure alone can no longer resist collapse,
12
+ regardless of the equation of state -- the star must become a black hole.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import numpy as np
18
+ from scipy.integrate import solve_ivp
19
+
20
+ __all__ = ["NeutronStar"]
21
+
22
+
23
+ class NeutronStar:
24
+ """A neutron star modeled with a polytropic equation of state, solved via the TOV equations.
25
+
26
+ The equation of state is the polytrope :math:`P = K \\rho_0^\\Gamma`
27
+ relating pressure to rest-mass density; the total energy density
28
+ (rest mass plus internal energy) used as the gravitational source is
29
+ :math:`\\varepsilon = \\rho_0 + P/(\\Gamma - 1)`. All quantities are in
30
+ geometrized units; ``K`` and ``Gamma`` are illustrative "toy" parameters
31
+ unless calibrated to a specific realistic equation of state.
32
+
33
+ Parameters
34
+ ----------
35
+ K : float, default=100.0
36
+ Polytropic constant.
37
+ Gamma : float, default=2.0
38
+ Polytropic index (:math:`\\Gamma = 2` is a common toy choice
39
+ loosely representative of nuclear matter).
40
+ """
41
+
42
+ def __init__(self, K=100.0, Gamma=2.0):
43
+ self.K = K
44
+ self.Gamma = Gamma
45
+
46
+ def energy_density(self, pressure):
47
+ """Total energy density :math:`\\varepsilon(P) = (P/K)^{1/\\Gamma} + P/(\\Gamma-1)`.
48
+
49
+ Parameters
50
+ ----------
51
+ pressure : float or array_like
52
+ Pressure.
53
+
54
+ Returns
55
+ -------
56
+ float or ndarray
57
+ """
58
+ pressure = np.asarray(pressure, dtype=np.float64)
59
+ rest_mass_density = (pressure / self.K) ** (1.0 / self.Gamma)
60
+ return rest_mass_density + pressure / (self.Gamma - 1.0)
61
+
62
+ def _tov_rhs(self, r, y):
63
+ m, P = y
64
+ if P <= 0.0:
65
+ return [0.0, 0.0]
66
+ eps = self.energy_density(P)
67
+ dm_dr = 4.0 * np.pi * r**2 * eps
68
+ dP_dr = -(eps + P) * (m + 4.0 * np.pi * r**3 * P) / (r * (r - 2.0 * m))
69
+ return [dm_dr, dP_dr]
70
+
71
+ def solve(self, central_density, r_max=50.0, r_start=1.0e-6):
72
+ """Integrate the TOV equations outward from the center to the stellar surface.
73
+
74
+ Parameters
75
+ ----------
76
+ central_density : float
77
+ Central rest-mass density :math:`\\rho_0(0)`.
78
+ r_max : float, default=50.0
79
+ Outer integration bound (should exceed any physically expected
80
+ stellar radius for the given equation of state).
81
+ r_start : float, default=1e-6
82
+ Small starting radius (avoids the coordinate singularity at
83
+ exactly :math:`r=0`).
84
+
85
+ Returns
86
+ -------
87
+ mass : float
88
+ Total gravitational mass :math:`M`, read off where the pressure
89
+ drops to (numerically) zero -- the stellar surface.
90
+ radius : float
91
+ Stellar radius :math:`R`.
92
+ solution : scipy.integrate.OdeSolution
93
+ The full ``solve_ivp`` result, for inspecting the interior
94
+ profile.
95
+
96
+ Examples
97
+ --------
98
+ >>> star = NeutronStar(K=100.0, Gamma=2.0)
99
+ >>> M, R, sol = star.solve(central_density=1.28e-3)
100
+ >>> bool(M > 0.0 and R > 0.0)
101
+ True
102
+ """
103
+ pressure_central = self.K * central_density**self.Gamma
104
+
105
+ def surface_event(r, y):
106
+ return y[1] - 1.0e-10 * pressure_central
107
+
108
+ surface_event.terminal = True
109
+ surface_event.direction = -1
110
+
111
+ solution = solve_ivp(
112
+ self._tov_rhs,
113
+ [r_start, r_max],
114
+ [0.0, pressure_central],
115
+ events=surface_event,
116
+ dense_output=True,
117
+ max_step=0.01,
118
+ rtol=1.0e-8,
119
+ atol=1.0e-14,
120
+ )
121
+ radius = solution.t[-1]
122
+ mass = solution.y[0, -1]
123
+ return mass, radius, solution
124
+
125
+ def mass_radius_curve(self, central_densities):
126
+ """Trace the mass-radius relation over a range of central densities.
127
+
128
+ The existence of a maximum mass (a turning point in :math:`M` as a
129
+ function of central density, beyond which increasing the central
130
+ density *decreases* the stable mass) is the TOV equation's central
131
+ physical prediction.
132
+
133
+ Parameters
134
+ ----------
135
+ central_densities : array_like
136
+ Central densities to sample.
137
+
138
+ Returns
139
+ -------
140
+ masses : ndarray
141
+ radii : ndarray
142
+ """
143
+ masses = np.empty(len(central_densities))
144
+ radii = np.empty(len(central_densities))
145
+ for i, rho_c in enumerate(central_densities):
146
+ M, R, _ = self.solve(rho_c)
147
+ masses[i] = M
148
+ radii[i] = R
149
+ return masses, radii
@@ -0,0 +1,412 @@
1
+ """The Schwarzschild black hole: orbits, precession, light bending, and the photon sphere.
2
+
3
+ The Schwarzschild solution -- the first exact solution to Einstein's field
4
+ equations, found by Karl Schwarzschild in 1916 while serving on the Russian
5
+ front, just weeks after Einstein published General Relativity -- describes
6
+ the spacetime around any non-rotating, uncharged spherical mass. It predicts
7
+ three of GR's classic observational triumphs: the anomalous perihelion
8
+ precession of Mercury, the bending of starlight grazing the Sun (confirmed
9
+ by Eddington's 1919 eclipse expedition), and the Shapiro time delay of radar
10
+ signals passing near the Sun.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import numpy as np
16
+
17
+ from physicskit.relativity.core.geodesics import integrate_schwarzschild_geodesic
18
+
19
+ __all__ = ["SchwarzschildBlackHole"]
20
+
21
+
22
+ class SchwarzschildBlackHole:
23
+ """A non-rotating black hole (or any spherical mass) of mass ``M``, in geometrized units.
24
+
25
+ Parameters
26
+ ----------
27
+ M : float, default=1.0
28
+ Mass, in geometrized length units (:math:`GM/c^2`). Use
29
+ :func:`physicskit.relativity.utils.constants.solar_masses_to_geometrized`
30
+ to convert from a physical mass in solar masses.
31
+ """
32
+
33
+ def __init__(self, M=1.0):
34
+ self.M = M
35
+
36
+ @property
37
+ def horizon_radius(self):
38
+ """Event horizon radius, :math:`r_s = 2M`."""
39
+ return 2.0 * self.M
40
+
41
+ @property
42
+ def photon_sphere_radius(self):
43
+ """Photon sphere radius, :math:`r_{ph} = 3M`."""
44
+ return 3.0 * self.M
45
+
46
+ @property
47
+ def isco_radius(self):
48
+ """Innermost stable circular orbit radius, :math:`r_{\\text{ISCO}} = 6M`."""
49
+ return 6.0 * self.M
50
+
51
+ @property
52
+ def critical_impact_parameter(self):
53
+ """Critical photon impact parameter, :math:`b_c = 3\\sqrt{3}\\,M`."""
54
+ return 3.0 * np.sqrt(3.0) * self.M
55
+
56
+ def circular_orbit_angular_velocity(self, r):
57
+ """Coordinate angular velocity :math:`\\Omega = d\\phi/dt` of a circular timelike orbit.
58
+
59
+ Exactly Keplerian in Schwarzschild coordinates:
60
+ :math:`\\Omega = \\sqrt{M/r^3}`.
61
+
62
+ Parameters
63
+ ----------
64
+ r : float
65
+ Orbital radius.
66
+
67
+ Returns
68
+ -------
69
+ float
70
+ """
71
+ return np.sqrt(self.M / r**3)
72
+
73
+ def circular_orbit_initial_state(self, r0):
74
+ """Initial 8-component state for a circular, equatorial, timelike orbit at radius ``r0``.
75
+
76
+ Parameters
77
+ ----------
78
+ r0 : float
79
+ Orbital radius. Should exceed :attr:`isco_radius` for the orbit
80
+ to be stable.
81
+
82
+ Returns
83
+ -------
84
+ ndarray of shape (8,)
85
+ :math:`(t, r, \\theta, \\phi, u^t, u^r, u^\\theta, u^\\phi)` at
86
+ :math:`\\tau = 0`.
87
+ """
88
+ M = self.M
89
+ f = 1.0 - 2.0 * M / r0
90
+ Omega = self.circular_orbit_angular_velocity(r0)
91
+ ut = 1.0 / np.sqrt(f - r0**2 * Omega**2)
92
+ uphi = Omega * ut
93
+ return np.array([0.0, r0, np.pi / 2.0, 0.0, ut, 0.0, 0.0, uphi])
94
+
95
+ def eccentric_orbit_initial_state(self, r0, eccentricity_boost=0.0):
96
+ """Initial state for a bound, generally eccentric equatorial timelike orbit.
97
+
98
+ Starts at radius ``r0`` (taken as the initial apoapsis) with purely
99
+ tangential velocity reduced below the circular value by
100
+ ``eccentricity_boost``, producing a radially oscillating (rosette,
101
+ precessing) orbit for ``eccentricity_boost > 0``.
102
+
103
+ Parameters
104
+ ----------
105
+ r0 : float
106
+ Starting radius (apoapsis).
107
+ eccentricity_boost : float, default=0.0
108
+ Fractional reduction of the tangential velocity relative to the
109
+ circular orbit at ``r0``; ``0`` gives a circular orbit, larger
110
+ values give more eccentric orbits.
111
+
112
+ Returns
113
+ -------
114
+ ndarray of shape (8,)
115
+ Initial state, as in :meth:`circular_orbit_initial_state`.
116
+ """
117
+ M = self.M
118
+ f = 1.0 - 2.0 * M / r0
119
+ Omega = self.circular_orbit_angular_velocity(r0) * (1.0 - eccentricity_boost)
120
+ ut = 1.0 / np.sqrt(f - r0**2 * Omega**2)
121
+ uphi = Omega * ut
122
+ return np.array([0.0, r0, np.pi / 2.0, 0.0, ut, 0.0, 0.0, uphi])
123
+
124
+ def null_geodesic_initial_state(self, r0, impact_parameter, ingoing=True):
125
+ """Initial state for an equatorial null (photon) geodesic with a given impact parameter.
126
+
127
+ Parameters
128
+ ----------
129
+ r0 : float
130
+ Starting radius.
131
+ impact_parameter : float
132
+ Impact parameter :math:`b = L/E`.
133
+ ingoing : bool, default=True
134
+ Whether the photon starts moving toward decreasing :math:`r`.
135
+
136
+ Returns
137
+ -------
138
+ ndarray of shape (8,)
139
+ Initial state with :math:`E = 1` (an affine-parameter
140
+ normalization choice; only the ratio :math:`b` is physical).
141
+ """
142
+ M = self.M
143
+ f = 1.0 - 2.0 * M / r0
144
+ E = 1.0
145
+ L = impact_parameter * E
146
+ ut = E / f
147
+ uphi = L / r0**2
148
+ radicand = E**2 - f * L**2 / r0**2
149
+ ur = -np.sqrt(max(radicand, 0.0)) if ingoing else np.sqrt(max(radicand, 0.0))
150
+ return np.array([0.0, r0, np.pi / 2.0, 0.0, ut, ur, 0.0, uphi])
151
+
152
+ def integrate_geodesic(self, y0, dtau, n_steps):
153
+ """Integrate a geodesic from initial state ``y0`` via fixed-step RK4.
154
+
155
+ Parameters
156
+ ----------
157
+ y0 : ndarray of shape (8,)
158
+ Initial state, e.g. from :meth:`circular_orbit_initial_state`,
159
+ :meth:`eccentric_orbit_initial_state`, or
160
+ :meth:`null_geodesic_initial_state`.
161
+ dtau : float
162
+ Affine-parameter (or proper-time) step size.
163
+ n_steps : int
164
+ Maximum number of steps.
165
+
166
+ Returns
167
+ -------
168
+ dict of str -> ndarray
169
+ Keys ``"t"``, ``"r"``, ``"theta"``, ``"phi"``, ``"ut"``,
170
+ ``"ur"``, ``"utheta"``, ``"uphi"``, each a 1D array over the
171
+ (trimmed) trajectory, plus ``"energy"`` and
172
+ ``"angular_momentum"``: the conserved
173
+ :math:`E = -u_t = (1-2M/r) u^t` and
174
+ :math:`L = u_\\phi = r^2 \\sin^2\\theta \\, u^\\phi` evaluated
175
+ at every step (constant along an exact geodesic; their spread
176
+ measures integration error).
177
+
178
+ Examples
179
+ --------
180
+ >>> bh = SchwarzschildBlackHole(M=1.0)
181
+ >>> y0 = bh.circular_orbit_initial_state(r0=10.0)
182
+ >>> traj = bh.integrate_geodesic(y0, dtau=0.01, n_steps=500)
183
+ >>> float(np.std(traj["energy"])) < 1e-6
184
+ True
185
+ """
186
+ trajectory, n_valid = integrate_schwarzschild_geodesic(y0, self.M, dtau, n_steps)
187
+ trajectory = trajectory[: n_valid + 1]
188
+ t, r, theta, phi, ut, ur, uth, uphi = trajectory.T
189
+ f = 1.0 - 2.0 * self.M / r
190
+ energy = f * ut
191
+ ang_mom = r**2 * np.sin(theta) ** 2 * uphi
192
+ return {
193
+ "t": t,
194
+ "r": r,
195
+ "theta": theta,
196
+ "phi": phi,
197
+ "ut": ut,
198
+ "ur": ur,
199
+ "utheta": uth,
200
+ "uphi": uphi,
201
+ "energy": energy,
202
+ "angular_momentum": ang_mom,
203
+ }
204
+
205
+ def perihelion_precession(self, trajectory):
206
+ """Measure the apsidal (perihelion) precession per orbit from an integrated trajectory.
207
+
208
+ Locates successive periapsis passages (local minima of :math:`r(\\lambda)`)
209
+ and returns the excess azimuthal angle swept between them beyond
210
+ :math:`2\\pi`.
211
+
212
+ Parameters
213
+ ----------
214
+ trajectory : dict of str -> ndarray
215
+ Output of :meth:`integrate_geodesic` for an eccentric orbit.
216
+
217
+ Returns
218
+ -------
219
+ ndarray
220
+ Precession (in radians) measured between each pair of
221
+ consecutive periapsis passages found in the trajectory.
222
+ """
223
+ r = trajectory["r"]
224
+ phi = trajectory["phi"]
225
+ is_min = (r[1:-1] < r[:-2]) & (r[1:-1] < r[2:])
226
+ idx = np.nonzero(is_min)[0] + 1
227
+ if len(idx) < 2:
228
+ return np.array([])
229
+ phi_at_peri = phi[idx]
230
+ delta_phi = np.diff(phi_at_peri)
231
+ return delta_phi - 2.0 * np.pi
232
+
233
+ def weak_field_precession_per_orbit(self, semi_major_axis, eccentricity):
234
+ """Leading-order post-Newtonian perihelion precession per orbit.
235
+
236
+ .. math::
237
+
238
+ \\Delta\\phi = \\frac{6\\pi M}{a (1 - e^2)}
239
+
240
+ Parameters
241
+ ----------
242
+ semi_major_axis : float
243
+ Orbital semi-major axis :math:`a`.
244
+ eccentricity : float
245
+ Orbital eccentricity :math:`e \\in [0, 1)`.
246
+
247
+ Returns
248
+ -------
249
+ float
250
+ Precession per orbit, in radians.
251
+ """
252
+ return 6.0 * np.pi * self.M / (semi_major_axis * (1.0 - eccentricity**2))
253
+
254
+ def light_deflection_angle(self, impact_parameter):
255
+ """Leading-order light deflection angle for a photon passing at a given impact parameter.
256
+
257
+ .. math::
258
+
259
+ \\delta\\phi \\approx \\frac{4M}{b}
260
+
261
+ The weak-field (:math:`b \\gg M`) limit of gravitational light
262
+ bending; famously confirmed for starlight grazing the Sun during
263
+ the 1919 solar eclipse.
264
+
265
+ Parameters
266
+ ----------
267
+ impact_parameter : float
268
+ Impact parameter :math:`b`.
269
+
270
+ Returns
271
+ -------
272
+ float
273
+ Deflection angle, in radians.
274
+ """
275
+ return 4.0 * self.M / impact_parameter
276
+
277
+ def shapiro_delay(self, r1, r2, impact_parameter):
278
+ """Shapiro (gravitational) time delay for light passing between two radii.
279
+
280
+ .. math::
281
+
282
+ \\Delta t = 2M \\ln\\left[
283
+ \\frac{\\left(r_1 + \\sqrt{r_1^2 - b^2}\\right)
284
+ \\left(r_2 + \\sqrt{r_2^2 - b^2}\\right)}{b^2}
285
+ \\right]
286
+
287
+ The excess light-travel time (beyond flat-spacetime expectations)
288
+ caused by spacetime curvature, first measured via radar ranging to
289
+ Venus and the Viking Mars landers.
290
+
291
+ Parameters
292
+ ----------
293
+ r1, r2 : float
294
+ Radial coordinates of the two endpoints (e.g. Earth and a
295
+ reflecting planet or spacecraft).
296
+ impact_parameter : float
297
+ Closest approach distance of the light path to the mass.
298
+
299
+ Returns
300
+ -------
301
+ float
302
+ Time delay, in geometrized time units (length; divide by
303
+ :data:`physicskit.relativity.utils.constants.C_SI` for seconds).
304
+ """
305
+ b = impact_parameter
306
+ term1 = r1 + np.sqrt(r1**2 - b**2)
307
+ term2 = r2 + np.sqrt(r2**2 - b**2)
308
+ return 2.0 * self.M * np.log(term1 * term2 / b**2)
309
+
310
+ def effective_potential(self, r, L):
311
+ """Effective potential for equatorial timelike orbits, :math:`V_{\\text{eff}}(r) = (1-2M/r)(1+L^2/r^2)`.
312
+
313
+ Radial motion obeys :math:`(dr/d\\tau)^2 = E^2 - V_{\\text{eff}}(r)`.
314
+
315
+ Parameters
316
+ ----------
317
+ r : float or array_like
318
+ Radial coordinate(s).
319
+ L : float
320
+ Specific angular momentum.
321
+
322
+ Returns
323
+ -------
324
+ float or ndarray
325
+ """
326
+ r = np.asarray(r, dtype=np.float64)
327
+ return (1.0 - 2.0 * self.M / r) * (1.0 + L**2 / r**2)
328
+
329
+ def disk_redshift_factor(self, r, impact_parameter):
330
+ """Combined gravitational + Doppler redshift factor for a circularly orbiting disk emitter.
331
+
332
+ For a photon with impact parameter :math:`b = L_{\\text{ph}}/E_{\\text{ph}}`
333
+ received from gas in a circular Keplerian orbit at radius :math:`r`,
334
+ the ratio of observed to emitted photon energy is
335
+
336
+ .. math::
337
+
338
+ g = \\frac{E_{\\text{obs}}}{E_{\\text{emit}}}
339
+ = \\frac{1}{u^t(r)\\left[1 - b\\,\\Omega(r)\\right]}
340
+
341
+ where :math:`u^t(r) = 1/\\sqrt{f(r) - r^2\\Omega(r)^2}` is the
342
+ emitter's time dilation factor and :math:`\\Omega(r) =
343
+ \\sqrt{M/r^3}` its orbital angular velocity (see
344
+ :meth:`circular_orbit_angular_velocity`). :math:`g < 1` is redshifted
345
+ (gravity, or the far/receding side of the disk); :math:`g > 1` is
346
+ blueshifted (the near/approaching side, when Doppler beaming wins).
347
+
348
+ Parameters
349
+ ----------
350
+ r : float or array_like
351
+ Disk radius at emission.
352
+ impact_parameter : float or array_like
353
+ The received photon's impact parameter :math:`b`.
354
+
355
+ Returns
356
+ -------
357
+ float or ndarray
358
+ The redshift factor :math:`g`.
359
+ """
360
+ r = np.asarray(r, dtype=np.float64)
361
+ b = np.asarray(impact_parameter, dtype=np.float64)
362
+ f = 1.0 - 2.0 * self.M / r
363
+ Omega = self.circular_orbit_angular_velocity(r)
364
+ u_t = 1.0 / np.sqrt(f - r**2 * Omega**2)
365
+ return 1.0 / (u_t * (1.0 - b * Omega))
366
+
367
+ def tidal_acceleration(self, r, proper_separation):
368
+ """Tidal (geodesic deviation) acceleration on a radially infalling object.
369
+
370
+ In the local orthonormal frame of a freely-falling observer, the
371
+ Riemann tensor's nonzero components give a stretching acceleration
372
+ along the radial direction and an equal compression along each
373
+ transverse direction:
374
+
375
+ .. math::
376
+
377
+ a_{\\text{radial}} = \\frac{2M}{r^3}\\,\\ell, \\qquad
378
+ a_{\\text{transverse}} = -\\frac{M}{r^3}\\,\\ell
379
+
380
+ for two points separated by a small proper length :math:`\\ell`.
381
+ This is "spaghettification": an object falling feet-first is
382
+ stretched head-to-toe and squeezed side-to-side, with both effects
383
+ growing as :math:`1/r^3` and formally diverging at the singularity.
384
+
385
+ Parameters
386
+ ----------
387
+ r : float or array_like
388
+ Radial coordinate.
389
+ proper_separation : float
390
+ Proper length between the two points being torn apart (e.g. the
391
+ height of an infalling astronaut).
392
+
393
+ Returns
394
+ -------
395
+ radial : float or ndarray
396
+ Stretching acceleration along the radial direction (positive:
397
+ pulls the two points apart).
398
+ transverse : float or ndarray
399
+ Compressing acceleration along each transverse direction
400
+ (negative: pushes together).
401
+
402
+ Examples
403
+ --------
404
+ >>> bh = SchwarzschildBlackHole(M=1.0)
405
+ >>> radial, transverse = bh.tidal_acceleration(r=6.0, proper_separation=1.0)
406
+ >>> bool(radial > 0.0 and transverse < 0.0)
407
+ True
408
+ """
409
+ r = np.asarray(r, dtype=np.float64)
410
+ radial = 2.0 * self.M / r**3 * proper_separation
411
+ transverse = -self.M / r**3 * proper_separation
412
+ return radial, transverse
@@ -0,0 +1,133 @@
1
+ """Relativistic clock corrections: why GPS needs General Relativity every day.
2
+
3
+ A GPS satellite clock experiences two competing relativistic effects
4
+ relative to a clock on the ground: it runs *faster* because it sits higher
5
+ in Earth's gravitational potential (gravitational blueshift), and *slower*
6
+ because it moves at orbital speed (special-relativistic time dilation). For
7
+ the GPS constellation's medium-Earth orbit, the gravitational effect wins by
8
+ a wide margin, and the net result -- about 38 microseconds per day -- is
9
+ large enough that, left uncorrected, GPS position errors would accumulate at
10
+ roughly 10 km per day. Every GPS satellite clock is deliberately built to
11
+ tick slightly slow on the ground so that, once in orbit, it keeps pace with
12
+ ground clocks -- General Relativity engineered directly into consumer
13
+ electronics.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import numpy as np
19
+
20
+ from physicskit.relativity.utils.constants import C_SI, G_SI
21
+
22
+ __all__ = [
23
+ "EARTH_MASS_KG",
24
+ "EARTH_RADIUS_M",
25
+ "EARTH_SIDEREAL_DAY_S",
26
+ "GPS_ORBITAL_RADIUS_M",
27
+ "clock_rate_factor",
28
+ "earth_mass_geometrized",
29
+ "gps_relativistic_offset_per_day",
30
+ ]
31
+
32
+ #: Earth's mass, in kg.
33
+ EARTH_MASS_KG = 5.9722e24
34
+ #: Earth's mean equatorial radius, in meters.
35
+ EARTH_RADIUS_M = 6.371e6
36
+ #: Earth's sidereal rotation period, in seconds.
37
+ EARTH_SIDEREAL_DAY_S = 86164.0905
38
+ #: Typical GPS satellite orbital semi-major axis, in meters (~20,200 km altitude).
39
+ GPS_ORBITAL_RADIUS_M = 2.6560e7
40
+
41
+
42
+ def earth_mass_geometrized():
43
+ """Earth's mass in geometrized length units, :math:`GM_\\oplus/c^2`.
44
+
45
+ Returns
46
+ -------
47
+ float
48
+ """
49
+ return G_SI * EARTH_MASS_KG / C_SI**2
50
+
51
+
52
+ def clock_rate_factor(r, angular_velocity_si, M=None):
53
+ """Proper-to-coordinate time rate :math:`d\\tau/dt` for a clock at radius ``r`` rotating at a given rate.
54
+
55
+ .. math::
56
+
57
+ \\frac{d\\tau}{dt} = \\sqrt{\\left(1 - \\frac{2M}{r}\\right) - r^2 \\Omega^2}
58
+
59
+ combining gravitational time dilation and the special-relativistic time
60
+ dilation of the clock's rotational motion in one formula (this reduces
61
+ to the familiar circular-orbit result :math:`\\sqrt{1-3M/r}` when
62
+ :math:`\\Omega` is the Keplerian orbital angular velocity, and to pure
63
+ gravitational redshift :math:`\\sqrt{1-2M/r}` when :math:`\\Omega = 0`).
64
+
65
+ Parameters
66
+ ----------
67
+ r : float
68
+ Radial coordinate, in meters.
69
+ angular_velocity_si : float
70
+ The clock's angular velocity, in rad/s (SI).
71
+ M : float, optional
72
+ Central mass, in geometrized length units. Defaults to
73
+ :func:`earth_mass_geometrized`.
74
+
75
+ Returns
76
+ -------
77
+ float
78
+ The dimensionless rate :math:`d\\tau/dt`.
79
+ """
80
+ if M is None:
81
+ M = earth_mass_geometrized()
82
+ omega_geometrized = angular_velocity_si / C_SI # rad/s -> rad per geometrized length unit
83
+ f = 1.0 - 2.0 * M / r
84
+ return np.sqrt(f - r**2 * omega_geometrized**2)
85
+
86
+
87
+ def gps_relativistic_offset_per_day(r_satellite=None, r_ground=None, M=None):
88
+ """Net relativistic clock rate offset of a GPS satellite relative to the ground, in microseconds/day.
89
+
90
+ The satellite is treated as free-falling in a circular Keplerian orbit
91
+ (angular velocity :math:`\\Omega = \\sqrt{M/r^3}`); the ground clock is
92
+ treated as co-rotating with Earth at its sidereal rate. A positive
93
+ result means the satellite clock runs fast relative to the ground.
94
+
95
+ Parameters
96
+ ----------
97
+ r_satellite : float, optional
98
+ Satellite orbital radius, in meters. Defaults to
99
+ :data:`GPS_ORBITAL_RADIUS_M`.
100
+ r_ground : float, optional
101
+ Ground station radius, in meters. Defaults to
102
+ :data:`EARTH_RADIUS_M`.
103
+ M : float, optional
104
+ Earth's mass, in geometrized length units. Defaults to
105
+ :func:`earth_mass_geometrized`.
106
+
107
+ Returns
108
+ -------
109
+ float
110
+ Accumulated time offset, in microseconds per day (positive: the
111
+ satellite clock runs fast).
112
+
113
+ Examples
114
+ --------
115
+ >>> offset = gps_relativistic_offset_per_day()
116
+ >>> bool(30.0 < offset < 45.0) # the well-known ~38 microseconds/day GPS correction
117
+ True
118
+ """
119
+ if r_satellite is None:
120
+ r_satellite = GPS_ORBITAL_RADIUS_M
121
+ if r_ground is None:
122
+ r_ground = EARTH_RADIUS_M
123
+ if M is None:
124
+ M = earth_mass_geometrized()
125
+
126
+ omega_satellite_si = np.sqrt(M / r_satellite**3) * C_SI # geometrized Omega -> rad/s
127
+ omega_ground_si = 2.0 * np.pi / EARTH_SIDEREAL_DAY_S
128
+
129
+ rate_satellite = clock_rate_factor(r_satellite, omega_satellite_si, M=M)
130
+ rate_ground = clock_rate_factor(r_ground, omega_ground_si, M=M)
131
+
132
+ fractional_rate_diff = rate_satellite - rate_ground
133
+ return fractional_rate_diff * 86400.0 * 1.0e6