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,198 @@
1
+ import numpy as np
2
+ import pytest
3
+
4
+ from physicskit.astro.stellar_dynamo import (
5
+ _spectral_grid_2d,
6
+ alpha_omega_growth_rate,
7
+ alpha_omega_wave_frequency,
8
+ convective_roll_rhs,
9
+ dominant_mode_growth_rate,
10
+ kinetic_energy,
11
+ simulate_alpha_omega_dynamo,
12
+ simulate_stellar_convection,
13
+ )
14
+
15
+ # ---------------------------------------------------------------------------
16
+ # Part 2: alpha-omega mean-field dynamo -- the core dispersion-relation check
17
+ # ---------------------------------------------------------------------------
18
+
19
+
20
+ def test_alpha_omega_growth_rate_matches_simulation_for_unstable_mode():
21
+ """The single most important correctness guarantee in this module:
22
+ seed a pure Fourier mode, evolve it, and check the numerically
23
+ observed growth rate against the closed-form dispersion relation."""
24
+ Lx = 2 * np.pi
25
+ nx = 64
26
+ x = np.linspace(0, Lx, nx, endpoint=False)
27
+ k0 = 1.0 # m = 1: k0 = 2*pi*m/Lx with Lx = 2*pi
28
+ alpha, shear, eta = 1.0, 5.0, 0.05
29
+
30
+ A0 = 1e-3 * np.cos(k0 * x)
31
+ B0 = np.zeros_like(A0)
32
+
33
+ sigma_predicted = alpha_omega_growth_rate(alpha, shear, k0, eta)
34
+ assert sigma_predicted > 0 # this test is specifically the unstable/growing case
35
+
36
+ dt = 0.01
37
+ n_steps = 600
38
+ save_every = 5
39
+ times, A_snapshots, B_snapshots = simulate_alpha_omega_dynamo(A0, B0, alpha, shear, eta, Lx, dt, n_steps, save_every)
40
+
41
+ sigma_observed = dominant_mode_growth_rate(B_snapshots, dt_save=dt * save_every)
42
+ assert sigma_observed == pytest.approx(sigma_predicted, rel=0.02)
43
+
44
+ # Cross-check against A too, and against the module's independent
45
+ # frequency formula (same magnitude as the growth rate, by construction
46
+ # of the dispersion relation s^2 = i*alpha*shear*k).
47
+ sigma_observed_A = dominant_mode_growth_rate(A_snapshots, dt_save=dt * save_every)
48
+ assert sigma_observed_A == pytest.approx(sigma_predicted, rel=0.02)
49
+ omega_freq = alpha_omega_wave_frequency(alpha, shear, k0)
50
+ assert omega_freq == pytest.approx(np.sqrt(alpha * shear * k0 / 2.0), rel=1e-10)
51
+
52
+
53
+ def test_alpha_omega_dispersion_relation_holds_for_several_wavenumbers():
54
+ """The closed-form growth rate and wave-frequency magnitude must agree
55
+ (they're the real and imaginary parts of the same complex root)."""
56
+ alpha, shear, eta = 0.8, 3.0, 0.1
57
+ k = np.array([0.5, 1.0, 2.0, 3.0])
58
+ sigma = alpha_omega_growth_rate(alpha, shear, k, eta)
59
+ freq = alpha_omega_wave_frequency(alpha, shear, k)
60
+ assert freq == pytest.approx(sigma + eta * k**2, rel=1e-10)
61
+
62
+
63
+ def test_alpha_omega_dynamo_decays_in_stable_regime():
64
+ """Large diffusivity relative to alpha*shear*k should make the
65
+ dispersion relation predict decay, and the simulated field energy
66
+ should actually decay."""
67
+ Lx = 2 * np.pi
68
+ nx = 64
69
+ x = np.linspace(0, Lx, nx, endpoint=False)
70
+ k0 = 1.0
71
+ alpha, shear, eta = 1.0, 1.0, 2.0
72
+
73
+ sigma_predicted = alpha_omega_growth_rate(alpha, shear, k0, eta)
74
+ assert sigma_predicted < 0 # this test is specifically the stable/decaying case
75
+
76
+ A0 = 1e-3 * np.cos(k0 * x)
77
+ B0 = np.zeros_like(A0)
78
+ dt = 0.01
79
+ n_steps = 600
80
+ save_every = 5
81
+ times, A_snapshots, B_snapshots = simulate_alpha_omega_dynamo(A0, B0, alpha, shear, eta, Lx, dt, n_steps, save_every)
82
+
83
+ initial_energy = np.sum(A_snapshots[0] ** 2 + B_snapshots[0] ** 2)
84
+ final_energy = np.sum(A_snapshots[-1] ** 2 + B_snapshots[-1] ** 2)
85
+ assert final_energy < initial_energy
86
+
87
+
88
+ def test_simulate_alpha_omega_dynamo_shapes_and_finiteness():
89
+ Lx = 2 * np.pi
90
+ nx = 40
91
+ x = np.linspace(0, Lx, nx, endpoint=False)
92
+ A0 = 1e-3 * np.cos(2 * x)
93
+ B0 = np.zeros_like(A0)
94
+ times, A_snapshots, B_snapshots = simulate_alpha_omega_dynamo(A0, B0, alpha=1.0, shear=2.0, eta=0.1, Lx=Lx, dt=0.02, n_steps=30, save_every=3)
95
+ n_saved = 30 // 3 + 1
96
+ assert times.shape == (n_saved,)
97
+ assert A_snapshots.shape == (n_saved, nx)
98
+ assert B_snapshots.shape == (n_saved, nx)
99
+ assert np.all(np.isfinite(A_snapshots))
100
+ assert np.all(np.isfinite(B_snapshots))
101
+ assert A_snapshots[0] == pytest.approx(A0)
102
+ assert B_snapshots[0] == pytest.approx(B0)
103
+
104
+
105
+ def test_alpha_omega_growth_rate_vectorizes_over_k():
106
+ k = np.array([0.0, 1.0, 2.0, 4.0])
107
+ sigma = alpha_omega_growth_rate(alpha=1.0, shear=2.0, k=k, eta=0.1)
108
+ assert sigma.shape == (4,)
109
+ # k=0: no alpha-omega drive at all, growth rate is exactly zero (no diffusion either, at k=0).
110
+ assert sigma[0] == pytest.approx(0.0)
111
+
112
+
113
+ def test_dominant_mode_growth_rate_recovers_known_slope():
114
+ t = np.arange(20) * 0.1
115
+ sigma_true = 1.7
116
+ A_snapshots = np.exp(sigma_true * t)[:, None] * np.ones((20, 6))
117
+ sigma_fit = dominant_mode_growth_rate(A_snapshots, dt_save=0.1)
118
+ assert sigma_fit == pytest.approx(sigma_true, rel=1e-6)
119
+
120
+
121
+ # ---------------------------------------------------------------------------
122
+ # Part 1: 2D convective rolls
123
+ # ---------------------------------------------------------------------------
124
+
125
+
126
+ @pytest.mark.slow
127
+ @pytest.mark.parametrize("seed", [0, 1])
128
+ def test_convection_grows_and_stays_finite(seed):
129
+ """Small random noise should grow into sustained convective motion
130
+ (kinetic energy at the end of the run meaningfully larger than at the
131
+ start) without ever producing NaN/Inf, for at least two random seeds."""
132
+ nx = ny = 32
133
+ Lx = Ly = 2 * np.pi
134
+ times, omega_snapshots, T_snapshots = simulate_stellar_convection(nx, ny, Lx, Ly, n_steps=2000, seed=seed)
135
+
136
+ assert np.all(np.isfinite(omega_snapshots))
137
+ assert np.all(np.isfinite(T_snapshots))
138
+
139
+ _, _, KX, KY, K2 = _spectral_grid_2d(nx, ny, Lx, Ly)
140
+ KE_initial = kinetic_energy(omega_snapshots[0], KX, KY, K2)
141
+ KE_final = kinetic_energy(omega_snapshots[-1], KX, KY, K2)
142
+ assert KE_final > 100.0 * KE_initial
143
+
144
+
145
+ def test_convective_roll_rhs_shapes():
146
+ nx = ny = 32
147
+ Lx = Ly = 2 * np.pi
148
+ _, Y, KX, KY, K2 = _spectral_grid_2d(nx, ny, Lx, Ly)
149
+ rng = np.random.default_rng(0)
150
+ omega = 1e-3 * rng.standard_normal((ny, nx))
151
+ T = 1e-3 * rng.standard_normal((ny, nx))
152
+ domega_dt, dT_dt = convective_roll_rhs(omega, T, Y, KX, KY, K2, nu=0.05, kappa=0.05, g_alpha=1.0, beta=1.0, Ly=Ly, tau_relax=0.5)
153
+ assert domega_dt.shape == (ny, nx)
154
+ assert dT_dt.shape == (ny, nx)
155
+ assert np.all(np.isfinite(domega_dt))
156
+ assert np.all(np.isfinite(dT_dt))
157
+
158
+
159
+ def test_convective_roll_rhs_relaxation_pulls_uniform_zero_field_toward_teq():
160
+ """With zero velocity and zero perturbation temperature, the only
161
+ surviving term in dT'/dt is the Newtonian-cooling relaxation toward
162
+ Teq(y); check its sign and magnitude directly against the formula."""
163
+ nx = ny = 16
164
+ Lx = Ly = 2 * np.pi
165
+ _, Y, KX, KY, K2 = _spectral_grid_2d(nx, ny, Lx, Ly)
166
+ omega = np.zeros((ny, nx))
167
+ T = np.zeros((ny, nx))
168
+ beta, tau_relax = 2.0, 0.5
169
+ _, dT_dt = convective_roll_rhs(omega, T, Y, KX, KY, K2, nu=0.05, kappa=0.05, g_alpha=1.0, beta=beta, Ly=Ly, tau_relax=tau_relax)
170
+ Teq = -beta * np.cos(2 * np.pi * Y / Ly)
171
+ expected = Teq / tau_relax
172
+ assert dT_dt == pytest.approx(expected, abs=1e-10)
173
+
174
+
175
+ def test_simulate_stellar_convection_shapes():
176
+ nx, ny = 24, 32
177
+ Lx, Ly = 2 * np.pi, 3.0
178
+ n_steps, save_every = 20, 5
179
+ times, omega_snapshots, T_snapshots = simulate_stellar_convection(nx, ny, Lx, Ly, n_steps=n_steps, save_every=save_every, seed=0)
180
+ n_saved = n_steps // save_every + 1
181
+ assert times.shape == (n_saved,)
182
+ assert omega_snapshots.shape == (n_saved, ny, nx)
183
+ assert T_snapshots.shape == (n_saved, ny, nx)
184
+
185
+
186
+ def test_kinetic_energy_of_zero_vorticity_is_zero():
187
+ nx = ny = 32
188
+ Lx = Ly = 2 * np.pi
189
+ _, _, KX, KY, K2 = _spectral_grid_2d(nx, ny, Lx, Ly)
190
+ assert kinetic_energy(np.zeros((ny, nx)), KX, KY, K2) == 0.0
191
+
192
+
193
+ def test_kinetic_energy_positive_for_nonzero_vorticity():
194
+ nx = ny = 32
195
+ Lx = Ly = 2 * np.pi
196
+ X, Y, KX, KY, K2 = _spectral_grid_2d(nx, ny, Lx, Ly)
197
+ omega = np.sin(X) * np.cos(Y)
198
+ assert kinetic_energy(omega, KX, KY, K2) > 0.0
@@ -0,0 +1,52 @@
1
+ import numpy as np
2
+ import pytest
3
+
4
+ from physicskit.astro.stellar_structure import (
5
+ PolytropicStar,
6
+ chandrasekhar_mass,
7
+ lane_emden,
8
+ main_sequence_luminosity,
9
+ )
10
+
11
+
12
+ def test_lane_emden_n0_matches_analytic_solution():
13
+ xi, theta = lane_emden(0.0)
14
+ assert xi[-1] == pytest.approx(np.sqrt(6.0), rel=1e-3)
15
+ # analytic: theta(xi) = 1 - xi^2/6
16
+ analytic = 1.0 - xi**2 / 6.0
17
+ assert theta == pytest.approx(analytic, abs=2e-3)
18
+
19
+
20
+ def test_lane_emden_n1_matches_analytic_solution():
21
+ xi, theta = lane_emden(1.0)
22
+ assert xi[-1] == pytest.approx(np.pi, rel=1e-3)
23
+ # analytic: theta(xi) = sin(xi)/xi
24
+ analytic = np.sin(xi) / xi
25
+ assert theta == pytest.approx(analytic, abs=2e-3)
26
+
27
+
28
+ def test_polytropic_star_n0_matches_uniform_sphere_mass():
29
+ star = PolytropicStar(n=0.0, K=2.5, rho_c=3.0)
30
+ uniform_mass = 4.0 / 3.0 * np.pi * star.radius**3 * star.rho_c
31
+ assert star.mass == pytest.approx(uniform_mass, rel=1e-2)
32
+
33
+
34
+ def test_polytropic_star_positive_physical_quantities():
35
+ star = PolytropicStar(n=1.5, K=1.0, rho_c=1.0)
36
+ assert star.radius > 0
37
+ assert star.mass > 0
38
+ assert star.xi1 > 0
39
+
40
+
41
+ def test_chandrasekhar_mass_near_known_value():
42
+ M = chandrasekhar_mass(2.0)
43
+ assert 1.2 < M < 1.5
44
+
45
+
46
+ def test_chandrasekhar_mass_scales_as_inverse_mu_e_squared():
47
+ assert chandrasekhar_mass(4.0) == pytest.approx(chandrasekhar_mass(2.0) / 4.0)
48
+
49
+
50
+ def test_main_sequence_luminosity_power_law():
51
+ assert main_sequence_luminosity(2.0) == pytest.approx(2.0**3.5)
52
+ assert main_sequence_luminosity(1.0) == pytest.approx(1.0)
@@ -0,0 +1,159 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+ import pytest
4
+ from matplotlib.animation import PillowWriter
5
+ from matplotlib.collections import LineCollection
6
+
7
+ from physicskit.astro.cosmic_web import lagrangian_grid, random_displacement_potential
8
+ from physicskit.astro.galactic_dynamics import circular_velocity
9
+ from physicskit.astro.nbody import NBodySystem, figure_eight_initial_conditions
10
+ from physicskit.astro.stellar_dynamo import simulate_alpha_omega_dynamo, simulate_stellar_convection
11
+ from physicskit.astro.stellar_structure import lane_emden
12
+ from physicskit.astro.visualizers import (
13
+ animate_dynamo_wave,
14
+ animate_nbody_trajectories,
15
+ animate_stellar_convection,
16
+ animate_zeldovich_collapse,
17
+ plot_dynamo_butterfly_diagram,
18
+ plot_lane_emden,
19
+ plot_nbody_trajectories,
20
+ plot_rotation_curve,
21
+ plot_zeldovich_snapshot,
22
+ )
23
+
24
+
25
+ @pytest.mark.slow
26
+ def test_animate_nbody_trajectories_figure_eight_saves_gif(tmp_path):
27
+ positions, velocities, masses = figure_eight_initial_conditions()
28
+ system = NBodySystem(positions, velocities, masses)
29
+ history = system.simulate(dt=0.002, n_steps=300)
30
+
31
+ anim = animate_nbody_trajectories(history, skip=5)
32
+ out = tmp_path / "nbody_figure_eight.gif"
33
+ anim.save(out, writer=PillowWriter(fps=10))
34
+ assert out.exists() and out.stat().st_size > 0
35
+
36
+
37
+ def test_animate_nbody_trajectories_uses_one_collection_and_marker_per_body():
38
+ history = np.random.default_rng(1).normal(size=(50, 3, 3))
39
+
40
+ anim = animate_nbody_trajectories(history, title="N-body test")
41
+ ax = anim._fig.axes[0]
42
+ collections = [c for c in ax.collections if isinstance(c, LineCollection)]
43
+ assert len(collections) == 3
44
+ assert len(ax.lines) == 3
45
+ assert ax.get_title() == "N-body test"
46
+
47
+ anim._draw_frame(0) # a single point per body: the <2-point trail branch
48
+ assert collections[0].get_segments() == []
49
+
50
+
51
+ def test_animate_nbody_trajectories_trail_fades_with_alpha():
52
+ """The trail must actually fade: older segments more transparent than
53
+ the most recent one."""
54
+ history = np.cumsum(np.random.default_rng(2).normal(size=(100, 3, 3)), axis=0)
55
+
56
+ anim = animate_nbody_trajectories(history, trail=100)
57
+ anim._draw_frame(99)
58
+ ax = anim._fig.axes[0]
59
+ lc = next(c for c in ax.collections if isinstance(c, LineCollection))
60
+ alphas = np.asarray(lc.get_colors())[:, 3]
61
+ assert alphas[0] < alphas[-1]
62
+
63
+
64
+ def test_plot_nbody_trajectories_returns_one_line_per_body():
65
+ # A synthetic array is enough here -- plot_nbody_trajectories only
66
+ # cares about (n_steps+1, N, 3) shape, not real dynamics.
67
+ history = np.random.default_rng(0).normal(size=(10, 3, 3))
68
+
69
+ fig, ax = plot_nbody_trajectories(history)
70
+ assert isinstance(fig, plt.Figure)
71
+ assert len(ax.lines) == 3
72
+
73
+ _, ax_given = plot_nbody_trajectories(history, ax=ax)
74
+ assert ax_given is ax # reuses the supplied axes rather than creating a new figure
75
+
76
+
77
+ def test_plot_lane_emden_returns_figure():
78
+ xi, theta = lane_emden(1.5, n_points=50)
79
+ fig, ax = plot_lane_emden(xi, theta)
80
+ assert isinstance(fig, plt.Figure)
81
+ assert len(ax.lines) == 2 # theta(xi) curve + the axhline(0) reference line
82
+ assert len(ax.collections) == 1 # the surface-point scatter
83
+
84
+ _, ax_given = plot_lane_emden(xi, theta, ax=ax)
85
+ assert ax_given is ax
86
+
87
+
88
+ def test_plot_rotation_curve_with_and_without_observed_data():
89
+ r = np.linspace(1.0, 10.0, 10)
90
+ v_model = circular_velocity(r, lambda rr: 1.0)
91
+
92
+ fig1, ax1 = plot_rotation_curve(r, v_model)
93
+ assert isinstance(fig1, plt.Figure)
94
+ assert len(ax1.collections) == 0 # no scatter without observed data
95
+
96
+ fig2, ax2 = plot_rotation_curve(r, v_model, v_observed=v_model * 1.1)
97
+ assert isinstance(fig2, plt.Figure)
98
+ assert len(ax2.collections) == 1 # scatter added for observed data
99
+
100
+ _, ax_given = plot_rotation_curve(r, v_model, ax=ax1)
101
+ assert ax_given is ax1
102
+
103
+
104
+ def _small_zeldovich_field():
105
+ q = lagrangian_grid(5, 1.0)
106
+ k_vectors, amplitudes, phases = random_displacement_potential(4, k_min=2 * np.pi, k_max=6 * np.pi, amplitude_scale=0.02, seed=0)
107
+ return q, k_vectors, amplitudes, phases
108
+
109
+
110
+ def test_animate_zeldovich_collapse_builds_and_draws_a_frame():
111
+ q, k_vectors, amplitudes, phases = _small_zeldovich_field()
112
+ D_values = np.linspace(0.0, 0.1, 3)
113
+ anim = animate_zeldovich_collapse(q, D_values, k_vectors, amplitudes, phases)
114
+ anim._draw_frame(1)
115
+ assert anim._fig.axes[0].collections # the density-colored scatter exists
116
+
117
+
118
+ def test_plot_zeldovich_snapshot_returns_figure():
119
+ q, k_vectors, amplitudes, phases = _small_zeldovich_field()
120
+ fig, ax = plot_zeldovich_snapshot(q, 0.05, k_vectors, amplitudes, phases)
121
+ assert isinstance(fig, plt.Figure)
122
+ assert ax.collections
123
+
124
+ _, ax_given = plot_zeldovich_snapshot(q, 0.05, k_vectors, amplitudes, phases, ax=ax)
125
+ assert ax_given is ax
126
+
127
+
128
+ @pytest.mark.slow
129
+ def test_animate_stellar_convection_builds_and_draws_a_frame():
130
+ times, omega_snaps, T_snaps = simulate_stellar_convection(16, 16, 2 * np.pi, 2 * np.pi, n_steps=20, save_every=10, seed=0)
131
+ anim = animate_stellar_convection(times, omega_snaps, T_snaps)
132
+ anim._draw_frame(1)
133
+ ax_omega, ax_T = anim._fig.axes[0], anim._fig.axes[1]
134
+ assert len(ax_omega.images) == 1 and len(ax_T.images) == 1
135
+
136
+
137
+ def test_animate_dynamo_wave_builds_and_draws_a_frame():
138
+ Lx = 2 * np.pi
139
+ x = np.linspace(0, Lx, 16, endpoint=False)
140
+ A0 = 1e-3 * np.cos(x)
141
+ B0 = np.zeros_like(A0)
142
+ times, A_snaps, B_snaps = simulate_alpha_omega_dynamo(A0, B0, alpha=1.0, shear=5.0, eta=0.05, Lx=Lx, dt=0.01, n_steps=20, save_every=5)
143
+ anim = animate_dynamo_wave(times, A_snaps, B_snaps, x)
144
+ anim._draw_frame(1)
145
+ assert len(anim._fig.axes[0].lines) == 2 # A(x) and B(x)
146
+
147
+
148
+ def test_plot_dynamo_butterfly_diagram_returns_figure():
149
+ Lx = 2 * np.pi
150
+ x = np.linspace(0, Lx, 16, endpoint=False)
151
+ A0 = 1e-3 * np.cos(x)
152
+ B0 = np.zeros_like(A0)
153
+ times, A_snaps, B_snaps = simulate_alpha_omega_dynamo(A0, B0, alpha=1.0, shear=5.0, eta=0.05, Lx=Lx, dt=0.01, n_steps=20, save_every=5)
154
+ fig, ax = plot_dynamo_butterfly_diagram(times, B_snaps, x)
155
+ assert isinstance(fig, plt.Figure)
156
+ assert ax.collections
157
+
158
+ _, ax_given = plot_dynamo_butterfly_diagram(times, B_snaps, x, ax=ax)
159
+ assert ax_given is ax