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,705 @@
1
+ r"""Animations for the ten toy "collider physics" demonstrations built on
2
+ top of :mod:`physicskit.particle`'s decay, scattering, shower,
3
+ confinement, electroweak, and neutrino-oscillation models.
4
+
5
+ Every function here returns a :class:`matplotlib.animation.FuncAnimation`
6
+ (built with ``blit=False`` throughout, since several of these redraw
7
+ variable-length or variable-count artists each frame); save it with
8
+ e.g. ``anim.save(path, writer=PillowWriter(fps=10))``.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import matplotlib.pyplot as plt
14
+ import numpy as np
15
+ from matplotlib.animation import FuncAnimation
16
+ from matplotlib.patches import Circle
17
+
18
+ from physicskit.particle.collider import charged_track_points, cluster_into_jets, flatten_shower, shower_leaves
19
+ from physicskit.particle.decays import michel_spectrum
20
+ from physicskit.particle.electroweak import cp_asymmetry, higgs_potential
21
+ from physicskit.particle.electroweak import qed_dsigma_domega_mumu as _qed_dsigma_domega_mumu
22
+ from physicskit.particle.neutrinos import oscillation_probability
23
+ from physicskit.particle.scattering import ALPHA_FS
24
+
25
+ __all__ = [
26
+ "animate_particle_cascade",
27
+ "animate_parton_shower",
28
+ "animate_detector_event",
29
+ "animate_string_breaking",
30
+ "animate_higgs_rollover",
31
+ "animate_decay_chain_bars",
32
+ "animate_neutrino_oscillation",
33
+ "animate_qed_angular_distribution",
34
+ "animate_michel_histogram",
35
+ "animate_cp_asymmetry",
36
+ ]
37
+
38
+
39
+ # ---------------------------------------------------------------------------
40
+ # Items 1 & 7: shower / parton-shower tree animation (shared machinery)
41
+ # ---------------------------------------------------------------------------
42
+
43
+
44
+ def _layout_shower_positions(root, track_length):
45
+ """Map each non-root node to a (start, end) 2D transverse-plane segment,
46
+ walking outward from the collision vertex at the origin."""
47
+ positions = {}
48
+
49
+ def walk(node, start):
50
+ for child in node.children:
51
+ px, py = child.four_vector.px, child.four_vector.py
52
+ pt = float(np.hypot(px, py))
53
+ direction = np.array([px, py]) / pt if pt > 1e-9 else np.array([1.0, 0.0])
54
+ end = start + track_length * direction
55
+ positions[id(child)] = (start, end)
56
+ walk(child, end)
57
+
58
+ walk(root, np.array([0.0, 0.0]))
59
+ return positions
60
+
61
+
62
+ def _animate_shower_tree(root, detector_radii, track_length, interval, ax, color_func, extra_static=None):
63
+ positions = _layout_shower_positions(root, track_length)
64
+ nodes = [n for n in flatten_shower(root) if n.parent is not None]
65
+ nodes.sort(key=lambda n: n.generation)
66
+
67
+ if ax is None:
68
+ fig, ax = plt.subplots()
69
+ else:
70
+ fig = ax.figure
71
+ R_track, R_calo = detector_radii
72
+ ax.add_patch(Circle((0, 0), R_track, fill=False, linestyle="--", color="steelblue"))
73
+ ax.add_patch(Circle((0, 0), R_calo, fill=False, linestyle="-", color="firebrick"))
74
+ if extra_static is not None:
75
+ extra_static(ax, R_calo)
76
+ ax.set_xlim(-R_calo * 1.15, R_calo * 1.15)
77
+ ax.set_ylim(-R_calo * 1.15, R_calo * 1.15)
78
+ ax.set_aspect("equal")
79
+ ax.plot(0, 0, "k*", markersize=10)
80
+
81
+ lines = [ax.plot([], [], lw=1.6, color=color_func(n))[0] for n in nodes]
82
+ (markers,) = ax.plot([], [], "o", color="black", markersize=3)
83
+
84
+ def update(frame):
85
+ visible = nodes[: frame + 1]
86
+ for line, node in zip(lines, nodes):
87
+ if node in visible:
88
+ s, e = positions[id(node)]
89
+ line.set_data([s[0], e[0]], [s[1], e[1]])
90
+ ends = np.array([positions[id(n)][1] for n in visible]) if visible else np.empty((0, 2))
91
+ if len(ends):
92
+ markers.set_data(ends[:, 0], ends[:, 1])
93
+ return [*lines, markers]
94
+
95
+ return FuncAnimation(fig, update, frames=max(len(nodes), 1), interval=interval, blit=False)
96
+
97
+
98
+ def animate_particle_cascade(root, detector_radii=(3.0, 6.0), track_length=0.6, interval=150, ax=None):
99
+ """Animate a toy shower cascade (:func:`physicskit.particle.collider.simple_shower`)
100
+ propagating outward from the collision vertex through a schematic detector.
101
+
102
+ Concentric circles mark a "tracker" (inner) and "calorimeter" (outer)
103
+ region; each branch of the shower tree appears as one more track
104
+ segment per frame, in order of production (generation).
105
+
106
+ Parameters
107
+ ----------
108
+ root : physicskit.particle.collider.ShowerParticle
109
+ Root of the shower tree, e.g. from
110
+ :func:`physicskit.particle.collider.simple_shower`.
111
+ detector_radii : (float, float), default=(3.0, 6.0)
112
+ Radii of the schematic tracker and calorimeter circles.
113
+ track_length : float, default=0.6
114
+ Schematic (not physically derived) drawn length of each track
115
+ segment -- purely a layout choice, not a decay-length calculation.
116
+ interval : int, default=150
117
+ Delay between frames, in milliseconds.
118
+ ax : matplotlib.axes.Axes, optional
119
+ Axes to draw into; a new figure is created if omitted.
120
+
121
+ Returns
122
+ -------
123
+ matplotlib.animation.FuncAnimation
124
+
125
+ Examples
126
+ --------
127
+ >>> import numpy as np
128
+ >>> from physicskit.particle.collider import simple_shower
129
+ >>> root = simple_shower(50.0, E_threshold=5.0, rng=np.random.default_rng(0))
130
+ >>> anim = animate_particle_cascade(root)
131
+ >>> anim.__class__.__name__
132
+ 'FuncAnimation'
133
+ """
134
+ return _animate_shower_tree(
135
+ root,
136
+ detector_radii,
137
+ track_length,
138
+ interval,
139
+ ax,
140
+ color_func=lambda n: plt.cm.plasma(min(n.generation / 6.0, 1.0)),
141
+ )
142
+
143
+
144
+ def animate_parton_shower(root, detector_radii=(3.0, 6.0), track_length=0.6, n_jets=2, interval=150, ax=None):
145
+ """Animate a toy parton shower (:func:`physicskit.particle.collider.parton_shower`)
146
+ developing into jets.
147
+
148
+ Reuses the tree-reveal machinery of :func:`animate_particle_cascade`,
149
+ color-coding branches by parton flavor (quark/antiquark vs. gluon)
150
+ and overlaying the final jet-axis directions found by
151
+ :func:`physicskit.particle.collider.cluster_into_jets`.
152
+
153
+ Parameters
154
+ ----------
155
+ root : physicskit.particle.collider.ShowerParticle
156
+ Root of the parton shower tree.
157
+ detector_radii, track_length, interval, ax
158
+ See :func:`animate_particle_cascade`.
159
+ n_jets : int, default=2
160
+ Number of jet cones to cluster the final state into and overlay.
161
+
162
+ Returns
163
+ -------
164
+ matplotlib.animation.FuncAnimation
165
+
166
+ Examples
167
+ --------
168
+ >>> import numpy as np
169
+ >>> from physicskit.particle.collider import parton_shower
170
+ >>> root = parton_shower(50.0, E_threshold=5.0, rng=np.random.default_rng(0))
171
+ >>> anim = animate_parton_shower(root)
172
+ >>> anim.__class__.__name__
173
+ 'FuncAnimation'
174
+ """
175
+ flavor_colors = {"q": "royalblue", "qbar": "seagreen", "g": "firebrick", "": "gray"}
176
+ leaves = shower_leaves(root)
177
+ jets = cluster_into_jets(leaves, n_jets=n_jets) if len(leaves) >= n_jets else []
178
+
179
+ def extra_static(ax, R_calo):
180
+ for jet in jets:
181
+ if not jet:
182
+ continue
183
+ px = np.mean([leaf.four_vector.px for leaf in jet])
184
+ py = np.mean([leaf.four_vector.py for leaf in jet])
185
+ pt = np.hypot(px, py)
186
+ if pt > 1e-9:
187
+ ax.plot([0, R_calo * px / pt], [0, R_calo * py / pt], "--", color="black", alpha=0.4, lw=1.0)
188
+
189
+ return _animate_shower_tree(
190
+ root,
191
+ detector_radii,
192
+ track_length,
193
+ interval,
194
+ ax,
195
+ color_func=lambda n: flavor_colors.get(n.flavor, "gray"),
196
+ extra_static=extra_static,
197
+ )
198
+
199
+
200
+ # ---------------------------------------------------------------------------
201
+ # Item 10: detector event display
202
+ # ---------------------------------------------------------------------------
203
+
204
+
205
+ def animate_detector_event(four_vectors, charges, B, detector_radii=(3.0, 6.0), n_frames=60, interval=100, ax=None):
206
+ r"""Animate final-state tracks growing outward from the vertex and
207
+ landing in a schematic calorimeter.
208
+
209
+ Charged particles curve (radius :math:`r=p_T/(qB)`, see
210
+ :func:`physicskit.particle.collider.charged_track_points`); neutral
211
+ particles fly in straight lines. Each frame reveals one more step
212
+ along every track; a marker is drawn at each track's current
213
+ endpoint, standing in for a calorimeter energy deposit once the
214
+ track reaches the outer radius.
215
+
216
+ Parameters
217
+ ----------
218
+ four_vectors : sequence of physicskit.particle.kinematics.FourVector
219
+ Final-state particles.
220
+ charges : sequence of float
221
+ Charge of each particle, in units of the elementary charge.
222
+ B : float
223
+ Magnetic field strength (see
224
+ :func:`~physicskit.particle.collider.charged_track_points`).
225
+ detector_radii : (float, float), default=(3.0, 6.0)
226
+ Radii of the schematic tracker and calorimeter circles.
227
+ n_frames : int, default=60
228
+ Number of animation frames (and points sampled along each track).
229
+ interval : int, default=100
230
+ Delay between frames, in milliseconds.
231
+ ax : matplotlib.axes.Axes, optional
232
+ Axes to draw into; a new figure is created if omitted.
233
+
234
+ Returns
235
+ -------
236
+ matplotlib.animation.FuncAnimation
237
+
238
+ Examples
239
+ --------
240
+ >>> from physicskit.particle.kinematics import FourVector
241
+ >>> ps = [FourVector(5.0, 3.0, 0.0, 3.0), FourVector(4.0, 0.0, 3.0, 2.0)]
242
+ >>> anim = animate_detector_event(ps, charges=[1.0, -1.0], B=1.0)
243
+ >>> anim.__class__.__name__
244
+ 'FuncAnimation'
245
+ """
246
+ R_track, R_calo = detector_radii
247
+ tracks = [charged_track_points(p, q, B, n_points=n_frames, path_length=R_calo * 1.3) for p, q in zip(four_vectors, charges)]
248
+
249
+ if ax is None:
250
+ fig, ax = plt.subplots()
251
+ else:
252
+ fig = ax.figure
253
+ ax.add_patch(Circle((0, 0), R_track, fill=False, linestyle="--", color="steelblue"))
254
+ ax.add_patch(Circle((0, 0), R_calo, fill=False, color="firebrick"))
255
+ ax.set_xlim(-R_calo * 1.15, R_calo * 1.15)
256
+ ax.set_ylim(-R_calo * 1.15, R_calo * 1.15)
257
+ ax.set_aspect("equal")
258
+ ax.plot(0, 0, "k*", markersize=10)
259
+
260
+ colors = ["crimson" if q > 0 else ("royalblue" if q < 0 else "gray") for q in charges]
261
+ lines = [ax.plot([], [], lw=1.8, color=c)[0] for c in colors]
262
+ (deposits,) = ax.plot([], [], "s", color="darkorange", markersize=7)
263
+
264
+ def update(frame):
265
+ ends = []
266
+ for line, track in zip(lines, tracks):
267
+ pts = track[: frame + 2]
268
+ line.set_data(pts[:, 0], pts[:, 1])
269
+ ends.append(pts[-1])
270
+ ends = np.array(ends)
271
+ deposits.set_data(ends[:, 0], ends[:, 1])
272
+ return [*lines, deposits]
273
+
274
+ return FuncAnimation(fig, update, frames=n_frames, interval=interval, blit=False)
275
+
276
+
277
+ # ---------------------------------------------------------------------------
278
+ # Item 2: quark confinement / string breaking
279
+ # ---------------------------------------------------------------------------
280
+
281
+
282
+ def animate_string_breaking(sim, interval=120, ax=None):
283
+ r"""Animate a receding quark pair's confining string stretching and
284
+ breaking, from :func:`physicskit.particle.confinement.string_break_chain`.
285
+
286
+ A thick line (whose width and color track the stored tension,
287
+ ``energy_per_segment``) stretches between the two receding quark
288
+ markers; each time the simulation records a break, it snaps into
289
+ one more, shorter segment, with a new marker appearing at each
290
+ newly created quark-antiquark endpoint. (The endpoints of the
291
+ ``n_segments(t)`` current strings are drawn evenly spaced across the
292
+ current total extent -- a schematic simplification, see
293
+ :func:`~physicskit.particle.confinement.string_break_chain`'s
294
+ docstring, rather than tracking each new pair's exact, individually
295
+ frozen creation position.)
296
+
297
+ Parameters
298
+ ----------
299
+ sim : dict
300
+ Output of :func:`physicskit.particle.confinement.string_break_chain`.
301
+ interval : int, default=120
302
+ Delay between frames, in milliseconds.
303
+ ax : matplotlib.axes.Axes, optional
304
+ Axes to draw into; a new figure is created if omitted.
305
+
306
+ Returns
307
+ -------
308
+ matplotlib.animation.FuncAnimation
309
+
310
+ Examples
311
+ --------
312
+ >>> import numpy as np
313
+ >>> from physicskit.particle.confinement import string_break_chain
314
+ >>> sim = string_break_chain(np.linspace(0, 10, 40), v=0.3, kappa=1.0, m_q=1.0, n_breaks=2)
315
+ >>> anim = animate_string_breaking(sim)
316
+ >>> anim.__class__.__name__
317
+ 'FuncAnimation'
318
+ """
319
+ t, r, n_segments, energy_per_segment = sim["t"], sim["r"], sim["n_segments"], sim["energy_per_segment"]
320
+ m_q = sim["m_q"]
321
+ max_segments = int(n_segments.max())
322
+
323
+ if ax is None:
324
+ fig, ax = plt.subplots(figsize=(7, 2.5))
325
+ else:
326
+ fig = ax.figure
327
+ rmax = r.max() * 0.55 + 1e-9
328
+ ax.set_xlim(-rmax, rmax)
329
+ ax.set_ylim(-1.0, 1.0)
330
+ ax.set_yticks([])
331
+ ax.set_xlabel("separation")
332
+ ax.set_title("QCD string breaking")
333
+
334
+ lines = [ax.plot([], [], lw=3, solid_capstyle="round", color="darkorange")[0] for _ in range(max_segments)]
335
+ (endpoints,) = ax.plot([], [], "o", color="black", markersize=7)
336
+
337
+ def update(frame):
338
+ n = int(n_segments[frame])
339
+ half = r[frame] / 2.0
340
+ xs = np.linspace(-half, half, n + 1)
341
+ tension = min(energy_per_segment[frame] / (2.0 * m_q), 1.0)
342
+ for i, line in enumerate(lines):
343
+ if i < n:
344
+ line.set_data([xs[i], xs[i + 1]], [0.0, 0.0])
345
+ line.set_color(plt.cm.inferno(0.2 + 0.6 * tension))
346
+ line.set_linewidth(1.0 + 4.0 * tension)
347
+ else:
348
+ line.set_data([], [])
349
+ endpoints.set_data(xs, np.zeros_like(xs))
350
+ return [*lines, endpoints]
351
+
352
+ return FuncAnimation(fig, update, frames=len(t), interval=interval, blit=False)
353
+
354
+
355
+ # ---------------------------------------------------------------------------
356
+ # Item 3: Higgs mechanism (classical rollover)
357
+ # ---------------------------------------------------------------------------
358
+
359
+
360
+ def animate_higgs_rollover(phi_t, a, b, interval=30, ax=None):
361
+ r"""Animate a scalar field rolling from the unstable symmetric point
362
+ into a broken-symmetry vacuum, from
363
+ :func:`physicskit.particle.electroweak.higgs_field_rollover`.
364
+
365
+ The static curve is :func:`physicskit.particle.electroweak.higgs_potential`;
366
+ a point (with a fading trail) traces :math:`(\phi(t), V(\phi(t)))` as
367
+ the field rolls down one side of the double well.
368
+
369
+ Parameters
370
+ ----------
371
+ phi_t : ndarray
372
+ Field trajectory :math:`\phi(t)`, e.g. the first output of
373
+ :func:`~physicskit.particle.electroweak.higgs_field_rollover`.
374
+ a, b : float
375
+ Potential parameters, see
376
+ :func:`~physicskit.particle.electroweak.higgs_potential`.
377
+ interval : int, default=30
378
+ Delay between frames, in milliseconds.
379
+ ax : matplotlib.axes.Axes, optional
380
+ Axes to draw into; a new figure is created if omitted.
381
+
382
+ Returns
383
+ -------
384
+ matplotlib.animation.FuncAnimation
385
+
386
+ Examples
387
+ --------
388
+ >>> import numpy as np
389
+ >>> from physicskit.particle.electroweak import higgs_field_rollover
390
+ >>> t = np.linspace(0, 40, 100)
391
+ >>> phi, _ = higgs_field_rollover(1e-3, 0.0, a=1.0, b=1.0, t_eval=t, damping=0.05)
392
+ >>> anim = animate_higgs_rollover(phi, a=1.0, b=1.0)
393
+ >>> anim.__class__.__name__
394
+ 'FuncAnimation'
395
+ """
396
+ span = 1.3 * np.max(np.abs(phi_t)) + 0.1
397
+ phi_range = np.linspace(-span, span, 400)
398
+ V = higgs_potential(phi_range, a, b)
399
+
400
+ if ax is None:
401
+ fig, ax = plt.subplots()
402
+ else:
403
+ fig = ax.figure
404
+ ax.plot(phi_range, V, color="gray", lw=1.5)
405
+ ax.set_xlabel(r"$\phi$")
406
+ ax.set_ylabel(r"$V(\phi)$")
407
+ ax.set_title("Classical symmetry breaking")
408
+ (point,) = ax.plot([], [], "o", color="crimson", markersize=8)
409
+ (trace,) = ax.plot([], [], color="crimson", lw=1.0, alpha=0.5)
410
+
411
+ def update(frame):
412
+ phi = phi_t[: frame + 1]
413
+ V_phi = higgs_potential(phi, a, b)
414
+ trace.set_data(phi, V_phi)
415
+ point.set_data([phi[-1]], [V_phi[-1]])
416
+ return [point, trace]
417
+
418
+ return FuncAnimation(fig, update, frames=len(phi_t), interval=interval, blit=False)
419
+
420
+
421
+ # ---------------------------------------------------------------------------
422
+ # Item 4: decay chain population animation
423
+ # ---------------------------------------------------------------------------
424
+
425
+
426
+ def animate_decay_chain_bars(t, populations, labels=None, interval=150, ax=None):
427
+ """Animate each species' population evolving over time in a decay chain.
428
+
429
+ Parameters
430
+ ----------
431
+ t : ndarray of shape (n_t,)
432
+ Times.
433
+ populations : ndarray of shape (n_species, n_t)
434
+ Population of each species over time, e.g. from
435
+ :func:`physicskit.particle.decays.bateman_decay_chain`.
436
+ labels : sequence of str, optional
437
+ Bar labels; defaults to ``"species 1"``, ``"species 2"``, ...
438
+ interval : int, default=150
439
+ Delay between frames, in milliseconds.
440
+ ax : matplotlib.axes.Axes, optional
441
+ Axes to draw into; a new figure is created if omitted.
442
+
443
+ Returns
444
+ -------
445
+ matplotlib.animation.FuncAnimation
446
+
447
+ Examples
448
+ --------
449
+ >>> import numpy as np
450
+ >>> from physicskit.particle.decays import bateman_decay_chain
451
+ >>> t = np.linspace(0, 10, 30)
452
+ >>> N = bateman_decay_chain(1000.0, [0.5, 0.2], t)
453
+ >>> anim = animate_decay_chain_bars(t, N)
454
+ >>> anim.__class__.__name__
455
+ 'FuncAnimation'
456
+ """
457
+ populations = np.asarray(populations)
458
+ n_species = populations.shape[0]
459
+ if labels is None:
460
+ labels = [f"species {i + 1}" for i in range(n_species)]
461
+ if ax is None:
462
+ fig, ax = plt.subplots()
463
+ else:
464
+ fig = ax.figure
465
+ bars = ax.bar(labels, populations[:, 0], color=plt.cm.viridis(np.linspace(0, 1, n_species)))
466
+ ax.set_ylim(0, populations.max() * 1.05 + 1e-12)
467
+ ax.set_ylabel("population")
468
+ title = ax.set_title(f"t = {t[0]:.2f}")
469
+
470
+ def update(frame):
471
+ for bar, h in zip(bars, populations[:, frame]):
472
+ bar.set_height(h)
473
+ title.set_text(f"t = {t[frame]:.2f}")
474
+ return [*bars, title]
475
+
476
+ return FuncAnimation(fig, update, frames=len(t), interval=interval, blit=False)
477
+
478
+
479
+ # ---------------------------------------------------------------------------
480
+ # Item 5: neutrino oscillations
481
+ # ---------------------------------------------------------------------------
482
+
483
+
484
+ def animate_neutrino_oscillation(L, E, theta, delta_m2, interval=60, ax=None):
485
+ r"""Animate :math:`P(\nu_e)` and :math:`P(\nu_\mu)` growing as a
486
+ function of distance traveled, from
487
+ :func:`physicskit.particle.neutrinos.oscillation_probability`.
488
+
489
+ Parameters
490
+ ----------
491
+ L : ndarray
492
+ Baselines (distance traveled), in km, in increasing order.
493
+ E : float
494
+ Neutrino energy, in GeV.
495
+ theta : float
496
+ Mixing angle, radians.
497
+ delta_m2 : float
498
+ Mass-squared splitting, in :math:`{\rm eV}^2`.
499
+ interval : int, default=60
500
+ Delay between frames, in milliseconds.
501
+ ax : matplotlib.axes.Axes, optional
502
+ Axes to draw into; a new figure is created if omitted.
503
+
504
+ Returns
505
+ -------
506
+ matplotlib.animation.FuncAnimation
507
+
508
+ Examples
509
+ --------
510
+ >>> import numpy as np
511
+ >>> L = np.linspace(0, 1000, 100)
512
+ >>> anim = animate_neutrino_oscillation(L, E=1.0, theta=0.6, delta_m2=2.5e-3)
513
+ >>> anim.__class__.__name__
514
+ 'FuncAnimation'
515
+ """
516
+ L = np.asarray(L, dtype=float)
517
+ P_mu = oscillation_probability(L, E, theta, delta_m2)
518
+ P_e = 1.0 - P_mu
519
+
520
+ if ax is None:
521
+ fig, ax = plt.subplots()
522
+ else:
523
+ fig = ax.figure
524
+ ax.set_xlim(L.min(), L.max())
525
+ ax.set_ylim(0.0, 1.05)
526
+ ax.set_xlabel("L [km]")
527
+ ax.set_ylabel("probability")
528
+ (line_e,) = ax.plot([], [], color="steelblue", label=r"$P(\nu_e)$")
529
+ (line_mu,) = ax.plot([], [], color="firebrick", label=r"$P(\nu_\mu)$")
530
+ ax.legend(loc="upper right")
531
+
532
+ def update(frame):
533
+ line_e.set_data(L[: frame + 1], P_e[: frame + 1])
534
+ line_mu.set_data(L[: frame + 1], P_mu[: frame + 1])
535
+ return [line_e, line_mu]
536
+
537
+ return FuncAnimation(fig, update, frames=len(L), interval=interval, blit=False)
538
+
539
+
540
+ # ---------------------------------------------------------------------------
541
+ # Item 6: QED angular distribution vs. sqrt(s)
542
+ # ---------------------------------------------------------------------------
543
+
544
+
545
+ def animate_qed_angular_distribution(sqrt_s_values, alpha=ALPHA_FS, n_theta=200, interval=200, ax=None):
546
+ r"""Animate the :math:`e^+e^-\to\mu^+\mu^-` angular distribution's
547
+ shape as :math:`\sqrt s` is swept, from
548
+ :func:`physicskit.particle.electroweak.qed_dsigma_domega_mumu`.
549
+
550
+ Parameters
551
+ ----------
552
+ sqrt_s_values : ndarray
553
+ Center-of-mass energies to sweep through (one per frame).
554
+ alpha : float, default=ALPHA_FS
555
+ Fine-structure constant.
556
+ n_theta : int, default=200
557
+ Number of polar-angle samples per frame.
558
+ interval : int, default=200
559
+ Delay between frames, in milliseconds.
560
+ ax : matplotlib.axes.Axes, optional
561
+ Polar axes to draw into; new polar axes are created if omitted.
562
+
563
+ Returns
564
+ -------
565
+ matplotlib.animation.FuncAnimation
566
+
567
+ Examples
568
+ --------
569
+ >>> import numpy as np
570
+ >>> sqrt_s = np.linspace(5.0, 20.0, 20)
571
+ >>> anim = animate_qed_angular_distribution(sqrt_s)
572
+ >>> anim.__class__.__name__
573
+ 'FuncAnimation'
574
+ """
575
+ theta = np.linspace(0.0, np.pi, n_theta)
576
+ if ax is None:
577
+ fig = plt.figure()
578
+ ax = fig.add_subplot(projection="polar")
579
+ else:
580
+ fig = ax.figure
581
+ (line,) = ax.plot([], [])
582
+ title = ax.set_title("")
583
+
584
+ def update(frame):
585
+ s = sqrt_s_values[frame]
586
+ vals = _qed_dsigma_domega_mumu(np.cos(theta), s, alpha=alpha)
587
+ line.set_data(theta, vals)
588
+ ax.set_ylim(0.0, max(float(vals.max()) * 1.1, 1e-30))
589
+ title.set_text(rf"$\sqrt{{s}}={s:.2f}$")
590
+ return [line, title]
591
+
592
+ return FuncAnimation(fig, update, frames=len(sqrt_s_values), interval=interval, blit=False)
593
+
594
+
595
+ # ---------------------------------------------------------------------------
596
+ # Item 8: muon decay / Michel spectrum
597
+ # ---------------------------------------------------------------------------
598
+
599
+
600
+ def animate_michel_histogram(x_samples, batch_size=20, n_bins=30, interval=100, ax=None):
601
+ r"""Animate a histogram of sampled Michel-spectrum electron energies
602
+ building up event-by-event, converging to
603
+ :func:`physicskit.particle.decays.michel_spectrum`.
604
+
605
+ Parameters
606
+ ----------
607
+ x_samples : ndarray
608
+ Sampled scaled electron energies, e.g. from
609
+ :func:`physicskit.particle.decays.sample_michel_electron_energies`.
610
+ batch_size : int, default=20
611
+ Number of additional samples revealed per frame.
612
+ n_bins : int, default=30
613
+ Number of histogram bins.
614
+ interval : int, default=100
615
+ Delay between frames, in milliseconds.
616
+ ax : matplotlib.axes.Axes, optional
617
+ Axes to draw into; a new figure is created if omitted.
618
+
619
+ Returns
620
+ -------
621
+ matplotlib.animation.FuncAnimation
622
+
623
+ Examples
624
+ --------
625
+ >>> import numpy as np
626
+ >>> from physicskit.particle.decays import sample_michel_electron_energies
627
+ >>> xs = sample_michel_electron_energies(500, rng=np.random.default_rng(0))
628
+ >>> anim = animate_michel_histogram(xs, batch_size=100)
629
+ >>> anim.__class__.__name__
630
+ 'FuncAnimation'
631
+ """
632
+ if ax is None:
633
+ fig, ax = plt.subplots()
634
+ else:
635
+ fig = ax.figure
636
+ x_theory = np.linspace(0.0, 1.0, 200)
637
+ y_theory = michel_spectrum(x_theory)
638
+ n_frames = int(np.ceil(len(x_samples) / batch_size))
639
+
640
+ def update(frame):
641
+ ax.cla()
642
+ ax.plot(x_theory, y_theory, color="black", lw=2, label="Michel spectrum")
643
+ n = min((frame + 1) * batch_size, len(x_samples))
644
+ ax.hist(x_samples[:n], bins=n_bins, range=(0.0, 1.0), density=True, color="steelblue", alpha=0.7, label=f"N={n}")
645
+ ax.set_xlabel(r"$x=2E_e/m_\mu$")
646
+ ax.set_ylabel(r"$d\Gamma/dx$")
647
+ ax.set_ylim(0.0, max(2.2, y_theory.max() * 1.2))
648
+ ax.legend(loc="upper left")
649
+ return []
650
+
651
+ return FuncAnimation(fig, update, frames=n_frames, interval=interval, blit=False)
652
+
653
+
654
+ # ---------------------------------------------------------------------------
655
+ # Item 9: CP violation
656
+ # ---------------------------------------------------------------------------
657
+
658
+
659
+ def animate_cp_asymmetry(t, delta_m, gamma_s, gamma_l, epsilon, interval=60, ax=None):
660
+ r"""Animate the neutral-meson decay-rate CP asymmetry :math:`A(t)`
661
+ building up, from :func:`physicskit.particle.electroweak.cp_asymmetry`.
662
+
663
+ Parameters
664
+ ----------
665
+ t : ndarray
666
+ Times.
667
+ delta_m, gamma_s, gamma_l, epsilon
668
+ See :func:`physicskit.particle.electroweak.meson_decay_rates_cp_eigenstate`.
669
+ interval : int, default=60
670
+ Delay between frames, in milliseconds.
671
+ ax : matplotlib.axes.Axes, optional
672
+ Axes to draw into; a new figure is created if omitted.
673
+
674
+ Returns
675
+ -------
676
+ matplotlib.animation.FuncAnimation
677
+
678
+ Examples
679
+ --------
680
+ >>> import numpy as np
681
+ >>> t = np.linspace(0, 20, 100)
682
+ >>> anim = animate_cp_asymmetry(t, delta_m=0.5, gamma_s=1.0, gamma_l=0.1, epsilon=0.002 + 0.001j)
683
+ >>> anim.__class__.__name__
684
+ 'FuncAnimation'
685
+ """
686
+ t = np.asarray(t, dtype=float)
687
+ A = cp_asymmetry(t, delta_m, gamma_s, gamma_l, epsilon)
688
+
689
+ if ax is None:
690
+ fig, ax = plt.subplots()
691
+ else:
692
+ fig = ax.figure
693
+ amax = float(np.max(np.abs(A))) + 1e-12
694
+ ax.set_xlim(t.min(), t.max())
695
+ ax.set_ylim(-1.15 * amax, 1.15 * amax)
696
+ ax.set_xlabel("t")
697
+ ax.set_ylabel("A(t)")
698
+ ax.set_title("CP-violating decay-rate asymmetry")
699
+ (line,) = ax.plot([], [], color="darkorange", lw=1.6)
700
+
701
+ def update(frame):
702
+ line.set_data(t[: frame + 1], A[: frame + 1])
703
+ return [line]
704
+
705
+ return FuncAnimation(fig, update, frames=len(t), interval=interval, blit=False)