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,161 @@
1
+ """Interactive Plotly visualizations.
2
+
3
+ Every other module in :mod:`physicskit.statphys.visualizers` produces static Matplotlib
4
+ figures, well suited to publication and to this documentation's example
5
+ gallery. This module offers the same information as pan/zoom/hover-enabled
6
+ Plotly figures instead -- convenient for interactively exploring a parameter
7
+ sweep or a dense vector field in a Jupyter notebook, or for embedding in a
8
+ standalone HTML page.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import numpy as np
14
+ import plotly.graph_objects as go
15
+ from plotly.subplots import make_subplots
16
+
17
+ __all__ = [
18
+ "interactive_particle_snapshot",
19
+ "interactive_temperature_sweep",
20
+ "interactive_vortex_field",
21
+ ]
22
+
23
+
24
+ def interactive_temperature_sweep(result, T_c=None):
25
+ """Build an interactive 2x2 subplot figure of a temperature sweep result.
26
+
27
+ Parameters
28
+ ----------
29
+ result : dict of str -> ndarray
30
+ Output of e.g. ``Ising2D.run_temperature_sweep`` or
31
+ ``PottsModel2D.run_temperature_sweep``.
32
+ T_c : float, optional
33
+ Critical temperature to mark with a vertical line on every panel.
34
+
35
+ Returns
36
+ -------
37
+ plotly.graph_objects.Figure
38
+ A 2x2 subplot figure with hoverable energy, order-parameter,
39
+ specific-heat, and susceptibility traces.
40
+
41
+ Examples
42
+ --------
43
+ >>> from physicskit.statphys.chapters.ising_lattice import Ising2D
44
+ >>> model = Ising2D(L=10, seed=0)
45
+ >>> result = model.run_temperature_sweep([2.0, 2.269, 2.5], n_equil=10, n_measure=10)
46
+ >>> fig = interactive_temperature_sweep(result, T_c=model.T_C)
47
+ >>> len(fig.data) > 0
48
+ True
49
+ """
50
+ T = result["T"]
51
+ panels = [
52
+ ("E", "Energy per site"),
53
+ ("M" if "M" in result else "m", "Order parameter"),
54
+ ("C_v", "Specific heat"),
55
+ ("chi", "Susceptibility"),
56
+ ]
57
+ fig = make_subplots(rows=2, cols=2, subplot_titles=[label for _, label in panels])
58
+ positions = [(1, 1), (1, 2), (2, 1), (2, 2)]
59
+ for (key, label), (row, col) in zip(panels, positions):
60
+ if key not in result:
61
+ continue
62
+ fig.add_trace(go.Scatter(x=T, y=result[key], mode="lines+markers", name=label), row=row, col=col)
63
+ if T_c is not None:
64
+ fig.add_vline(x=T_c, line_dash="dash", line_color="black", row=row, col=col)
65
+ fig.update_layout(title="Temperature sweep", showlegend=False, height=600)
66
+ return fig
67
+
68
+
69
+ def interactive_vortex_field(theta, vorticity=None, step=1):
70
+ """Build an interactive XY spin field plot with vortex/antivortex markers.
71
+
72
+ Parameters
73
+ ----------
74
+ theta : ndarray of shape (L, L)
75
+ XY model spin angles, e.g. ``XYModel2D.theta``.
76
+ vorticity : ndarray of shape (L, L), optional
77
+ Precomputed plaquette vorticity; computed from ``theta`` if omitted.
78
+ step : int, default=1
79
+ Subsampling factor for the arrow field.
80
+
81
+ Returns
82
+ -------
83
+ plotly.graph_objects.Figure
84
+ """
85
+ if vorticity is None:
86
+ from physicskit.statphys.core.monte_carlo import xy_plaquette_vorticity
87
+
88
+ vorticity = xy_plaquette_vorticity(theta)
89
+
90
+ L = theta.shape[0]
91
+ idx = np.arange(0, L, step)
92
+ ii, jj = np.meshgrid(idx, idx, indexing="ij")
93
+ sub_theta = theta[np.ix_(idx, idx)]
94
+
95
+ scale = 0.4 * step
96
+ xs, ys = [], []
97
+ for a, b, t in zip(ii.ravel(), jj.ravel(), sub_theta.ravel()):
98
+ xs += [float(b), float(b) + scale * np.cos(t), None]
99
+ ys += [float(a), float(a) + scale * np.sin(t), None]
100
+
101
+ fig = go.Figure()
102
+ fig.add_trace(
103
+ go.Scatter(
104
+ x=xs,
105
+ y=ys,
106
+ mode="lines",
107
+ line={"color": "steelblue"},
108
+ showlegend=False,
109
+ hoverinfo="skip",
110
+ )
111
+ )
112
+ vi, vj = np.nonzero(vorticity > 0.5)
113
+ ai, aj = np.nonzero(vorticity < -0.5)
114
+ fig.add_trace(go.Scatter(x=vj, y=vi, mode="markers", marker={"color": "red", "size": 10}, name="vortex"))
115
+ fig.add_trace(
116
+ go.Scatter(
117
+ x=aj,
118
+ y=ai,
119
+ mode="markers",
120
+ marker={"color": "blue", "size": 10, "symbol": "x"},
121
+ name="antivortex",
122
+ )
123
+ )
124
+ fig.update_yaxes(autorange="reversed", scaleanchor="x", scaleratio=1)
125
+ fig.update_layout(title="XY spin field and vortices", height=600)
126
+ return fig
127
+
128
+
129
+ def interactive_particle_snapshot(gas):
130
+ """Build an interactive scatter plot of a Lennard-Jones gas snapshot, colored by speed.
131
+
132
+ Parameters
133
+ ----------
134
+ gas : LennardJonesGas
135
+ Simulation instance to render.
136
+
137
+ Returns
138
+ -------
139
+ plotly.graph_objects.Figure
140
+ """
141
+ speeds = gas.speeds()
142
+ fig = go.Figure(
143
+ data=go.Scatter(
144
+ x=gas.positions[:, 0],
145
+ y=gas.positions[:, 1],
146
+ mode="markers",
147
+ marker={
148
+ "color": speeds,
149
+ "colorscale": "Plasma",
150
+ "showscale": True,
151
+ "size": 8,
152
+ "colorbar": {"title": "speed"},
153
+ },
154
+ text=[f"speed={s:.2f}" for s in speeds],
155
+ hoverinfo="text",
156
+ )
157
+ )
158
+ fig.update_xaxes(range=[0, gas.box_size])
159
+ fig.update_yaxes(range=[0, gas.box_size], scaleanchor="x", scaleratio=1)
160
+ fig.update_layout(title=f"Lennard-Jones gas, t={gas.time:.2f}", height=600)
161
+ return fig
@@ -0,0 +1,44 @@
1
+ """Visualizations of the Jarzynski equality: nonequilibrium work distributions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+
8
+ __all__ = ["plot_work_distribution"]
9
+
10
+
11
+ def plot_work_distribution(work, dF_true=0.0, dF_estimate=None, ax=None, bins=50):
12
+ """Histogram nonequilibrium work samples against the true and Jarzynski-estimated free energy.
13
+
14
+ Parameters
15
+ ----------
16
+ work : array_like
17
+ Work samples, e.g. from :meth:`JarzynskiHarmonicTrap.run_protocol`.
18
+ dF_true : float, default=0.0
19
+ Known equilibrium free energy difference, marked with a solid line.
20
+ dF_estimate : float, optional
21
+ Jarzynski-equality estimate of the free energy (e.g. from
22
+ :meth:`JarzynskiHarmonicTrap.jarzynski_free_energy_estimate`),
23
+ marked with a dashed line if given.
24
+ ax : matplotlib.axes.Axes, optional
25
+ Axes to draw into.
26
+ bins : int, default=50
27
+ Number of histogram bins.
28
+
29
+ Returns
30
+ -------
31
+ matplotlib.axes.Axes
32
+ """
33
+ work = np.asarray(work)
34
+ if ax is None:
35
+ _, ax = plt.subplots(figsize=(6, 4))
36
+ ax.hist(work, bins=bins, density=True, alpha=0.6, label="work samples")
37
+ ax.axvline(work.mean(), color="tab:blue", linestyle=":", label=rf"$\langle W \rangle$={work.mean():.2f}")
38
+ ax.axvline(dF_true, color="black", linewidth=2, label=rf"$\Delta F$={dF_true:.2f}")
39
+ if dF_estimate is not None:
40
+ ax.axvline(dF_estimate, color="tab:red", linestyle="--", label=rf"Jarzynski $\Delta F$={dF_estimate:.2f}")
41
+ ax.set_xlabel("work W")
42
+ ax.set_ylabel("density")
43
+ ax.legend()
44
+ return ax
@@ -0,0 +1,65 @@
1
+ """Visualizations of KPZ/RSOS interface growth: height profiles and width scaling."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+
8
+ __all__ = ["plot_interface_profile", "plot_width_growth"]
9
+
10
+
11
+ def plot_interface_profile(interface, ax=None):
12
+ """Plot the current 1D interface height profile.
13
+
14
+ Parameters
15
+ ----------
16
+ interface : KPZInterface
17
+ Interface instance to render.
18
+ ax : matplotlib.axes.Axes, optional
19
+ Axes to draw into. A new figure and axes are created if not given.
20
+
21
+ Returns
22
+ -------
23
+ matplotlib.axes.Axes
24
+ """
25
+ if ax is None:
26
+ _, ax = plt.subplots(figsize=(7, 3))
27
+ x = np.arange(interface.L)
28
+ ax.plot(x, interface.heights, drawstyle="steps-mid")
29
+ ax.set_xlabel("site")
30
+ ax.set_ylabel("height h(x)")
31
+ ax.set_title(f"RSOS interface at t={interface.time:.0f} sweeps")
32
+ return ax
33
+
34
+
35
+ def plot_width_growth(times, widths, ax=None, show_theory=True, beta=1.0 / 3.0):
36
+ """Log-log plot of interface width vs. time, with a t^beta growth reference line.
37
+
38
+ Parameters
39
+ ----------
40
+ times, widths : array_like
41
+ Growth curve, e.g. from :meth:`KPZInterface.run_growth_curve`.
42
+ ax : matplotlib.axes.Axes, optional
43
+ Axes to draw into.
44
+ show_theory : bool, default=True
45
+ Overlay a :math:`t^\\beta` reference line (matched in amplitude to
46
+ the first data point) for the KPZ growth exponent.
47
+ beta : float, default=1/3
48
+ Growth exponent for the reference line (the 1+1D KPZ value).
49
+
50
+ Returns
51
+ -------
52
+ matplotlib.axes.Axes
53
+ """
54
+ times = np.asarray(times)
55
+ widths = np.asarray(widths)
56
+ if ax is None:
57
+ _, ax = plt.subplots(figsize=(5, 4))
58
+ ax.loglog(times, widths, marker="o", ms=3, linestyle="none", label="simulation")
59
+ if show_theory:
60
+ amplitude = widths[0] / times[0] ** beta
61
+ ax.loglog(times, amplitude * times**beta, linestyle="--", label=rf"$t^{{{beta:.2f}}}$")
62
+ ax.set_xlabel("t (sweeps)")
63
+ ax.set_ylabel("interface width w(t)")
64
+ ax.legend()
65
+ return ax
@@ -0,0 +1,212 @@
1
+ """Static and animated visualizations of lattice spin configurations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+ from matplotlib.animation import FuncAnimation
8
+
9
+ __all__ = [
10
+ "animate_lattice_sweeps",
11
+ "plot_cluster_size_distribution",
12
+ "plot_percolation_clusters",
13
+ "plot_spin_grid",
14
+ "plot_thermodynamics",
15
+ ]
16
+
17
+
18
+ def plot_spin_grid(spins, ax=None, cmap="coolwarm", title=None, colorbar=False):
19
+ """Render a spin (or Potts state) configuration as a heatmap.
20
+
21
+ Parameters
22
+ ----------
23
+ spins : ndarray of shape (L, L)
24
+ Spin configuration, e.g. ``Ising2D.spins`` or ``PottsModel2D.spins``.
25
+ ax : matplotlib.axes.Axes, optional
26
+ Axes to draw into. A new figure and axes are created if not given.
27
+ cmap : str, default="coolwarm"
28
+ Matplotlib colormap name.
29
+ title : str, optional
30
+ Axes title.
31
+ colorbar : bool, default=False
32
+ Whether to attach a colorbar.
33
+
34
+ Returns
35
+ -------
36
+ matplotlib.axes.Axes
37
+
38
+ Examples
39
+ --------
40
+ >>> from physicskit.statphys.chapters import Ising2D
41
+ >>> model = Ising2D(L=16, seed=0)
42
+ >>> ax = plot_spin_grid(model.spins)
43
+ """
44
+ if ax is None:
45
+ _, ax = plt.subplots(figsize=(4, 4))
46
+ im = ax.imshow(spins, cmap=cmap, interpolation="nearest")
47
+ ax.set_xticks([])
48
+ ax.set_yticks([])
49
+ if title:
50
+ ax.set_title(title)
51
+ if colorbar:
52
+ plt.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
53
+ return ax
54
+
55
+
56
+ def animate_lattice_sweeps(model, beta, n_frames=100, sweeps_per_frame=1, algorithm="metropolis", cmap="coolwarm"):
57
+ """Animate a lattice model relaxing under repeated Monte Carlo sweeps.
58
+
59
+ Parameters
60
+ ----------
61
+ model : Ising2D or PottsModel2D
62
+ A model instance exposing a ``sweep(beta, ...)`` method and a
63
+ ``spins`` attribute.
64
+ beta : float
65
+ Inverse temperature at which to sweep.
66
+ n_frames : int, default=100
67
+ Number of animation frames.
68
+ sweeps_per_frame : int, default=1
69
+ Sweeps performed between consecutive frames.
70
+ algorithm : str, default="metropolis"
71
+ Forwarded to ``model.sweep`` when supported (``Ising2D`` only).
72
+ cmap : str, default="coolwarm"
73
+ Matplotlib colormap name.
74
+
75
+ Returns
76
+ -------
77
+ matplotlib.animation.FuncAnimation
78
+ """
79
+ fig, ax = plt.subplots(figsize=(4, 4))
80
+ im = ax.imshow(model.spins, cmap=cmap, interpolation="nearest")
81
+ ax.set_xticks([])
82
+ ax.set_yticks([])
83
+ title = ax.set_title("sweep 0")
84
+
85
+ def update(frame):
86
+ try:
87
+ model.sweep(beta, algorithm=algorithm, n_sweeps=sweeps_per_frame)
88
+ except TypeError:
89
+ model.sweep(beta, n_sweeps=sweeps_per_frame)
90
+ im.set_data(model.spins)
91
+ title.set_text(f"sweep {(frame + 1) * sweeps_per_frame}")
92
+ return im, title
93
+
94
+ return FuncAnimation(fig, update, frames=n_frames, blit=False, interval=50)
95
+
96
+
97
+ def plot_thermodynamics(result, T_c=None, ax=None):
98
+ """Plot energy, magnetization, specific heat, and susceptibility versus temperature.
99
+
100
+ Parameters
101
+ ----------
102
+ result : dict of str -> ndarray
103
+ Output of ``Ising2D.run_temperature_sweep`` (or the analogous Potts
104
+ method, in which case ``"M"``/``"chi"`` keys may be absent).
105
+ T_c : float, optional
106
+ Critical temperature to mark with a vertical dashed line on every
107
+ panel.
108
+ ax : ndarray of matplotlib.axes.Axes, optional
109
+ A ``(2, 2)`` array of axes to draw into. A new figure is created if
110
+ not given.
111
+
112
+ Returns
113
+ -------
114
+ ndarray of matplotlib.axes.Axes
115
+ """
116
+ if ax is None:
117
+ _, ax = plt.subplots(2, 2, figsize=(9, 7), sharex=True)
118
+ T = result["T"]
119
+
120
+ panels = [
121
+ (ax[0, 0], "E", "Energy per site"),
122
+ (ax[0, 1], "M" if "M" in result else "m", "Magnetization / order parameter"),
123
+ (ax[1, 0], "C_v", "Specific heat"),
124
+ (ax[1, 1], "chi", "Susceptibility"),
125
+ ]
126
+ for axis, key, label in panels:
127
+ if key not in result:
128
+ axis.axis("off")
129
+ continue
130
+ axis.plot(T, result[key], marker="o", ms=3)
131
+ axis.set_ylabel(label)
132
+ axis.set_xlabel("Temperature")
133
+ if T_c is not None:
134
+ axis.axvline(T_c, color="k", linestyle="--", linewidth=1, alpha=0.6)
135
+ plt.tight_layout()
136
+ return ax
137
+
138
+
139
+ def plot_percolation_clusters(percolation, ax=None, highlight_spanning=True, cmap="nipy_spectral"):
140
+ """Render a percolation lattice with each connected cluster in a distinct color.
141
+
142
+ Parameters
143
+ ----------
144
+ percolation : Percolation2D
145
+ Percolation instance whose current ``labels`` should be drawn.
146
+ ax : matplotlib.axes.Axes, optional
147
+ Axes to draw into. A new figure and axes are created if not given.
148
+ highlight_spanning : bool, default=True
149
+ Whether to redraw spanning clusters (if any) in solid black on top
150
+ of the color-coded background.
151
+ cmap : str, default="nipy_spectral"
152
+ Colormap used to distinguish clusters. Unoccupied sites are drawn in
153
+ white.
154
+
155
+ Returns
156
+ -------
157
+ matplotlib.axes.Axes
158
+ """
159
+ if ax is None:
160
+ _, ax = plt.subplots(figsize=(5, 5))
161
+ labels = percolation.labels
162
+ display = np.ma.masked_equal(labels, 0)
163
+ cmap_obj = plt.get_cmap(cmap).copy()
164
+ cmap_obj.set_bad("white")
165
+ ax.imshow(display, cmap=cmap_obj, interpolation="nearest")
166
+ if highlight_spanning:
167
+ spanning = percolation.spanning_labels()
168
+ if len(spanning):
169
+ mask = np.isin(labels, spanning)
170
+ spanning_display = np.ma.masked_where(~mask, mask.astype(float))
171
+ ax.imshow(spanning_display, cmap="Greys", vmin=0, vmax=1, alpha=0.7, interpolation="nearest")
172
+ ax.set_xticks([])
173
+ ax.set_yticks([])
174
+ ax.set_title(f"{percolation.mode} percolation, p = {percolation.p:.3f}")
175
+ return ax
176
+
177
+
178
+ def plot_cluster_size_distribution(sizes, ax=None, bins=30, tau_theory=187 / 91):
179
+ """Log-log histogram of percolation cluster sizes against the theoretical Fisher exponent.
180
+
181
+ Parameters
182
+ ----------
183
+ sizes : array_like
184
+ Cluster sizes, e.g. from ``Percolation2D.cluster_size_distribution``.
185
+ ax : matplotlib.axes.Axes, optional
186
+ Axes to draw into.
187
+ bins : int, default=30
188
+ Number of logarithmically spaced bins.
189
+ tau_theory : float, default=187/91
190
+ Theoretical Fisher exponent to overlay as a reference power law.
191
+ Pass ``None`` to omit it.
192
+
193
+ Returns
194
+ -------
195
+ matplotlib.axes.Axes
196
+ """
197
+ sizes = np.asarray(sizes)
198
+ sizes = sizes[sizes > 0]
199
+ if ax is None:
200
+ _, ax = plt.subplots(figsize=(5, 4))
201
+ log_bins = np.logspace(0, np.log10(sizes.max()), bins)
202
+ counts, edges = np.histogram(sizes, bins=log_bins, density=True)
203
+ centers = np.sqrt(edges[:-1] * edges[1:])
204
+ mask = counts > 0
205
+ ax.loglog(centers[mask], counts[mask], marker="o", ms=3, linestyle="none", label="simulation")
206
+ if tau_theory is not None and np.any(mask):
207
+ ref = counts[mask][0] * (centers[mask] / centers[mask][0]) ** (-tau_theory)
208
+ ax.loglog(centers[mask], ref, linestyle="--", color="k", label=f"$s^{{-{tau_theory:.3f}}}$")
209
+ ax.set_xlabel("cluster size s")
210
+ ax.set_ylabel("P(s)")
211
+ ax.legend()
212
+ return ax
@@ -0,0 +1,121 @@
1
+ """Visualizations of the Lennard-Jones gas: particle snapshots and velocity statistics."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+ from matplotlib.animation import FuncAnimation
8
+
9
+ from physicskit.statphys.utils.thermodynamics import maxwell_boltzmann_speed_pdf
10
+
11
+ __all__ = ["animate_gas", "plot_particle_snapshot", "plot_velocity_histogram"]
12
+
13
+
14
+ def plot_particle_snapshot(gas, ax=None, show_velocities=False, color_by_speed=True):
15
+ """Draw a single snapshot of the particle gas's positions.
16
+
17
+ Parameters
18
+ ----------
19
+ gas : LennardJonesGas
20
+ Simulation instance to render.
21
+ ax : matplotlib.axes.Axes, optional
22
+ Axes to draw into. A new figure and axes are created if not given.
23
+ show_velocities : bool, default=False
24
+ Whether to overlay velocity vectors as arrows.
25
+ color_by_speed : bool, default=True
26
+ Whether to color particles by their instantaneous speed.
27
+
28
+ Returns
29
+ -------
30
+ matplotlib.axes.Axes
31
+ """
32
+ if ax is None:
33
+ _, ax = plt.subplots(figsize=(5, 5))
34
+ speeds = gas.speeds()
35
+ c = speeds if color_by_speed else "steelblue"
36
+ scatter = ax.scatter(gas.positions[:, 0], gas.positions[:, 1], c=c, cmap="plasma", s=25)
37
+ if color_by_speed:
38
+ plt.colorbar(scatter, ax=ax, fraction=0.046, pad=0.04, label="speed")
39
+ if show_velocities:
40
+ ax.quiver(
41
+ gas.positions[:, 0],
42
+ gas.positions[:, 1],
43
+ gas.velocities[:, 0],
44
+ gas.velocities[:, 1],
45
+ color="black",
46
+ alpha=0.5,
47
+ scale_units="xy",
48
+ angles="xy",
49
+ scale=1.0,
50
+ )
51
+ ax.set_xlim(0, gas.box_size)
52
+ ax.set_ylim(0, gas.box_size)
53
+ ax.set_aspect("equal")
54
+ ax.set_title(f"t = {gas.time:.2f}, T = {gas.temperature():.2f}")
55
+ return ax
56
+
57
+
58
+ def plot_velocity_histogram(gas, ax=None, bins=40, show_theory=True):
59
+ """Plot the current speed histogram against the theoretical Maxwell-Boltzmann curve.
60
+
61
+ Parameters
62
+ ----------
63
+ gas : LennardJonesGas
64
+ Simulation instance to render.
65
+ ax : matplotlib.axes.Axes, optional
66
+ Axes to draw into.
67
+ bins : int, default=40
68
+ Histogram bin count.
69
+ show_theory : bool, default=True
70
+ Whether to overlay the equilibrium Maxwell-Boltzmann density at the
71
+ gas's instantaneous kinetic temperature.
72
+
73
+ Returns
74
+ -------
75
+ matplotlib.axes.Axes
76
+ """
77
+ if ax is None:
78
+ _, ax = plt.subplots(figsize=(5, 4))
79
+ speeds = gas.speeds()
80
+ ax.hist(speeds, bins=bins, density=True, alpha=0.6, color="steelblue", label="simulation")
81
+ if show_theory:
82
+ v = np.linspace(0, speeds.max() * 1.2, 200)
83
+ pdf = maxwell_boltzmann_speed_pdf(v, gas.temperature(), mass=gas.mass, kB=gas.kB, dim=2)
84
+ ax.plot(v, pdf, color="crimson", linewidth=2, label="Maxwell-Boltzmann")
85
+ ax.set_xlabel("speed")
86
+ ax.set_ylabel("probability density")
87
+ ax.legend()
88
+ return ax
89
+
90
+
91
+ def animate_gas(gas, n_frames=200, steps_per_frame=5):
92
+ """Animate the particle gas evolving under Velocity Verlet dynamics.
93
+
94
+ Parameters
95
+ ----------
96
+ gas : LennardJonesGas
97
+ Simulation instance to animate; advanced in place.
98
+ n_frames : int, default=200
99
+ Number of animation frames.
100
+ steps_per_frame : int, default=5
101
+ Integration steps performed between consecutive frames.
102
+
103
+ Returns
104
+ -------
105
+ matplotlib.animation.FuncAnimation
106
+ """
107
+ fig, ax = plt.subplots(figsize=(5, 5))
108
+ scatter = ax.scatter(gas.positions[:, 0], gas.positions[:, 1], c=gas.speeds(), cmap="plasma", s=25)
109
+ ax.set_xlim(0, gas.box_size)
110
+ ax.set_ylim(0, gas.box_size)
111
+ ax.set_aspect("equal")
112
+ title = ax.set_title(f"t = {gas.time:.2f}")
113
+
114
+ def update(_frame):
115
+ gas.step(steps_per_frame)
116
+ scatter.set_offsets(gas.positions)
117
+ scatter.set_array(gas.speeds())
118
+ title.set_text(f"t = {gas.time:.2f}, T = {gas.temperature():.2f}")
119
+ return scatter, title
120
+
121
+ return FuncAnimation(fig, update, frames=n_frames, blit=False, interval=40)