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
physicskit/__init__.py ADDED
@@ -0,0 +1,51 @@
1
+ """physicskit: unified scientific toolkit for computational physics.
2
+
3
+ Import as ``pk`` by convention::
4
+
5
+ import physicskit as pk
6
+ pk.condensed.compute_chern_number(...)
7
+ pk.chaos.systems.maps.LogisticMap(...)
8
+ pk.fields.nls_dark_soliton(...)
9
+ pk.optics.GaussianBeam(wavelength=1.064e-3, w0=0.05)
10
+ pk.particle.FourVector(E=1.0, px=0.0, py=0.0, pz=0.6)
11
+ pk.astro.PolytropicStar(n=1.5, K=1.0, rho_c=1.0)
12
+ pk.plasma.alfven_speed(B=1.0, rho=1e-6)
13
+ """
14
+
15
+ from physicskit import (
16
+ astro,
17
+ chaos,
18
+ classical,
19
+ condensed,
20
+ constants,
21
+ fields,
22
+ integrators,
23
+ optics,
24
+ particle,
25
+ plasma,
26
+ quantum,
27
+ relativity,
28
+ rmt,
29
+ semiclassical,
30
+ statphys,
31
+ )
32
+
33
+ __version__ = "0.1.0"
34
+
35
+ __all__ = [
36
+ "astro",
37
+ "chaos",
38
+ "classical",
39
+ "condensed",
40
+ "constants",
41
+ "fields",
42
+ "integrators",
43
+ "optics",
44
+ "particle",
45
+ "plasma",
46
+ "quantum",
47
+ "relativity",
48
+ "rmt",
49
+ "semiclassical",
50
+ "statphys",
51
+ ]
@@ -0,0 +1,66 @@
1
+ """physicskit.astro: stellar structure, N-body dynamics, orbital mechanics, and galactic dynamics.
2
+
3
+ Uses **gravitational units with** :math:`G=1` by default throughout
4
+ (every function that needs it accepts ``G`` as a keyword argument), the
5
+ same convention :mod:`physicskit.relativity` uses for its own
6
+ geometrized units.
7
+
8
+ - :mod:`physicskit.astro.stellar_structure` -- polytropic stellar models
9
+ via the Lane-Emden equation, the Chandrasekhar mass limit, and the
10
+ main-sequence mass-luminosity relation.
11
+ - :mod:`physicskit.astro.nbody` -- direct-summation N-body gravitational
12
+ dynamics with a symplectic leapfrog integrator.
13
+ - :mod:`physicskit.astro.orbital_mechanics` -- classical orbital elements,
14
+ state-vector conversion, and Hohmann transfers.
15
+ - :mod:`physicskit.astro.galactic_dynamics` -- the NFW dark matter halo
16
+ profile and the rotation curves it produces.
17
+ - :mod:`physicskit.astro.visualizers` -- N-body, Lane-Emden, and
18
+ rotation-curve plots.
19
+ """
20
+
21
+ from physicskit.astro.galactic_dynamics import circular_velocity, nfw_density, nfw_enclosed_mass, nfw_potential
22
+ from physicskit.astro.nbody import NBodySystem, gravitational_acceleration, leapfrog_step
23
+ from physicskit.astro.orbital_mechanics import (
24
+ hohmann_transfer,
25
+ orbital_elements_from_state,
26
+ orbital_period,
27
+ state_from_orbital_elements,
28
+ vis_viva_speed,
29
+ )
30
+ from physicskit.astro.stellar_structure import (
31
+ PolytropicStar,
32
+ chandrasekhar_mass,
33
+ lane_emden,
34
+ main_sequence_luminosity,
35
+ )
36
+ from physicskit.astro.visualizers import plot_lane_emden, plot_nbody_trajectories, plot_rotation_curve
37
+
38
+ __version__ = "0.1.0"
39
+
40
+ __all__ = [
41
+ "__version__",
42
+ # stellar_structure
43
+ "lane_emden",
44
+ "PolytropicStar",
45
+ "chandrasekhar_mass",
46
+ "main_sequence_luminosity",
47
+ # nbody
48
+ "gravitational_acceleration",
49
+ "leapfrog_step",
50
+ "NBodySystem",
51
+ # orbital_mechanics
52
+ "orbital_period",
53
+ "vis_viva_speed",
54
+ "orbital_elements_from_state",
55
+ "state_from_orbital_elements",
56
+ "hohmann_transfer",
57
+ # galactic_dynamics
58
+ "nfw_density",
59
+ "nfw_enclosed_mass",
60
+ "nfw_potential",
61
+ "circular_velocity",
62
+ # visualizers
63
+ "plot_nbody_trajectories",
64
+ "plot_lane_emden",
65
+ "plot_rotation_curve",
66
+ ]
@@ -0,0 +1,395 @@
1
+ r"""The Zel'dovich (1970) approximation and the formation of the cosmic web.
2
+
3
+ In an expanding universe, small density perturbations do not stay small
4
+ forever: gravity amplifies them until they collapse along their fastest-
5
+ contracting direction first, producing the sheets ("pancakes"), filaments,
6
+ and dense nodes that together make up the observed large-scale structure of
7
+ the universe -- the *cosmic web*. Zel'dovich (1970, *Astronomy and
8
+ Astrophysics* 5, "Gravitational instability: An approximate theory for
9
+ large density perturbations") gave the classic, mathematically clean
10
+ description of this process: to first order in the displacement of matter
11
+ away from a uniform background, each fluid element simply moves in a
12
+ straight line (in comoving coordinates) at a rate set by the local gradient
13
+ of a fixed potential. The approximation is exact in one dimension and
14
+ remains an excellent guide to the onset of nonlinear structure in more
15
+ dimensions, which is why it is still the standard way to generate the
16
+ initial conditions of cosmological N-body simulations today.
17
+
18
+ This module works in a flat, matter-dominated (Einstein-de Sitter)
19
+ background, where the scale factor grows as :math:`a(t)\propto t^{2/3}`
20
+ and the linear growth factor of density perturbations is proportional to
21
+ the scale factor, :math:`D(t)\propto a(t)`. Rather than tracking time
22
+ directly, every function here is parametrized by the growth factor
23
+ :math:`D` itself, which increases monotonically from :math:`D=0` at the
24
+ initial (unperturbed) time.
25
+
26
+ Given a fixed Lagrangian ("unperturbed") position :math:`\mathbf{q}` and a
27
+ scalar displacement potential :math:`\Phi(\mathbf{q})`, the Zel'dovich
28
+ approximation maps :math:`\mathbf{q}` to a comoving Eulerian position
29
+
30
+ .. math::
31
+
32
+ \mathbf{x}(\mathbf{q}, D) = \mathbf{q} - D\,\nabla\Phi(\mathbf{q}),
33
+
34
+ i.e. every fluid element streams away from its starting point along a
35
+ straight line, in the fixed direction :math:`-\nabla\Phi(\mathbf{q})`, at a
36
+ rate that grows linearly with :math:`D`. This module builds :math:`\Phi` as
37
+ a sum of a modest number of plane waves -- a simple stand-in for a
38
+ realistic Gaussian random field, exactly as used pedagogically --
39
+
40
+ .. math::
41
+
42
+ \Phi(\mathbf{q}) = \sum_{n=1}^{N} A_n\cos(\mathbf{k}_n\cdot\mathbf{q}+\varphi_n),
43
+
44
+ with random wavevectors :math:`\mathbf{k}_n`, amplitudes :math:`A_n`, and
45
+ phases :math:`\varphi_n`. Because mass is conserved as fluid elements move,
46
+ the local density contrast follows directly from the Jacobian of the
47
+ mapping :math:`\mathbf{q}\mapsto\mathbf{x}`:
48
+
49
+ .. math::
50
+
51
+ \frac{\rho(\mathbf{x})}{\bar\rho} = \frac{1}{\left|\det\left(I - D\,H_\Phi(\mathbf{q})\right)\right|},
52
+
53
+ where :math:`H_\Phi` is the Hessian of :math:`\Phi`. This formally
54
+ diverges -- a caustic, i.e. a "pancake" -- the first time :math:`D` reaches
55
+ :math:`1/\lambda_{\max}(\mathbf{q})`, where :math:`\lambda_{\max}(\mathbf{q})`
56
+ is the largest eigenvalue of :math:`H_\Phi` at that point. The very first
57
+ caustic anywhere in the field therefore forms at
58
+
59
+ .. math::
60
+
61
+ D_{\rm collapse} = \frac{1}{\max_{\mathbf{q}}\lambda_{\max}(\mathbf{q})}.
62
+
63
+ For a single plane-wave potential this is exact and closed-form
64
+ (:math:`D_{\rm collapse}=1/(A|\mathbf{k}|^2)`), which makes it a clean,
65
+ directly testable prediction; see the test suite for the exact derivation.
66
+
67
+ - :func:`random_displacement_potential` -- draw a random multi-mode
68
+ displacement potential :math:`\Phi`.
69
+ - :func:`zeldovich_displacement` -- the analytic gradient
70
+ :math:`\nabla\Phi(\mathbf{q})`.
71
+ - :func:`zeldovich_position` -- the Zel'dovich mapping
72
+ :math:`\mathbf{x}(\mathbf{q}, D)`.
73
+ - :func:`zeldovich_hessian_eigenvalues` -- the eigenvalues of
74
+ :math:`H_\Phi(\mathbf{q})`, which control local collapse.
75
+ - :func:`first_caustic_time` -- the growth factor at which the first
76
+ pancake forms anywhere in the field.
77
+ - :func:`lagrangian_grid` -- a regular grid of Lagrangian tracer particles
78
+ to evolve under the mapping.
79
+ """
80
+
81
+ from __future__ import annotations
82
+
83
+ import numpy as np
84
+
85
+ __all__ = [
86
+ "random_displacement_potential",
87
+ "zeldovich_displacement",
88
+ "zeldovich_position",
89
+ "zeldovich_hessian_eigenvalues",
90
+ "first_caustic_time",
91
+ "lagrangian_grid",
92
+ ]
93
+
94
+
95
+ def random_displacement_potential(n_modes, k_min, k_max, amplitude_scale, seed=None, ndim=2):
96
+ r"""Draw a random multi-mode displacement potential :math:`\Phi(\mathbf{q})`.
97
+
98
+ Builds :math:`\Phi(\mathbf{q}) = \sum_{n=1}^{N}A_n\cos(\mathbf{k}_n\cdot
99
+ \mathbf{q}+\varphi_n)` -- a simple stand-in for a realistic Gaussian
100
+ random field -- with wavevectors :math:`\mathbf{k}_n` of random
101
+ orientation and magnitude drawn uniformly from :math:`[k_{\min},
102
+ k_{\max}]`, amplitudes drawn uniformly from :math:`[0,
103
+ \text{amplitude\_scale}]`, and phases drawn uniformly from
104
+ :math:`[0, 2\pi)`.
105
+
106
+ Parameters
107
+ ----------
108
+ n_modes : int
109
+ Number of plane-wave modes, :math:`N`.
110
+ k_min, k_max : float
111
+ Lower and upper bounds on the wavenumber magnitude
112
+ :math:`|\mathbf{k}_n|`, setting the band of scales structure forms
113
+ at.
114
+ amplitude_scale : float
115
+ Upper bound on each mode's amplitude :math:`A_n`.
116
+ seed : int, optional
117
+ Random seed, for reproducibility.
118
+ ndim : int, default=2
119
+ Spatial dimension. Only ``ndim=2`` is supported; the analytic
120
+ gradient/Hessian machinery in this module is 2D-specific.
121
+
122
+ Returns
123
+ -------
124
+ k_vectors : ndarray, shape (n_modes, ndim)
125
+ Wavevectors :math:`\mathbf{k}_n`.
126
+ amplitudes : ndarray, shape (n_modes,)
127
+ Amplitudes :math:`A_n`.
128
+ phases : ndarray, shape (n_modes,)
129
+ Phases :math:`\varphi_n`, in :math:`[0, 2\pi)`.
130
+
131
+ Raises
132
+ ------
133
+ ValueError
134
+ If ``ndim != 2``, ``n_modes < 1``, or ``k_max < k_min``.
135
+
136
+ Examples
137
+ --------
138
+ >>> k_vectors, amplitudes, phases = random_displacement_potential(8, k_min=1.0, k_max=3.0, amplitude_scale=0.1, seed=0)
139
+ >>> k_vectors.shape, amplitudes.shape, phases.shape
140
+ ((8, 2), (8,), (8,))
141
+ >>> bool(np.all(amplitudes >= 0.0) and np.all(amplitudes <= 0.1))
142
+ True
143
+ """
144
+ if ndim != 2:
145
+ raise ValueError("random_displacement_potential only supports ndim=2.")
146
+ if n_modes < 1:
147
+ raise ValueError("n_modes must be >= 1.")
148
+ if k_max < k_min:
149
+ raise ValueError("k_max must be >= k_min.")
150
+
151
+ rng = np.random.default_rng(seed)
152
+ k_mag = rng.uniform(k_min, k_max, n_modes)
153
+ angle = rng.uniform(0.0, 2.0 * np.pi, n_modes)
154
+ k_vectors = np.stack([k_mag * np.cos(angle), k_mag * np.sin(angle)], axis=-1)
155
+ amplitudes = rng.uniform(0.0, amplitude_scale, n_modes)
156
+ phases = rng.uniform(0.0, 2.0 * np.pi, n_modes)
157
+ return k_vectors, amplitudes, phases
158
+
159
+
160
+ def _phase_argument(q, k_vectors, phases):
161
+ """``k_n . q_i + phase_n`` for every particle ``i`` and mode ``n``, shape (n_particles, n_modes)."""
162
+ q = np.atleast_2d(np.asarray(q, dtype=float))
163
+ k_vectors = np.asarray(k_vectors, dtype=float)
164
+ phases = np.asarray(phases, dtype=float)
165
+ return q @ k_vectors.T + phases[None, :]
166
+
167
+
168
+ def zeldovich_displacement(q, k_vectors, amplitudes, phases):
169
+ r"""The analytic displacement field :math:`\nabla\Phi(\mathbf{q})`.
170
+
171
+ .. math::
172
+
173
+ \nabla\Phi(\mathbf{q}) = \sum_n -A_n\,\mathbf{k}_n\,
174
+ \sin(\mathbf{k}_n\cdot\mathbf{q}+\varphi_n)
175
+
176
+ Vectorized over all particles and modes at once (no explicit loops).
177
+
178
+ Parameters
179
+ ----------
180
+ q : ndarray, shape (n_particles, 2)
181
+ Lagrangian (unperturbed) positions.
182
+ k_vectors : ndarray, shape (n_modes, 2)
183
+ amplitudes : ndarray, shape (n_modes,)
184
+ phases : ndarray, shape (n_modes,)
185
+ Potential parameters, e.g. from :func:`random_displacement_potential`.
186
+
187
+ Returns
188
+ -------
189
+ ndarray, shape (n_particles, 2)
190
+ :math:`\nabla\Phi` evaluated at each ``q``.
191
+
192
+ Examples
193
+ --------
194
+ >>> import numpy as np
195
+ >>> k_vectors = np.array([[1.0, 0.0]])
196
+ >>> amplitudes = np.array([2.0])
197
+ >>> phases = np.array([np.pi / 2]) # sin(pi/2) = 1
198
+ >>> grad = zeldovich_displacement(np.array([[0.0, 0.0]]), k_vectors, amplitudes, phases)
199
+ >>> np.round(grad + 0.0, 6) # "+ 0.0" avoids a printed "-0." for exact zeros
200
+ array([[-2., 0.]])
201
+ """
202
+ k_vectors = np.asarray(k_vectors, dtype=float)
203
+ amplitudes = np.asarray(amplitudes, dtype=float)
204
+ theta = _phase_argument(q, k_vectors, phases)
205
+ weighted_sin = np.sin(theta) * amplitudes[None, :]
206
+ return -(weighted_sin @ k_vectors)
207
+
208
+
209
+ def zeldovich_position(q, D, k_vectors, amplitudes, phases):
210
+ r"""The Zel'dovich mapping :math:`\mathbf{x}(\mathbf{q}, D) = \mathbf{q} - D\,\nabla\Phi(\mathbf{q})`.
211
+
212
+ Parameters
213
+ ----------
214
+ q : ndarray, shape (n_particles, 2)
215
+ Lagrangian (unperturbed) positions.
216
+ D : float
217
+ Linear growth factor (dimensionless "time"), :math:`D=0` at the
218
+ initial, unperturbed time.
219
+ k_vectors : ndarray, shape (n_modes, 2)
220
+ amplitudes : ndarray, shape (n_modes,)
221
+ phases : ndarray, shape (n_modes,)
222
+ Potential parameters, e.g. from :func:`random_displacement_potential`.
223
+
224
+ Returns
225
+ -------
226
+ ndarray, shape (n_particles, 2)
227
+ Comoving Eulerian positions :math:`\mathbf{x}`.
228
+
229
+ See Also
230
+ --------
231
+ zeldovich_displacement : The gradient field used here.
232
+
233
+ Examples
234
+ --------
235
+ >>> import numpy as np
236
+ >>> q = np.array([[0.3, 0.7], [1.1, -0.4]])
237
+ >>> k_vectors, amplitudes, phases = random_displacement_potential(4, 1.0, 2.0, 0.1, seed=1)
238
+ >>> x0 = zeldovich_position(q, 0.0, k_vectors, amplitudes, phases)
239
+ >>> bool(np.allclose(x0, q))
240
+ True
241
+ """
242
+ q = np.atleast_2d(np.asarray(q, dtype=float))
243
+ grad_phi = zeldovich_displacement(q, k_vectors, amplitudes, phases)
244
+ return q - D * grad_phi
245
+
246
+
247
+ def zeldovich_hessian_eigenvalues(q, k_vectors, amplitudes, phases):
248
+ r"""Eigenvalues of the analytic Hessian :math:`H_\Phi(\mathbf{q})`.
249
+
250
+ The Hessian components follow directly from differentiating the
251
+ plane-wave sum twice,
252
+
253
+ .. math::
254
+
255
+ \frac{\partial^2\Phi}{\partial q_i\partial q_j}
256
+ = \sum_n -A_n\,k_{n,i}k_{n,j}\cos(\mathbf{k}_n\cdot\mathbf{q}+\varphi_n),
257
+
258
+ and its two eigenvalues follow from the closed-form 2x2 symmetric
259
+ formula
260
+
261
+ .. math::
262
+
263
+ \lambda_\pm = \frac{(\Phi_{xx}+\Phi_{yy}) \pm
264
+ \sqrt{(\Phi_{xx}-\Phi_{yy})^2+4\Phi_{xy}^2}}{2},
265
+
266
+ computed directly as arrays (no per-particle ``numpy.linalg.eigh``
267
+ calls).
268
+
269
+ Parameters
270
+ ----------
271
+ q : ndarray, shape (n_particles, 2)
272
+ Lagrangian (unperturbed) positions.
273
+ k_vectors : ndarray, shape (n_modes, 2)
274
+ amplitudes : ndarray, shape (n_modes,)
275
+ phases : ndarray, shape (n_modes,)
276
+ Potential parameters, e.g. from :func:`random_displacement_potential`.
277
+
278
+ Returns
279
+ -------
280
+ ndarray, shape (n_particles, 2)
281
+ The two eigenvalues of :math:`H_\Phi` at each ``q``, sorted
282
+ ascending along the last axis.
283
+
284
+ See Also
285
+ --------
286
+ first_caustic_time : The growth factor at which the largest of these
287
+ eigenvalues, maximized over all ``q``, first causes a caustic.
288
+
289
+ Examples
290
+ --------
291
+ >>> import numpy as np
292
+ >>> k_vectors = np.array([[2 * np.pi, 0.0]])
293
+ >>> amplitudes = np.array([1.0])
294
+ >>> phases = np.array([np.pi]) # cos(phase) = -1 at q=0: the compression maximum
295
+ >>> eigs = zeldovich_hessian_eigenvalues(np.array([[0.0, 0.0]]), k_vectors, amplitudes, phases)
296
+ >>> np.round(eigs, 6)
297
+ array([[ 0. , 39.478418]])
298
+ """
299
+ k_vectors = np.asarray(k_vectors, dtype=float)
300
+ amplitudes = np.asarray(amplitudes, dtype=float)
301
+ theta = _phase_argument(q, k_vectors, phases)
302
+ weighted_cos = np.cos(theta) * amplitudes[None, :]
303
+
304
+ kx = k_vectors[:, 0]
305
+ ky = k_vectors[:, 1]
306
+ Pxx = -(weighted_cos @ (kx * kx))
307
+ Pyy = -(weighted_cos @ (ky * ky))
308
+ Pxy = -(weighted_cos @ (kx * ky))
309
+
310
+ trace = Pxx + Pyy
311
+ disc = np.sqrt((Pxx - Pyy) ** 2 + 4.0 * Pxy**2)
312
+ lambda_lo = 0.5 * (trace - disc)
313
+ lambda_hi = 0.5 * (trace + disc)
314
+ return np.stack([lambda_lo, lambda_hi], axis=-1)
315
+
316
+
317
+ def first_caustic_time(q, k_vectors, amplitudes, phases):
318
+ r"""The growth factor :math:`D_{\rm collapse}` at which the first caustic forms.
319
+
320
+ .. math::
321
+
322
+ D_{\rm collapse} = \frac{1}{\max_{\mathbf{q}}\lambda_{\max}(\mathbf{q})}
323
+
324
+ evaluated over the sampled points ``q`` (the true collapse time is a
325
+ supremum over the *continuous* field, so this is a lower bound that
326
+ tightens toward the true value as ``q`` samples the field more
327
+ finely).
328
+
329
+ Parameters
330
+ ----------
331
+ q : ndarray, shape (n_particles, 2)
332
+ Lagrangian (unperturbed) sample points, e.g. from
333
+ :func:`lagrangian_grid`.
334
+ k_vectors : ndarray, shape (n_modes, 2)
335
+ amplitudes : ndarray, shape (n_modes,)
336
+ phases : ndarray, shape (n_modes,)
337
+ Potential parameters, e.g. from :func:`random_displacement_potential`.
338
+
339
+ Returns
340
+ -------
341
+ float
342
+ :math:`D_{\rm collapse}`, the growth factor at which the first
343
+ pancake forms anywhere among the sampled points.
344
+
345
+ See Also
346
+ --------
347
+ zeldovich_hessian_eigenvalues : Supplies the per-point eigenvalues
348
+ this is maximized over.
349
+
350
+ Examples
351
+ --------
352
+ >>> import numpy as np
353
+ >>> k_vectors = np.array([[2 * np.pi, 0.0]])
354
+ >>> amplitudes = np.array([1.0])
355
+ >>> phases = np.array([np.pi])
356
+ >>> round(first_caustic_time(np.array([[0.0, 0.0]]), k_vectors, amplitudes, phases), 6)
357
+ 0.02533
358
+ """
359
+ eigs = zeldovich_hessian_eigenvalues(q, k_vectors, amplitudes, phases)
360
+ return float(1.0 / np.max(eigs[:, -1]))
361
+
362
+
363
+ def lagrangian_grid(n_side, box_size):
364
+ r"""A regular grid of Lagrangian tracer particles over :math:`[0, L)^2`.
365
+
366
+ The standard starting point for a Zel'dovich visualization: an
367
+ initially perfectly uniform grid of tracer particles, whose progressive
368
+ deformation into filaments, sheets, and nodes under
369
+ :func:`zeldovich_position` is itself part of what makes the
370
+ visualization compelling.
371
+
372
+ Parameters
373
+ ----------
374
+ n_side : int
375
+ Number of grid points along each axis.
376
+ box_size : float
377
+ Side length :math:`L` of the (periodic) comoving box.
378
+
379
+ Returns
380
+ -------
381
+ ndarray, shape (n_side * n_side, 2)
382
+ Lagrangian positions ``q``, tiling :math:`[0, L)^2` on a regular
383
+ grid.
384
+
385
+ Examples
386
+ --------
387
+ >>> q = lagrangian_grid(4, 1.0)
388
+ >>> q.shape
389
+ (16, 2)
390
+ >>> bool(np.all((q >= 0.0) & (q < 1.0)))
391
+ True
392
+ """
393
+ coords = np.linspace(0.0, box_size, n_side, endpoint=False)
394
+ qx, qy = np.meshgrid(coords, coords, indexing="ij")
395
+ return np.stack([qx.ravel(), qy.ravel()], axis=-1)
@@ -0,0 +1,137 @@
1
+ r"""The Navarro-Frenk-White dark matter halo profile and rotation curves.
2
+
3
+ Uses **gravitational units with** :math:`G=1` by default -- every function
4
+ accepts ``G`` as a keyword argument, the same convention
5
+ :mod:`physicskit.relativity` uses for its own geometrized units.
6
+
7
+ - :func:`nfw_density`, :func:`nfw_enclosed_mass`, :func:`nfw_potential`
8
+ -- the NFW halo profile and its enclosed mass and potential.
9
+ - :func:`circular_velocity` -- the rotation curve produced by any
10
+ enclosed-mass profile.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import numpy as np
16
+
17
+ __all__ = ["nfw_density", "nfw_enclosed_mass", "nfw_potential", "circular_velocity"]
18
+
19
+
20
+ def nfw_density(r, rho_s, r_s):
21
+ r"""The Navarro-Frenk-White density profile.
22
+
23
+ .. math::
24
+
25
+ \rho_{\rm NFW}(r) = \frac{\rho_s}{(r/r_s)(1+r/r_s)^2}
26
+
27
+ Parameters
28
+ ----------
29
+ r : array_like
30
+ Radius.
31
+ rho_s : float
32
+ Characteristic density.
33
+ r_s : float
34
+ Scale radius.
35
+
36
+ Returns
37
+ -------
38
+ ndarray or float
39
+
40
+ Examples
41
+ --------
42
+ >>> round(float(nfw_density(1.0, rho_s=1.0, r_s=1.0)), 6)
43
+ 0.25
44
+ """
45
+ x = np.asarray(r, dtype=float) / r_s
46
+ return rho_s / (x * (1.0 + x) ** 2)
47
+
48
+
49
+ def nfw_enclosed_mass(r, rho_s, r_s, G=1.0):
50
+ r"""Mass enclosed within radius ``r`` for an NFW halo.
51
+
52
+ .. math::
53
+
54
+ M(<r) = 4\pi\rho_s r_s^3\left[\ln\!\left(1+\frac{r}{r_s}\right)
55
+ - \frac{r/r_s}{1+r/r_s}\right]
56
+
57
+ ``G`` is accepted for interface consistency with the rest of this
58
+ module but is not used by this formula.
59
+
60
+ Parameters
61
+ ----------
62
+ r : array_like
63
+ Radius.
64
+ rho_s : float
65
+ Characteristic density.
66
+ r_s : float
67
+ Scale radius.
68
+ G : float, default=1.0
69
+ Unused; accepted for a consistent function signature.
70
+
71
+ Returns
72
+ -------
73
+ ndarray or float
74
+
75
+ Examples
76
+ --------
77
+ >>> round(float(nfw_enclosed_mass(1.0, rho_s=1.0, r_s=1.0)), 6)
78
+ 2.427159
79
+ """
80
+ del G
81
+ x = np.asarray(r, dtype=float) / r_s
82
+ return 4.0 * np.pi * rho_s * r_s**3 * (np.log(1.0 + x) - x / (1.0 + x))
83
+
84
+
85
+ def nfw_potential(r, rho_s, r_s, G=1.0):
86
+ r"""The NFW gravitational potential.
87
+
88
+ .. math::
89
+
90
+ \Phi(r) = -\frac{4\pi G\rho_sr_s^3}{r}\ln\!\left(1+\frac{r}{r_s}\right)
91
+
92
+ Parameters
93
+ ----------
94
+ r : array_like
95
+ Radius.
96
+ rho_s : float
97
+ Characteristic density.
98
+ r_s : float
99
+ Scale radius.
100
+ G : float, default=1.0
101
+ Gravitational constant.
102
+
103
+ Returns
104
+ -------
105
+ ndarray or float
106
+ """
107
+ r = np.asarray(r, dtype=float)
108
+ x = r / r_s
109
+ return -4.0 * np.pi * G * rho_s * r_s**3 * np.log(1.0 + x) / r
110
+
111
+
112
+ def circular_velocity(r, mass_enclosed_func, G=1.0):
113
+ r"""Circular orbital speed for any enclosed-mass profile, :math:`v_c(r)=\sqrt{GM(<r)/r}`.
114
+
115
+ Parameters
116
+ ----------
117
+ r : array_like
118
+ Radius.
119
+ mass_enclosed_func : callable
120
+ ``mass_enclosed_func(r) -> mass``, e.g.
121
+ ``lambda r: nfw_enclosed_mass(r, rho_s, r_s)``.
122
+ G : float, default=1.0
123
+ Gravitational constant.
124
+
125
+ Returns
126
+ -------
127
+ ndarray or float
128
+
129
+ Examples
130
+ --------
131
+ >>> M0 = 5.0
132
+ >>> round(float(circular_velocity(2.0, lambda r: M0, G=1.0)), 6)
133
+ 1.581139
134
+ """
135
+ r = np.asarray(r, dtype=float)
136
+ M = mass_enclosed_func(r)
137
+ return np.sqrt(G * M / r)