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,527 @@
1
+ """Soliton-bearing nonlinear field equations: KdV, the nonlinear Schrodinger equation, and Sine-Gordon.
2
+
3
+ Each equation is integrated with a scheme suited to its structure:
4
+
5
+ - **Korteweg-de Vries** -- Strang-split pseudo-spectral: the stiff linear
6
+ dispersion :math:`\\partial_x^3` is advanced exactly via the FFT, and the
7
+ non-stiff advection :math:`6u\\partial_x u` via RK4.
8
+ - **Nonlinear Schrodinger** -- split-step Fourier: exact for the linear
9
+ (kinetic) part and exact for the nonlinear (pointwise phase-rotation) part.
10
+ - **Sine-Gordon** -- explicit leapfrog finite differences on the wave equation.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import numpy as np
16
+
17
+ __all__ = [
18
+ "kdv_soliton",
19
+ "kdv_step",
20
+ "kdv_evolve",
21
+ "kdv_evolve_frames",
22
+ "nls_bright_soliton",
23
+ "nls_dark_soliton",
24
+ "nls_evolve",
25
+ "nls_evolve_frames",
26
+ "sine_gordon_kink",
27
+ "sine_gordon_evolve",
28
+ "sine_gordon_evolve_frames",
29
+ ]
30
+
31
+
32
+ # -- Korteweg-de Vries --------------------------------------------------------
33
+
34
+
35
+ def kdv_soliton(x: np.ndarray, c: float, x0: float = 0.0) -> np.ndarray:
36
+ """Exact single-soliton solution of :math:`u_t + 6uu_x + u_{xxx} = 0` at :math:`t=0`.
37
+
38
+ Parameters
39
+ ----------
40
+ x : ndarray
41
+ Spatial grid.
42
+ c : float
43
+ Soliton speed (equal to twice its amplitude: amplitude :math:`=c/2`).
44
+ x0 : float, default=0.0
45
+ Initial center position.
46
+
47
+ Returns
48
+ -------
49
+ ndarray
50
+ :math:`u(x, 0) = \\tfrac{c}{2}\\,\\mathrm{sech}^2\\!\\big(\\tfrac{\\sqrt{c}}{2}(x-x_0)\\big)`.
51
+
52
+ See Also
53
+ --------
54
+ kdv_evolve : Propagate this (or any) initial condition forward in time.
55
+
56
+ Examples
57
+ --------
58
+ >>> import numpy as np
59
+ >>> round(float(kdv_soliton(0.0, c=4.0)), 6)
60
+ 2.0
61
+ """
62
+ return (c / 2.0) * (1.0 / np.cosh(np.sqrt(c) / 2.0 * (x - x0))) ** 2
63
+
64
+
65
+ def kdv_step(u_hat: np.ndarray, k: np.ndarray, dt: float) -> np.ndarray:
66
+ """Advance the KdV equation in Fourier space by one Strang-split step.
67
+
68
+ Parameters
69
+ ----------
70
+ u_hat : ndarray
71
+ Fourier coefficients of :math:`u` (as from ``numpy.fft.fft``).
72
+ k : ndarray
73
+ Angular wavenumbers matching ``u_hat``.
74
+ dt : float
75
+ Time step.
76
+
77
+ Returns
78
+ -------
79
+ ndarray
80
+ Fourier coefficients after one step of size ``dt``.
81
+ """
82
+ ik3 = 1j * k**3
83
+
84
+ def nonlinear_rhs(uh):
85
+ u = np.real(np.fft.ifft(uh))
86
+ ux = np.real(np.fft.ifft(1j * k * uh))
87
+ return np.fft.fft(-6 * u * ux)
88
+
89
+ u_hat = u_hat * np.exp(ik3 * dt / 2)
90
+ k1 = nonlinear_rhs(u_hat)
91
+ k2 = nonlinear_rhs(u_hat + dt / 2 * k1)
92
+ k3 = nonlinear_rhs(u_hat + dt / 2 * k2)
93
+ k4 = nonlinear_rhs(u_hat + dt * k3)
94
+ u_hat = u_hat + dt / 6 * (k1 + 2 * k2 + 2 * k3 + k4)
95
+ return u_hat * np.exp(ik3 * dt / 2)
96
+
97
+
98
+ def kdv_evolve(u0: np.ndarray, x: np.ndarray, dt: float, steps: int) -> np.ndarray:
99
+ """Evolve a KdV initial condition forward in time on a periodic domain.
100
+
101
+ Parameters
102
+ ----------
103
+ u0 : ndarray
104
+ Initial field, sampled on the periodic grid ``x``.
105
+ x : ndarray
106
+ Uniformly spaced periodic spatial grid.
107
+ dt : float
108
+ Time step.
109
+ steps : int
110
+ Number of steps to advance.
111
+
112
+ Returns
113
+ -------
114
+ ndarray
115
+ Field after ``steps * dt`` time units.
116
+
117
+ Notes
118
+ -----
119
+ Because KdV solitons are true solitons, two colliding solitons of
120
+ different speed pass through each other **elastically**: each emerges
121
+ from the collision with its original amplitude and speed, shifted only
122
+ in phase -- unlike generic nonlinear waves, which would break up or
123
+ change shape on collision.
124
+
125
+ Examples
126
+ --------
127
+ A fast, tall soliton launched behind a slower, shorter one overtakes it;
128
+ both retain their original amplitudes after the collision:
129
+
130
+ >>> import numpy as np
131
+ >>> from scipy.signal import find_peaks
132
+ >>> N, L = 512, 60.0
133
+ >>> x = np.linspace(-L / 2, L / 2, N, endpoint=False)
134
+ >>> u0 = kdv_soliton(x, c=9.0, x0=-20) + kdv_soliton(x, c=4.0, x0=-8)
135
+ >>> u = kdv_evolve(u0, x, dt=0.0005, steps=6000)
136
+ >>> peaks, _ = find_peaks(u, height=1.0)
137
+ >>> heights = sorted(u[peaks])
138
+ >>> [round(float(h), 1) for h in heights]
139
+ [2.0, 4.5]
140
+ """
141
+ k = 2 * np.pi * np.fft.fftfreq(len(x), d=x[1] - x[0])
142
+ u_hat = np.fft.fft(u0)
143
+ for _ in range(steps):
144
+ u_hat = kdv_step(u_hat, k, dt)
145
+ return np.real(np.fft.ifft(u_hat))
146
+
147
+
148
+ def kdv_evolve_frames(u0: np.ndarray, x: np.ndarray, dt: float, steps_per_frame: int, n_frames: int) -> tuple:
149
+ """Evolve a KdV field and record a snapshot every ``steps_per_frame`` steps, for animation.
150
+
151
+ A thin looping wrapper around :func:`kdv_evolve` -- no new physics, just
152
+ repeated short calls with each chunk's output fed back in as the next
153
+ chunk's initial condition (valid since :func:`kdv_evolve` is a
154
+ deterministic one-step-at-a-time integrator), so the trajectory can be
155
+ animated frame by frame.
156
+
157
+ Parameters
158
+ ----------
159
+ u0 : ndarray
160
+ Initial field.
161
+ x : ndarray
162
+ Uniformly spaced periodic spatial grid.
163
+ dt : float
164
+ Time step.
165
+ steps_per_frame : int
166
+ Number of integration steps between recorded frames.
167
+ n_frames : int
168
+ Number of frames to record after the initial condition.
169
+
170
+ Returns
171
+ -------
172
+ frames : ndarray, shape (n_frames + 1, len(x))
173
+ Field at ``t=0`` and after each recorded chunk.
174
+ times : ndarray, shape (n_frames + 1,)
175
+
176
+ See Also
177
+ --------
178
+ physicskit.fields.visualizers.animate_field_1d : Render these frames as a line-plot animation.
179
+
180
+ Examples
181
+ --------
182
+ >>> import numpy as np
183
+ >>> x = np.linspace(-30, 30, 256, endpoint=False)
184
+ >>> u0 = kdv_soliton(x, c=4.0, x0=-15)
185
+ >>> frames, times = kdv_evolve_frames(u0, x, dt=0.001, steps_per_frame=200, n_frames=5)
186
+ >>> frames.shape
187
+ (6, 256)
188
+ """
189
+ u = np.array(u0, dtype=float, copy=True)
190
+ frames = [u.copy()]
191
+ times = [0.0]
192
+ for i in range(n_frames):
193
+ u = kdv_evolve(u, x, dt, steps_per_frame)
194
+ frames.append(u.copy())
195
+ times.append((i + 1) * steps_per_frame * dt)
196
+ return np.array(frames), np.array(times)
197
+
198
+
199
+ # -- Nonlinear Schrodinger equation -----------------------------------------
200
+
201
+
202
+ def nls_bright_soliton(x: np.ndarray, t: float, A: float = 1.0, v: float = 0.0, x0: float = 0.0) -> np.ndarray:
203
+ """Exact bright-soliton solution of the focusing NLS equation.
204
+
205
+ Solves :math:`i\\psi_t + \\tfrac{1}{2}\\psi_{xx} + |\\psi|^2\\psi = 0`.
206
+
207
+ Parameters
208
+ ----------
209
+ x : ndarray
210
+ Spatial grid.
211
+ t : float
212
+ Time.
213
+ A : float, default=1.0
214
+ Soliton amplitude.
215
+ v : float, default=0.0
216
+ Soliton velocity.
217
+ x0 : float, default=0.0
218
+ Initial center position.
219
+
220
+ Returns
221
+ -------
222
+ ndarray of complex
223
+ :math:`\\psi(x,t) = A\\,\\mathrm{sech}(A(x-x_0-vt))\\, e^{i[v(x-x_0) + (A^2-v^2)t/2]}`.
224
+
225
+ See Also
226
+ --------
227
+ nls_dark_soliton : The defocusing-equation counterpart.
228
+ nls_evolve : Propagate this (or any) initial condition numerically.
229
+
230
+ Examples
231
+ --------
232
+ >>> import numpy as np
233
+ >>> x = np.array([0.0])
234
+ >>> abs(nls_bright_soliton(x, t=0.0, A=1.0))
235
+ array([1.])
236
+ """
237
+ envelope = A / np.cosh(A * (x - x0 - v * t))
238
+ phase = v * (x - x0) + (A**2 - v**2) / 2 * t
239
+ return envelope * np.exp(1j * phase)
240
+
241
+
242
+ def nls_dark_soliton(x: np.ndarray, t: float, rho0: float = 1.0, x0: float = 0.0) -> np.ndarray:
243
+ """Exact stationary dark (black) soliton solution of the defocusing NLS equation.
244
+
245
+ Solves :math:`i\\psi_t + \\tfrac{1}{2}\\psi_{xx} - |\\psi|^2\\psi = 0`: a
246
+ density notch that vanishes at its center, sitting on a uniform
247
+ background of density ``rho0``.
248
+
249
+ Parameters
250
+ ----------
251
+ x : ndarray
252
+ Spatial grid.
253
+ t : float
254
+ Time.
255
+ rho0 : float, default=1.0
256
+ Background density far from the soliton.
257
+ x0 : float, default=0.0
258
+ Center position.
259
+
260
+ Returns
261
+ -------
262
+ ndarray of complex
263
+ :math:`\\psi(x,t) = \\sqrt{\\rho_0}\\,\\tanh\\!\\big(\\sqrt{\\rho_0/2}\\,(x-x_0)\\big)\\, e^{-i\\rho_0 t}`,
264
+ with healing length :math:`\\xi = 1/\\sqrt{\\rho_0}`.
265
+
266
+ See Also
267
+ --------
268
+ nls_bright_soliton : The focusing-equation counterpart.
269
+
270
+ Examples
271
+ --------
272
+ >>> import numpy as np
273
+ >>> x = np.array([0.0])
274
+ >>> abs(nls_dark_soliton(x, t=0.0, rho0=1.0))
275
+ array([0.])
276
+ """
277
+ envelope = np.sqrt(rho0) * np.tanh(np.sqrt(rho0 / 2) * (x - x0))
278
+ return envelope * np.exp(-1j * rho0 * t)
279
+
280
+
281
+ def nls_evolve(psi0: np.ndarray, x: np.ndarray, dt: float, steps: int, g: float = 1.0) -> np.ndarray:
282
+ """Evolve a nonlinear Schrodinger initial condition via split-step Fourier.
283
+
284
+ Solves :math:`i\\psi_t + \\tfrac{1}{2}\\psi_{xx} + g|\\psi|^2\\psi = 0`
285
+ on a periodic domain: ``g > 0`` is focusing (bright solitons),
286
+ ``g < 0`` is defocusing (dark solitons).
287
+
288
+ Parameters
289
+ ----------
290
+ psi0 : ndarray of complex
291
+ Initial wavefunction, sampled on the periodic grid ``x``.
292
+ x : ndarray
293
+ Uniformly spaced periodic spatial grid.
294
+ dt : float
295
+ Time step.
296
+ steps : int
297
+ Number of steps to advance.
298
+ g : float, default=1.0
299
+ Nonlinearity strength and sign.
300
+
301
+ Returns
302
+ -------
303
+ ndarray of complex
304
+ Field after ``steps * dt`` time units.
305
+
306
+ Examples
307
+ --------
308
+ A bright soliton propagates without dispersing -- its envelope
309
+ :math:`|\\psi|` is unchanged after 2 time units of evolution:
310
+
311
+ >>> import numpy as np
312
+ >>> N, L = 1024, 80.0
313
+ >>> x = np.linspace(-L / 2, L / 2, N, endpoint=False)
314
+ >>> psi0 = nls_bright_soliton(x, t=0.0, A=1.0)
315
+ >>> psi = nls_evolve(psi0, x, dt=0.001, steps=2000, g=1.0)
316
+ >>> shape_error = np.max(np.abs(np.abs(psi) - np.abs(psi0)))
317
+ >>> bool(shape_error < 1e-3)
318
+ True
319
+ """
320
+ k = 2 * np.pi * np.fft.fftfreq(len(x), d=x[1] - x[0])
321
+ lin_prop = np.exp(-1j * 0.5 * k**2 * dt)
322
+ psi = np.array(psi0, dtype=complex, copy=True)
323
+ for _ in range(steps):
324
+ psi_hat = np.fft.fft(psi)
325
+ psi_hat *= lin_prop
326
+ psi = np.fft.ifft(psi_hat)
327
+ psi *= np.exp(1j * g * np.abs(psi) ** 2 * dt)
328
+ return psi
329
+
330
+
331
+ def nls_evolve_frames(psi0: np.ndarray, x: np.ndarray, dt: float, steps_per_frame: int, n_frames: int, g: float = 1.0) -> tuple:
332
+ """Evolve an NLS field and record a snapshot every ``steps_per_frame`` steps, for animation.
333
+
334
+ A thin looping wrapper around :func:`nls_evolve`, analogous to
335
+ :func:`kdv_evolve_frames`: no new physics, just repeated chunked calls
336
+ with the state carried forward, to produce an animatable sequence of frames.
337
+
338
+ Parameters
339
+ ----------
340
+ psi0 : ndarray of complex
341
+ Initial wavefunction.
342
+ x : ndarray
343
+ Uniformly spaced periodic spatial grid.
344
+ dt : float
345
+ Time step.
346
+ steps_per_frame : int
347
+ Number of integration steps between recorded frames.
348
+ n_frames : int
349
+ Number of frames to record after the initial condition.
350
+ g : float, default=1.0
351
+ Nonlinearity strength and sign.
352
+
353
+ Returns
354
+ -------
355
+ frames : ndarray of complex, shape (n_frames + 1, len(x))
356
+ Field at ``t=0`` and after each recorded chunk.
357
+ times : ndarray, shape (n_frames + 1,)
358
+
359
+ See Also
360
+ --------
361
+ physicskit.fields.visualizers.animate_field_1d : Render these frames as a line-plot animation.
362
+
363
+ Examples
364
+ --------
365
+ >>> import numpy as np
366
+ >>> x = np.linspace(-40, 40, 512, endpoint=False)
367
+ >>> psi0 = nls_bright_soliton(x, t=0.0, A=1.0)
368
+ >>> frames, times = nls_evolve_frames(psi0, x, dt=0.001, steps_per_frame=200, n_frames=5, g=1.0)
369
+ >>> frames.shape
370
+ (6, 512)
371
+ """
372
+ psi = np.array(psi0, dtype=complex, copy=True)
373
+ frames = [psi.copy()]
374
+ times = [0.0]
375
+ for i in range(n_frames):
376
+ psi = nls_evolve(psi, x, dt, steps_per_frame, g)
377
+ frames.append(psi.copy())
378
+ times.append((i + 1) * steps_per_frame * dt)
379
+ return np.array(frames), np.array(times)
380
+
381
+
382
+ # -- Sine-Gordon --------------------------------------------------------------
383
+
384
+
385
+ def sine_gordon_kink(x: np.ndarray, t: float, v: float = 0.0, x0: float = 0.0, polarity: int = 1) -> np.ndarray:
386
+ """Exact kink (or antikink) solution of the Sine-Gordon equation :math:`u_{tt} - u_{xx} + \\sin u = 0`.
387
+
388
+ Parameters
389
+ ----------
390
+ x : ndarray
391
+ Spatial grid.
392
+ t : float
393
+ Time.
394
+ v : float, default=0.0
395
+ Kink velocity (:math:`|v| < 1`, the wave speed of the linearized equation).
396
+ x0 : float, default=0.0
397
+ Initial center position.
398
+ polarity : {1, -1}, default=1
399
+ ``1`` for a kink (field jumps by :math:`2\\pi`), ``-1`` for an antikink.
400
+
401
+ Returns
402
+ -------
403
+ ndarray
404
+ :math:`u(x,t) = 4\\arctan\\!\\big(\\exp[\\text{polarity}\\cdot\\gamma(x-x_0-vt)]\\big)`,
405
+ with :math:`\\gamma = 1/\\sqrt{1-v^2}`.
406
+
407
+ See Also
408
+ --------
409
+ sine_gordon_evolve : Propagate this (or any) initial condition numerically.
410
+
411
+ Examples
412
+ --------
413
+ >>> import numpy as np
414
+ >>> round(float(sine_gordon_kink(0.0, t=0.0)), 6)
415
+ 3.141593
416
+ """
417
+ gamma = 1.0 / np.sqrt(1 - v**2)
418
+ return 4 * np.arctan(np.exp(polarity * gamma * (x - x0 - v * t)))
419
+
420
+
421
+ def sine_gordon_evolve(u0: np.ndarray, u0_prev: np.ndarray, x: np.ndarray, dt: float, steps: int) -> tuple:
422
+ """Evolve the Sine-Gordon equation with explicit leapfrog finite differences.
423
+
424
+ Parameters
425
+ ----------
426
+ u0 : ndarray
427
+ Field at the starting time.
428
+ u0_prev : ndarray
429
+ Field one step *before* the starting time (needed to seed the
430
+ two-level leapfrog scheme); for a traveling-wave initial condition,
431
+ use the exact solution evaluated at ``t=-dt``.
432
+ x : ndarray
433
+ Uniformly spaced spatial grid, with fixed (Dirichlet) boundaries.
434
+ dt : float
435
+ Time step; must satisfy the CFL condition ``dt <= dx`` (wave speed 1).
436
+ steps : int
437
+ Number of steps to advance.
438
+
439
+ Returns
440
+ -------
441
+ u, u_prev : ndarray
442
+ The field at the final step and the step before it (the pair
443
+ needed to continue the integration further).
444
+
445
+ Examples
446
+ --------
447
+ A kink launched at speed :math:`v=0.5` arrives at the expected
448
+ Lorentz-contracted position after propagating:
449
+
450
+ >>> import numpy as np
451
+ >>> N, L, v, x0 = 4000, 200.0, 0.5, -50.0
452
+ >>> x = np.linspace(-L / 2, L / 2, N)
453
+ >>> dx = x[1] - x[0]
454
+ >>> dt = 0.4 * dx
455
+ >>> u_prev = sine_gordon_kink(x, -dt, v, x0)
456
+ >>> u0 = sine_gordon_kink(x, 0.0, v, x0)
457
+ >>> steps = 1000
458
+ >>> u, _ = sine_gordon_evolve(u0, u_prev, x, dt, steps)
459
+ >>> expected = sine_gordon_kink(x, steps * dt, v, x0)
460
+ >>> bool(np.max(np.abs(u - expected)) < 0.01)
461
+ True
462
+ """
463
+ dx = x[1] - x[0]
464
+ u_prev = np.array(u0_prev, dtype=float, copy=True)
465
+ u = np.array(u0, dtype=float, copy=True)
466
+ for _ in range(steps):
467
+ lap = np.zeros_like(u)
468
+ lap[1:-1] = (u[2:] - 2 * u[1:-1] + u[:-2]) / dx**2
469
+ u_next = 2 * u - u_prev + dt**2 * (lap - np.sin(u))
470
+ u_next[0] = u[0]
471
+ u_next[-1] = u[-1]
472
+ u_prev, u = u, u_next
473
+ return u, u_prev
474
+
475
+
476
+ def sine_gordon_evolve_frames(u0: np.ndarray, u0_prev: np.ndarray, x: np.ndarray, dt: float, steps_per_frame: int, n_frames: int) -> tuple:
477
+ """Evolve a Sine-Gordon field and record a snapshot every ``steps_per_frame`` steps, for animation.
478
+
479
+ A thin looping wrapper around :func:`sine_gordon_evolve`, analogous to
480
+ :func:`kdv_evolve_frames`: the ``(u, u_prev)`` leapfrog pair is carried
481
+ forward chunk to chunk, with no change to the underlying physics.
482
+
483
+ Parameters
484
+ ----------
485
+ u0 : ndarray
486
+ Field at the starting time.
487
+ u0_prev : ndarray
488
+ Field one step before the starting time (see :func:`sine_gordon_evolve`).
489
+ x : ndarray
490
+ Uniformly spaced spatial grid.
491
+ dt : float
492
+ Time step.
493
+ steps_per_frame : int
494
+ Number of integration steps between recorded frames.
495
+ n_frames : int
496
+ Number of frames to record after the initial condition.
497
+
498
+ Returns
499
+ -------
500
+ frames : ndarray, shape (n_frames + 1, len(x))
501
+ Field at ``t=0`` and after each recorded chunk.
502
+ times : ndarray, shape (n_frames + 1,)
503
+
504
+ See Also
505
+ --------
506
+ physicskit.fields.visualizers.animate_field_1d : Render these frames as a line-plot animation.
507
+
508
+ Examples
509
+ --------
510
+ >>> import numpy as np
511
+ >>> x = np.linspace(-50, 50, 800)
512
+ >>> dt = 0.4 * (x[1] - x[0])
513
+ >>> u_prev = sine_gordon_kink(x, -dt, v=0.5, x0=-20)
514
+ >>> u0 = sine_gordon_kink(x, 0.0, v=0.5, x0=-20)
515
+ >>> frames, times = sine_gordon_evolve_frames(u0, u_prev, x, dt, steps_per_frame=100, n_frames=4)
516
+ >>> frames.shape
517
+ (5, 800)
518
+ """
519
+ u = np.array(u0, dtype=float, copy=True)
520
+ u_prev = np.array(u0_prev, dtype=float, copy=True)
521
+ frames = [u.copy()]
522
+ times = [0.0]
523
+ for i in range(n_frames):
524
+ u, u_prev = sine_gordon_evolve(u, u_prev, x, dt, steps_per_frame)
525
+ frames.append(u.copy())
526
+ times.append((i + 1) * steps_per_frame * dt)
527
+ return np.array(frames), np.array(times)
File without changes
@@ -0,0 +1,7 @@
1
+ """Test-session setup: force Matplotlib's non-interactive Agg backend
2
+ before anything imports pyplot, so the suite (and CI, which has no
3
+ display) can exercise the plotting/animation code headlessly."""
4
+
5
+ import matplotlib
6
+
7
+ matplotlib.use("Agg")
@@ -0,0 +1,154 @@
1
+ """Animation smoke tests for physicskit.fields.visualizers: build each animation and save it
2
+ to a GIF, following the pattern in physicskit/classical/tests/test_visualizers.py."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import numpy as np
7
+ import pytest
8
+ from matplotlib.animation import PillowWriter
9
+
10
+ from physicskit.fields.electrodynamics import (
11
+ courant_limit_2d,
12
+ dielectric_slab,
13
+ fdtd_2d_tmz_evolve,
14
+ oscillating_dipole_source,
15
+ tmz_cavity_mode,
16
+ )
17
+ from physicskit.fields.quantum_fields import gpe_evolve, gpe_imprint_vortex, gpe_relax, harmonic_trap_grid
18
+ from physicskit.fields.solitons import (
19
+ kdv_evolve_frames,
20
+ kdv_soliton,
21
+ nls_bright_soliton,
22
+ nls_evolve_frames,
23
+ sine_gordon_evolve_frames,
24
+ sine_gordon_kink,
25
+ )
26
+ from physicskit.fields.visualizers import (
27
+ animate_casimir_modes,
28
+ animate_density_2d,
29
+ animate_field_1d,
30
+ animate_field_2d,
31
+ animate_flux_tube,
32
+ )
33
+
34
+
35
+ def _save(anim, tmp_path, name):
36
+ out = tmp_path / name
37
+ anim.save(out, writer=PillowWriter(fps=10))
38
+ assert out.exists() and out.stat().st_size > 0
39
+
40
+
41
+ class TestSolitonAnimations:
42
+ @pytest.mark.slow
43
+ def test_kdv_animation(self, tmp_path):
44
+ x = np.linspace(-30, 30, 200, endpoint=False)
45
+ u0 = kdv_soliton(x, c=4.0, x0=-15)
46
+ frames, times = kdv_evolve_frames(u0, x, dt=0.001, steps_per_frame=100, n_frames=4)
47
+ anim = animate_field_1d(x, frames, times, ylabel="u(x, t)")
48
+ _save(anim, tmp_path, "kdv.gif")
49
+
50
+ @pytest.mark.slow
51
+ def test_nls_animation(self, tmp_path):
52
+ x = np.linspace(-40, 40, 256, endpoint=False)
53
+ psi0 = nls_bright_soliton(x, t=0.0, A=1.0)
54
+ frames, times = nls_evolve_frames(psi0, x, dt=0.001, steps_per_frame=100, n_frames=4, g=1.0)
55
+ anim = animate_field_1d(x, frames, times, ylabel=r"$|\psi|$")
56
+ _save(anim, tmp_path, "nls.gif")
57
+
58
+ @pytest.mark.slow
59
+ def test_sine_gordon_animation(self, tmp_path):
60
+ x = np.linspace(-50, 50, 400)
61
+ dt = 0.4 * (x[1] - x[0])
62
+ u_prev = sine_gordon_kink(x, -dt, v=0.5, x0=-20)
63
+ u0 = sine_gordon_kink(x, 0.0, v=0.5, x0=-20)
64
+ frames, times = sine_gordon_evolve_frames(u0, u_prev, x, dt, steps_per_frame=50, n_frames=4)
65
+ anim = animate_field_1d(x, frames, times, ylabel="u(x, t)")
66
+ _save(anim, tmp_path, "sine_gordon.gif")
67
+
68
+
69
+ class TestFDTDAnimations:
70
+ @pytest.mark.slow
71
+ def test_dipole_radiation_animation(self, tmp_path):
72
+ N = 40
73
+ dx = dy = 2e-3
74
+ dt = 0.5 * courant_limit_2d(dx, dy)
75
+ eps_r = mu_r = np.ones((N, N))
76
+ Ez0 = Hx0 = Hy0 = np.zeros((N, N))
77
+ source = oscillating_dipole_source(N // 2, N // 2, amplitude=1.0, freq=3e10)
78
+ frames, times = fdtd_2d_tmz_evolve(Ez0, Hx0, Hy0, eps_r, mu_r, steps=40, dt=dt, dx=dx, dy=dy, source=source, snapshot_stride=5)
79
+ x = np.arange(N) * dx
80
+ y = np.arange(N) * dy
81
+ X, Y = np.meshgrid(x, y, indexing="ij")
82
+ anim = animate_field_2d(X, Y, frames, times)
83
+ _save(anim, tmp_path, "dipole.gif")
84
+
85
+ @pytest.mark.slow
86
+ def test_dielectric_slab_animation(self, tmp_path):
87
+ Nx, Ny = 60, 30
88
+ dx = dy = 1e-3
89
+ dt = 0.5 * courant_limit_2d(dx, dy)
90
+ eps_r = dielectric_slab((Nx, Ny), i_start=35, i_end=50, eps_r_slab=4.0)
91
+ mu_r = np.ones((Nx, Ny))
92
+ xs = np.arange(Nx)
93
+ Ez0 = np.exp(-((xs[:, None] - 15) ** 2) / (2 * 4.0**2)) * np.ones((1, Ny))
94
+ Hx0 = Hy0 = np.zeros((Nx, Ny))
95
+ frames, times = fdtd_2d_tmz_evolve(Ez0, Hx0, Hy0, eps_r, mu_r, steps=40, dt=dt, dx=dx, dy=dy, snapshot_stride=5)
96
+ x = np.arange(Nx) * dx
97
+ y = np.arange(Ny) * dy
98
+ X, Y = np.meshgrid(x, y, indexing="ij")
99
+ anim = animate_field_2d(X, Y, frames, times)
100
+ _save(anim, tmp_path, "slab.gif")
101
+ # the wave should have visibly entered the slab region, not just reflected away
102
+ assert np.max(np.abs(frames[:, 35:50, :])) > 0.0
103
+
104
+ @pytest.mark.slow
105
+ def test_cavity_mode_animation(self, tmp_path):
106
+ N = 25
107
+ dx = dy = 1e-3
108
+ dt = 0.5 * courant_limit_2d(dx, dy)
109
+ Ez0, omega = tmz_cavity_mode((N, N), dx, dy, m=1, n=1)
110
+ Hx0 = Hy0 = np.zeros((N, N))
111
+ eps_r = mu_r = np.ones((N, N))
112
+ frames, times = fdtd_2d_tmz_evolve(Ez0, Hx0, Hy0, eps_r, mu_r, steps=40, dt=dt, dx=dx, dy=dy, snapshot_stride=4)
113
+ x = np.arange(N) * dx
114
+ y = np.arange(N) * dy
115
+ X, Y = np.meshgrid(x, y, indexing="ij")
116
+ anim = animate_field_2d(X, Y, frames, times)
117
+ _save(anim, tmp_path, "cavity.gif")
118
+
119
+
120
+ class TestGPEAnimations:
121
+ @pytest.mark.slow
122
+ def test_vortex_precession_animation(self, tmp_path):
123
+ n, length, g = 40, 12.0, 4.0
124
+ X, Y, _, _, K2 = harmonic_trap_grid(n, length)
125
+ V = 0.5 * (X**2 + Y**2)
126
+ psi_gs = gpe_relax(np.exp(-0.5 * (X**2 + Y**2)).astype(complex), V, g, dtau=5e-4, steps=1500, X=X, Y=Y, K2=K2)
127
+ psi_v = gpe_imprint_vortex(psi_gs, X, Y, [(1.0, 0.03)])
128
+ frames, times = gpe_evolve(psi_v, V, g, dt=2e-3, steps=200, K2=K2, snapshot_stride=25)
129
+ extent = (X.min(), X.max(), Y.min(), Y.max())
130
+ anim = animate_density_2d(frames, extent=extent, times=times)
131
+ _save(anim, tmp_path, "vortex.gif")
132
+
133
+ @pytest.mark.slow
134
+ def test_self_focusing_animation(self, tmp_path):
135
+ n, length = 64, 16.0
136
+ X, Y, _, _, K2 = harmonic_trap_grid(n, length)
137
+ V = np.zeros((n, n))
138
+ psi0 = 3.0 * np.exp(-0.5 * (X**2 + Y**2)).astype(complex)
139
+ frames, times = gpe_evolve(psi0, V, g=-1.0, dt=2e-4, steps=200, K2=K2, snapshot_stride=25)
140
+ extent = (X.min(), X.max(), Y.min(), Y.max())
141
+ anim = animate_density_2d(frames, extent=extent, times=times)
142
+ _save(anim, tmp_path, "collapse.gif")
143
+
144
+
145
+ class TestFluxTubeAndCasimirAnimations:
146
+ @pytest.mark.slow
147
+ def test_flux_tube_animation(self, tmp_path):
148
+ anim = animate_flux_tube((80, 20), dx=0.25, dy=0.25, separations=np.linspace(4.0, 16.0, 5))
149
+ _save(anim, tmp_path, "flux_tube.gif")
150
+
151
+ @pytest.mark.slow
152
+ def test_casimir_animation(self, tmp_path):
153
+ anim = animate_casimir_modes(np.linspace(1.0, 5.0, 5))
154
+ _save(anim, tmp_path, "casimir.gif")