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,241 @@
1
+ """A Numba-accelerated backward photon ray-tracer for Schwarzschild gravitational lensing.
2
+
3
+ Rather than integrating the full 4D null geodesic equation per pixel, this
4
+ module exploits two facts about a spherically symmetric spacetime: every
5
+ photon trajectory is confined to a single plane through the black hole
6
+ (by symmetry), and within that plane, the trajectory obeys the classic
7
+ Binet-style orbit equation in :math:`u = 1/r`:
8
+
9
+ .. math::
10
+
11
+ \\frac{d^2 u}{d\\varphi^2} = -u + 3Mu^2
12
+
13
+ This is numerically robust (no turning-point sign ambiguities to handle,
14
+ unlike integrating :math:`dr/d\\lambda` directly) and fast: it reduces each
15
+ pixel's ray to a 2-variable ODE stepped in the orbital-plane angle
16
+ :math:`\\varphi`. To render an accretion disk, each step's in-plane
17
+ position is reconstructed in the observer's fixed 3D frame (using the
18
+ per-pixel orbital-plane basis fixed by its impact parameter geometry) and
19
+ checked against the disk's equatorial plane and radial extent.
20
+
21
+ Every camera ray is treated as parallel to the line of sight (an
22
+ orthographic projection), the standard and excellent approximation for an
23
+ observer at :math:`r_0 \\gg M` with a modest field of view.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import numpy as np
29
+ from numba import njit
30
+
31
+ __all__ = [
32
+ "OUTCOME_CAPTURED",
33
+ "OUTCOME_DISK",
34
+ "OUTCOME_ESCAPED",
35
+ "camera_basis",
36
+ "render_shadow_image",
37
+ ]
38
+
39
+ #: Pixel outcome code: the photon escaped to infinity without hitting the disk.
40
+ OUTCOME_ESCAPED = 0
41
+ #: Pixel outcome code: the photon crossed the event horizon.
42
+ OUTCOME_CAPTURED = 1
43
+ #: Pixel outcome code: the photon's orbit could not be resolved within the step
44
+ #: budget (deep near-critical winding); treated as captured for imaging purposes.
45
+ OUTCOME_UNRESOLVED = 2
46
+ #: Pixel outcome code: the photon crossed the accretion disk.
47
+ OUTCOME_DISK = 3
48
+
49
+
50
+ def camera_basis(inclination):
51
+ """Build an orthonormal camera frame looking at the origin from a given inclination.
52
+
53
+ The black hole sits at the origin with its spin/disk axis along
54
+ :math:`+Z`. The observer is placed in the :math:`X`-:math:`Z` plane at
55
+ polar angle ``inclination`` from the :math:`+Z` axis (``0`` = face-on,
56
+ looking down the pole; ``pi/2`` = edge-on, in the disk plane).
57
+
58
+ Parameters
59
+ ----------
60
+ inclination : float
61
+ Observer inclination, in radians, measured from the disk's normal axis.
62
+
63
+ Returns
64
+ -------
65
+ view_dir : ndarray of shape (3,)
66
+ Unit vector from the observer toward the origin.
67
+ right : ndarray of shape (3,)
68
+ Unit vector spanning the camera's horizontal screen axis.
69
+ up : ndarray of shape (3,)
70
+ Unit vector spanning the camera's vertical screen axis.
71
+ """
72
+ n_obs = np.array([np.sin(inclination), 0.0, np.cos(inclination)])
73
+ view_dir = -n_obs
74
+ up_hint = np.array([0.0, 0.0, 1.0]) if abs(inclination) > 1e-8 else np.array([1.0, 0.0, 0.0])
75
+ right = np.cross(view_dir, up_hint)
76
+ right = right / np.linalg.norm(right)
77
+ up = np.cross(right, view_dir)
78
+ up = up / np.linalg.norm(up)
79
+ return view_dir, right, up
80
+
81
+
82
+ @njit(cache=True)
83
+ def _trace_pixel(
84
+ alpha,
85
+ beta,
86
+ obs_pos,
87
+ right,
88
+ up,
89
+ view_dir,
90
+ M,
91
+ r_disk_inner,
92
+ r_disk_outer,
93
+ dphi,
94
+ n_steps,
95
+ r_horizon_factor,
96
+ ):
97
+ """Trace one camera ray; returns (outcome_code, hit_radius)."""
98
+ ray_origin = obs_pos + alpha * right + beta * up
99
+ r0 = np.sqrt(ray_origin[0] ** 2 + ray_origin[1] ** 2 + ray_origin[2] ** 2)
100
+
101
+ cross_ov = np.cross(ray_origin, view_dir)
102
+ b = np.sqrt(cross_ov[0] ** 2 + cross_ov[1] ** 2 + cross_ov[2] ** 2)
103
+
104
+ if b < 1.0e-8:
105
+ return OUTCOME_CAPTURED, -1.0
106
+
107
+ e1 = ray_origin / r0
108
+ proj = view_dir - np.dot(view_dir, e1) * e1
109
+ proj_norm = np.sqrt(proj[0] ** 2 + proj[1] ** 2 + proj[2] ** 2)
110
+ e2 = proj / proj_norm
111
+
112
+ u = 1.0 / r0
113
+ val = 1.0 / (b * b) - u * u + 2.0 * M * u**3
114
+ val = max(val, 0.0)
115
+ dudphi = np.sqrt(val)
116
+
117
+ u_crit = 1.0 / (r_horizon_factor * 2.0 * M)
118
+ phi = 0.0
119
+ pos0 = (1.0 / u) * (np.cos(phi) * e1 + np.sin(phi) * e2)
120
+ prev_z = pos0[2]
121
+
122
+ outcome = OUTCOME_UNRESOLVED
123
+ hit_r = -1.0
124
+
125
+ for i in range(n_steps):
126
+ if u >= u_crit:
127
+ outcome = OUTCOME_CAPTURED
128
+ break
129
+ if u <= 0.0 and i > 0:
130
+ outcome = OUTCOME_ESCAPED
131
+ break
132
+
133
+ k1u = dudphi
134
+ k1v = -u + 3.0 * M * u * u
135
+ u2 = u + 0.5 * dphi * k1u
136
+ v2 = dudphi + 0.5 * dphi * k1v
137
+ k2u = v2
138
+ k2v = -u2 + 3.0 * M * u2 * u2
139
+ u3 = u + 0.5 * dphi * k2u
140
+ v3 = dudphi + 0.5 * dphi * k2v
141
+ k3u = v3
142
+ k3v = -u3 + 3.0 * M * u3 * u3
143
+ u4 = u + dphi * k3u
144
+ v4 = dudphi + dphi * k3v
145
+ k4u = v4
146
+ k4v = -u4 + 3.0 * M * u4 * u4
147
+
148
+ u = u + (dphi / 6.0) * (k1u + 2.0 * k2u + 2.0 * k3u + k4u)
149
+ dudphi = dudphi + (dphi / 6.0) * (k1v + 2.0 * k2v + 2.0 * k3v + k4v)
150
+ phi = phi + dphi
151
+
152
+ if u > 1.0e-10:
153
+ r = 1.0 / u
154
+ pos = r * (np.cos(phi) * e1 + np.sin(phi) * e2)
155
+ z = pos[2]
156
+ if z * prev_z < 0.0 and r_disk_inner <= r <= r_disk_outer:
157
+ hit_r = r
158
+ outcome = OUTCOME_DISK
159
+ break
160
+ prev_z = z
161
+
162
+ return outcome, hit_r
163
+
164
+
165
+ @njit(cache=True)
166
+ def render_shadow_image(
167
+ ny,
168
+ nx,
169
+ screen_half_width,
170
+ screen_half_height,
171
+ obs_pos,
172
+ right,
173
+ up,
174
+ view_dir,
175
+ M,
176
+ r_disk_inner,
177
+ r_disk_outer,
178
+ dphi=0.01,
179
+ n_steps=3000,
180
+ r_horizon_factor=1.001,
181
+ ):
182
+ """Render a black hole shadow / accretion disk image by backward ray-tracing.
183
+
184
+ Parameters
185
+ ----------
186
+ ny, nx : int
187
+ Image height and width, in pixels.
188
+ screen_half_width, screen_half_height : float
189
+ Half-extent of the camera screen, in geometrized length units
190
+ (impact-parameter space); e.g. ``screen_half_width=15*M`` frames a
191
+ region a few times larger than the shadow.
192
+ obs_pos : ndarray of shape (3,)
193
+ Observer position in the black hole's rest frame.
194
+ right, up, view_dir : ndarray of shape (3,)
195
+ Camera basis vectors, e.g. from :func:`camera_basis`.
196
+ M : float
197
+ Black hole mass, in geometrized units.
198
+ r_disk_inner, r_disk_outer : float
199
+ Inner and outer radius of a thin equatorial accretion disk (set
200
+ ``r_disk_inner > r_disk_outer`` or both to 0 to omit the disk).
201
+ dphi : float, default=0.01
202
+ Angular step size for the orbital-plane integration.
203
+ n_steps : int, default=3000
204
+ Maximum steps per ray.
205
+ r_horizon_factor : float, default=1.001
206
+ A ray is marked captured once :math:`r` drops below this factor
207
+ times the horizon radius :math:`2M`.
208
+
209
+ Returns
210
+ -------
211
+ outcomes : ndarray of shape (ny, nx), dtype int64
212
+ Per-pixel outcome code (see :data:`OUTCOME_ESCAPED`,
213
+ :data:`OUTCOME_CAPTURED`, :data:`OUTCOME_UNRESOLVED`,
214
+ :data:`OUTCOME_DISK`).
215
+ hit_radii : ndarray of shape (ny, nx)
216
+ Disk-crossing radius for :data:`OUTCOME_DISK` pixels, ``-1``
217
+ elsewhere.
218
+ """
219
+ outcomes = np.zeros((ny, nx), dtype=np.int64)
220
+ hit_radii = np.full((ny, nx), -1.0)
221
+ for iy in range(ny):
222
+ beta = screen_half_height * (1.0 - 2.0 * iy / (ny - 1))
223
+ for ix in range(nx):
224
+ alpha = screen_half_width * (2.0 * ix / (nx - 1) - 1.0)
225
+ outcome, hit_r = _trace_pixel(
226
+ alpha,
227
+ beta,
228
+ obs_pos,
229
+ right,
230
+ up,
231
+ view_dir,
232
+ M,
233
+ r_disk_inner,
234
+ r_disk_outer,
235
+ dphi,
236
+ n_steps,
237
+ r_horizon_factor,
238
+ )
239
+ outcomes[iy, ix] = outcome
240
+ hit_radii[iy, ix] = hit_r
241
+ return outcomes, hit_radii
@@ -0,0 +1,468 @@
1
+ """A numerical differential geometry engine for arbitrary 4D spacetimes.
2
+
3
+ Rather than requiring a symbolic algebra system, this module computes
4
+ Christoffel symbols and curvature tensors **numerically**, by finite
5
+ differencing a metric function :math:`g_{\\mu\\nu}(x)` supplied as a plain
6
+ Python callable. This makes it trivial to plug in any metric -- Schwarzschild,
7
+ Kerr, Reissner-Nordstrom, FLRW, even an exotic metric like the Alcubierre
8
+ warp drive -- and get its curvature out, at the cost of some numerical noise
9
+ relative to an exact symbolic computation (typically negligible at the
10
+ default step size for smooth metrics away from coordinate singularities).
11
+
12
+ A metric function has the signature ``g(coords, **params) -> ndarray`` of
13
+ shape ``(4, 4)``, where ``coords`` is a length-4 array of the four spacetime
14
+ coordinates at which to evaluate the metric.
15
+
16
+ Every function in this module follows the :math:`(-,+,+,+)` signature
17
+ convention.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import numpy as np
23
+
24
+ __all__ = [
25
+ "alcubierre_metric",
26
+ "christoffel_symbols",
27
+ "einstein_tensor",
28
+ "flrw_metric",
29
+ "inverse_metric",
30
+ "kerr_metric_bl",
31
+ "reissner_nordstrom_metric",
32
+ "ricci_scalar",
33
+ "ricci_tensor",
34
+ "riemann_tensor",
35
+ "schwarzschild_metric",
36
+ ]
37
+
38
+
39
+ def inverse_metric(metric_func, coords, params=None):
40
+ """Inverse metric :math:`g^{\\mu\\nu}` at a point.
41
+
42
+ Parameters
43
+ ----------
44
+ metric_func : callable
45
+ A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
46
+ coords : array_like of shape (4,)
47
+ Coordinates at which to evaluate the metric.
48
+ params : dict, optional
49
+ Keyword parameters forwarded to ``metric_func`` (e.g. ``{"M": 1.0}``).
50
+
51
+ Returns
52
+ -------
53
+ ndarray of shape (4, 4)
54
+ The inverse metric :math:`g^{\\mu\\nu}`.
55
+ """
56
+ params = params or {}
57
+ g = metric_func(coords, **params)
58
+ return np.linalg.inv(g)
59
+
60
+
61
+ def christoffel_symbols(metric_func, coords, params=None, h=1e-6):
62
+ """Christoffel symbols of the second kind, :math:`\\Gamma^\\mu_{\\alpha\\beta}`.
63
+
64
+ .. math::
65
+
66
+ \\Gamma^\\mu_{\\alpha\\beta} = \\frac{1}{2} g^{\\mu\\nu}
67
+ \\left(\\partial_\\alpha g_{\\nu\\beta} + \\partial_\\beta g_{\\nu\\alpha}
68
+ - \\partial_\\nu g_{\\alpha\\beta}\\right)
69
+
70
+ Metric derivatives are estimated with a central finite difference.
71
+
72
+ Parameters
73
+ ----------
74
+ metric_func : callable
75
+ A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
76
+ coords : array_like of shape (4,)
77
+ Coordinates at which to evaluate the Christoffel symbols.
78
+ params : dict, optional
79
+ Keyword parameters forwarded to ``metric_func``.
80
+ h : float, default=1e-6
81
+ Finite-difference step size.
82
+
83
+ Returns
84
+ -------
85
+ ndarray of shape (4, 4, 4)
86
+ ``Gamma[mu, alpha, beta]`` :math:`= \\Gamma^\\mu_{\\alpha\\beta}`.
87
+
88
+ Examples
89
+ --------
90
+ >>> coords = np.array([0.0, 10.0, np.pi / 2, 0.0])
91
+ >>> Gamma = christoffel_symbols(schwarzschild_metric, coords, {"M": 1.0})
92
+ >>> Gamma.shape
93
+ (4, 4, 4)
94
+ """
95
+ params = params or {}
96
+ coords = np.asarray(coords, dtype=np.float64)
97
+ g_inv = inverse_metric(metric_func, coords, params)
98
+
99
+ dg = np.empty((4, 4, 4)) # dg[alpha, mu, nu] = d_alpha g_{mu nu}
100
+ for alpha in range(4):
101
+ shift = np.zeros(4)
102
+ shift[alpha] = h
103
+ g_plus = metric_func(coords + shift, **params)
104
+ g_minus = metric_func(coords - shift, **params)
105
+ dg[alpha] = (g_plus - g_minus) / (2.0 * h)
106
+
107
+ Gamma = np.zeros((4, 4, 4))
108
+ for mu in range(4):
109
+ for alpha in range(4):
110
+ for beta in range(4):
111
+ s = 0.0
112
+ for nu in range(4):
113
+ s += g_inv[mu, nu] * (dg[alpha, nu, beta] + dg[beta, nu, alpha] - dg[nu, alpha, beta])
114
+ Gamma[mu, alpha, beta] = 0.5 * s
115
+ return Gamma
116
+
117
+
118
+ def riemann_tensor(metric_func, coords, params=None, h=1e-4):
119
+ """Riemann curvature tensor :math:`R^\\rho{}_{\\sigma\\mu\\nu}`.
120
+
121
+ .. math::
122
+
123
+ R^\\rho{}_{\\sigma\\mu\\nu} = \\partial_\\mu \\Gamma^\\rho_{\\nu\\sigma}
124
+ - \\partial_\\nu \\Gamma^\\rho_{\\mu\\sigma}
125
+ + \\Gamma^\\rho_{\\mu\\lambda}\\Gamma^\\lambda_{\\nu\\sigma}
126
+ - \\Gamma^\\rho_{\\nu\\lambda}\\Gamma^\\lambda_{\\mu\\sigma}
127
+
128
+ Christoffel derivatives are estimated with a central finite difference of
129
+ :func:`christoffel_symbols` itself, so this involves an effective
130
+ second derivative of the metric; a coarser default step size than
131
+ :func:`christoffel_symbols` is used to balance truncation and
132
+ round-off error.
133
+
134
+ Parameters
135
+ ----------
136
+ metric_func : callable
137
+ A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
138
+ coords : array_like of shape (4,)
139
+ Coordinates at which to evaluate the Riemann tensor.
140
+ params : dict, optional
141
+ Keyword parameters forwarded to ``metric_func``.
142
+ h : float, default=1e-4
143
+ Finite-difference step size.
144
+
145
+ Returns
146
+ -------
147
+ ndarray of shape (4, 4, 4, 4)
148
+ ``R[rho, sigma, mu, nu]``.
149
+ """
150
+ params = params or {}
151
+ coords = np.asarray(coords, dtype=np.float64)
152
+
153
+ dGamma = np.empty((4, 4, 4, 4)) # dGamma[mu, rho, nu, sigma] = d_mu Gamma^rho_{nu sigma}
154
+ for mu in range(4):
155
+ shift = np.zeros(4)
156
+ shift[mu] = h
157
+ G_plus = christoffel_symbols(metric_func, coords + shift, params, h=h * 1e-2)
158
+ G_minus = christoffel_symbols(metric_func, coords - shift, params, h=h * 1e-2)
159
+ dGamma[mu] = (G_plus - G_minus) / (2.0 * h)
160
+
161
+ Gamma = christoffel_symbols(metric_func, coords, params, h=h * 1e-2)
162
+
163
+ R = np.zeros((4, 4, 4, 4))
164
+ for rho in range(4):
165
+ for sigma in range(4):
166
+ for mu in range(4):
167
+ for nu in range(4):
168
+ term = dGamma[mu, rho, nu, sigma] - dGamma[nu, rho, mu, sigma]
169
+ for lam in range(4):
170
+ term += Gamma[rho, mu, lam] * Gamma[lam, nu, sigma]
171
+ term -= Gamma[rho, nu, lam] * Gamma[lam, mu, sigma]
172
+ R[rho, sigma, mu, nu] = term
173
+ return R
174
+
175
+
176
+ def ricci_tensor(metric_func, coords, params=None, h=1e-4):
177
+ """Ricci tensor :math:`R_{\\mu\\nu} = R^\\rho{}_{\\mu\\rho\\nu}`, the trace of the Riemann tensor.
178
+
179
+ Parameters
180
+ ----------
181
+ metric_func : callable
182
+ A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
183
+ coords : array_like of shape (4,)
184
+ Coordinates at which to evaluate the Ricci tensor.
185
+ params : dict, optional
186
+ Keyword parameters forwarded to ``metric_func``.
187
+ h : float, default=1e-4
188
+ Finite-difference step size, forwarded to :func:`riemann_tensor`.
189
+
190
+ Returns
191
+ -------
192
+ ndarray of shape (4, 4)
193
+ The Ricci tensor :math:`R_{\\mu\\nu}`.
194
+ """
195
+ R = riemann_tensor(metric_func, coords, params, h=h)
196
+ return np.einsum("rmrn->mn", R)
197
+
198
+
199
+ def ricci_scalar(metric_func, coords, params=None, h=1e-4):
200
+ """Ricci scalar :math:`R = g^{\\mu\\nu} R_{\\mu\\nu}`.
201
+
202
+ Parameters
203
+ ----------
204
+ metric_func : callable
205
+ A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
206
+ coords : array_like of shape (4,)
207
+ Coordinates at which to evaluate the Ricci scalar.
208
+ params : dict, optional
209
+ Keyword parameters forwarded to ``metric_func``.
210
+ h : float, default=1e-4
211
+ Finite-difference step size, forwarded to :func:`riemann_tensor`.
212
+
213
+ Returns
214
+ -------
215
+ float
216
+ The Ricci scalar :math:`R`.
217
+ """
218
+ params = params or {}
219
+ g_inv = inverse_metric(metric_func, coords, params)
220
+ Ric = ricci_tensor(metric_func, coords, params, h=h)
221
+ return float(np.einsum("mn,mn->", g_inv, Ric))
222
+
223
+
224
+ def einstein_tensor(metric_func, coords, params=None, h=1e-4):
225
+ """Einstein tensor :math:`G_{\\mu\\nu} = R_{\\mu\\nu} - \\frac{1}{2} R g_{\\mu\\nu}`.
226
+
227
+ In vacuum, Einstein's field equations require :math:`G_{\\mu\\nu} = 0`;
228
+ evaluating this on the Schwarzschild metric and finding it numerically
229
+ close to zero is a good sanity check of both the metric and this
230
+ finite-difference curvature engine (see the Examples).
231
+
232
+ Parameters
233
+ ----------
234
+ metric_func : callable
235
+ A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
236
+ coords : array_like of shape (4,)
237
+ Coordinates at which to evaluate the Einstein tensor.
238
+ params : dict, optional
239
+ Keyword parameters forwarded to ``metric_func``.
240
+ h : float, default=1e-4
241
+ Finite-difference step size, forwarded to :func:`riemann_tensor`.
242
+
243
+ Returns
244
+ -------
245
+ ndarray of shape (4, 4)
246
+ The Einstein tensor :math:`G_{\\mu\\nu}`.
247
+
248
+ Examples
249
+ --------
250
+ >>> coords = np.array([0.0, 10.0, np.pi / 2, 0.0])
251
+ >>> G = einstein_tensor(schwarzschild_metric, coords, {"M": 1.0})
252
+ >>> bool(np.max(np.abs(G)) < 1e-2)
253
+ True
254
+ """
255
+ params = params or {}
256
+ g = metric_func(coords, **params)
257
+ Ric = ricci_tensor(metric_func, coords, params, h=h)
258
+ R = ricci_scalar(metric_func, coords, params, h=h)
259
+ return Ric - 0.5 * R * g
260
+
261
+
262
+ # ---------------------------------------------------------------------------
263
+ # Standard metrics
264
+ # ---------------------------------------------------------------------------
265
+
266
+
267
+ def schwarzschild_metric(coords, M=1.0):
268
+ """The Schwarzschild metric in Schwarzschild coordinates :math:`(t, r, \\theta, \\phi)`.
269
+
270
+ .. math::
271
+
272
+ ds^2 = -\\left(1 - \\frac{2M}{r}\\right) dt^2
273
+ + \\left(1 - \\frac{2M}{r}\\right)^{-1} dr^2
274
+ + r^2 d\\theta^2 + r^2 \\sin^2\\theta \\, d\\phi^2
275
+
276
+ Parameters
277
+ ----------
278
+ coords : array_like of shape (4,)
279
+ Coordinates :math:`(t, r, \\theta, \\phi)`.
280
+ M : float, default=1.0
281
+ Black hole mass, in geometrized units.
282
+
283
+ Returns
284
+ -------
285
+ ndarray of shape (4, 4)
286
+ The metric tensor :math:`g_{\\mu\\nu}`.
287
+ """
288
+ _t, r, theta, _phi = coords
289
+ f = 1.0 - 2.0 * M / r
290
+ g = np.zeros((4, 4))
291
+ g[0, 0] = -f
292
+ g[1, 1] = 1.0 / f
293
+ g[2, 2] = r**2
294
+ g[3, 3] = r**2 * np.sin(theta) ** 2
295
+ return g
296
+
297
+
298
+ def kerr_metric_bl(coords, M=1.0, a=0.0):
299
+ """The Kerr metric in Boyer-Lindquist coordinates :math:`(t, r, \\theta, \\phi)`.
300
+
301
+ .. math::
302
+
303
+ ds^2 = -\\left(1 - \\frac{2Mr}{\\Sigma}\\right) dt^2
304
+ - \\frac{4Mar\\sin^2\\theta}{\\Sigma} dt\\, d\\phi
305
+ + \\frac{\\Sigma}{\\Delta} dr^2 + \\Sigma\\, d\\theta^2
306
+ + \\left(r^2 + a^2 + \\frac{2Ma^2 r \\sin^2\\theta}{\\Sigma}\\right)
307
+ \\sin^2\\theta \\, d\\phi^2
308
+
309
+ with :math:`\\Sigma = r^2 + a^2\\cos^2\\theta` and
310
+ :math:`\\Delta = r^2 - 2Mr + a^2`.
311
+
312
+ Parameters
313
+ ----------
314
+ coords : array_like of shape (4,)
315
+ Coordinates :math:`(t, r, \\theta, \\phi)`.
316
+ M : float, default=1.0
317
+ Black hole mass, in geometrized units.
318
+ a : float, default=0.0
319
+ Spin parameter :math:`a = J/M`, with :math:`0 \\le a < M`.
320
+ ``a=0`` recovers the Schwarzschild metric.
321
+
322
+ Returns
323
+ -------
324
+ ndarray of shape (4, 4)
325
+ The metric tensor :math:`g_{\\mu\\nu}`.
326
+ """
327
+ _t, r, theta, _phi = coords
328
+ sin2 = np.sin(theta) ** 2
329
+ Sigma = r**2 + a**2 * np.cos(theta) ** 2
330
+ Delta = r**2 - 2.0 * M * r + a**2
331
+
332
+ g = np.zeros((4, 4))
333
+ g[0, 0] = -(1.0 - 2.0 * M * r / Sigma)
334
+ g[0, 3] = g[3, 0] = -2.0 * M * a * r * sin2 / Sigma
335
+ g[1, 1] = Sigma / Delta
336
+ g[2, 2] = Sigma
337
+ g[3, 3] = (r**2 + a**2 + 2.0 * M * a**2 * r * sin2 / Sigma) * sin2
338
+ return g
339
+
340
+
341
+ def reissner_nordstrom_metric(coords, M=1.0, Q=0.0):
342
+ """The Reissner-Nordstrom metric of a charged, non-rotating black hole.
343
+
344
+ .. math::
345
+
346
+ ds^2 = -\\left(1 - \\frac{2M}{r} + \\frac{Q^2}{r^2}\\right) dt^2
347
+ + \\left(1 - \\frac{2M}{r} + \\frac{Q^2}{r^2}\\right)^{-1} dr^2
348
+ + r^2 d\\theta^2 + r^2 \\sin^2\\theta \\, d\\phi^2
349
+
350
+ Parameters
351
+ ----------
352
+ coords : array_like of shape (4,)
353
+ Coordinates :math:`(t, r, \\theta, \\phi)`.
354
+ M : float, default=1.0
355
+ Mass, in geometrized units.
356
+ Q : float, default=0.0
357
+ Electric charge, in geometrized units (``Q=0`` recovers Schwarzschild).
358
+
359
+ Returns
360
+ -------
361
+ ndarray of shape (4, 4)
362
+ The metric tensor :math:`g_{\\mu\\nu}`.
363
+ """
364
+ _t, r, theta, _phi = coords
365
+ f = 1.0 - 2.0 * M / r + Q**2 / r**2
366
+ g = np.zeros((4, 4))
367
+ g[0, 0] = -f
368
+ g[1, 1] = 1.0 / f
369
+ g[2, 2] = r**2
370
+ g[3, 3] = r**2 * np.sin(theta) ** 2
371
+ return g
372
+
373
+
374
+ def flrw_metric(coords, a_func, k=0.0):
375
+ """The FLRW metric in comoving spherical coordinates :math:`(t, \\chi, \\theta, \\phi)`.
376
+
377
+ .. math::
378
+
379
+ ds^2 = -dt^2 + a(t)^2 \\left[d\\chi^2 + S_k(\\chi)^2 d\\Omega^2\\right]
380
+
381
+ where :math:`S_k(\\chi) = \\chi` for a flat universe (:math:`k=0`),
382
+ :math:`\\sin\\chi` for a closed universe (:math:`k=+1`), and
383
+ :math:`\\sinh\\chi` for an open universe (:math:`k=-1`).
384
+
385
+ Parameters
386
+ ----------
387
+ coords : array_like of shape (4,)
388
+ Coordinates :math:`(t, \\chi, \\theta, \\phi)`.
389
+ a_func : callable
390
+ The scale factor as a function of cosmic time, ``a_func(t) -> float``.
391
+ k : {-1, 0, 1}, default=0.0
392
+ Spatial curvature sign.
393
+
394
+ Returns
395
+ -------
396
+ ndarray of shape (4, 4)
397
+ The metric tensor :math:`g_{\\mu\\nu}`.
398
+ """
399
+ t, chi, theta, _phi = coords
400
+ a = a_func(t)
401
+ if k == 0:
402
+ Sk = chi
403
+ elif k > 0:
404
+ Sk = np.sin(chi)
405
+ else:
406
+ Sk = np.sinh(chi)
407
+
408
+ g = np.zeros((4, 4))
409
+ g[0, 0] = -1.0
410
+ g[1, 1] = a**2
411
+ g[2, 2] = a**2 * Sk**2
412
+ g[3, 3] = a**2 * Sk**2 * np.sin(theta) ** 2
413
+ return g
414
+
415
+
416
+ def alcubierre_metric(coords, v_s=2.0, sigma=8.0, R=1.0):
417
+ """The Alcubierre "warp drive" metric in Cartesian coordinates :math:`(t, x, y, z)`.
418
+
419
+ .. math::
420
+
421
+ ds^2 = -dt^2 + \\left[dx - v_s(t) f(r_s) \\, dt\\right]^2 + dy^2 + dz^2
422
+
423
+ where :math:`r_s = \\sqrt{(x - x_s(t))^2 + y^2 + z^2}` is the distance
424
+ from the center of the "warp bubble" (moving along :math:`x` at
425
+ coordinate speed :math:`v_s`, with :math:`x_s(t) = v_s t`), and
426
+
427
+ .. math::
428
+
429
+ f(r_s) = \\frac{\\tanh(\\sigma(r_s + R)) - \\tanh(\\sigma(r_s - R))}
430
+ {2 \\tanh(\\sigma R)}
431
+
432
+ is a smooth top-hat function equal to 1 well inside the bubble
433
+ (:math:`r_s \\ll R`) and 0 far outside it. Spacetime is flat both inside
434
+ and outside the thin bubble wall, but a ship riding inside can traverse
435
+ coordinate distance faster than light as measured by a distant observer
436
+ -- entirely by locally contracting spacetime ahead of it and expanding
437
+ spacetime behind, without ever locally exceeding the speed of light.
438
+ Known solutions like this one require exotic (negative-energy-density)
439
+ matter to source them via Einstein's equations.
440
+
441
+ Parameters
442
+ ----------
443
+ coords : array_like of shape (4,)
444
+ Coordinates :math:`(t, x, y, z)`.
445
+ v_s : float, default=2.0
446
+ Coordinate warp speed, in units of :math:`c`.
447
+ sigma : float, default=8.0
448
+ Bubble wall steepness.
449
+ R : float, default=1.0
450
+ Bubble radius, in geometrized length units.
451
+
452
+ Returns
453
+ -------
454
+ ndarray of shape (4, 4)
455
+ The metric tensor :math:`g_{\\mu\\nu}`.
456
+ """
457
+ t, x, y, z = coords
458
+ x_s = v_s * t
459
+ r_s = np.sqrt((x - x_s) ** 2 + y**2 + z**2)
460
+ f = (np.tanh(sigma * (r_s + R)) - np.tanh(sigma * (r_s - R))) / (2.0 * np.tanh(sigma * R))
461
+
462
+ g = np.zeros((4, 4))
463
+ g[0, 0] = v_s**2 * f**2 - 1.0
464
+ g[0, 1] = g[1, 0] = -v_s * f
465
+ g[1, 1] = 1.0
466
+ g[2, 2] = 1.0
467
+ g[3, 3] = 1.0
468
+ return g
File without changes