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,549 @@
1
+ """Cold plasma waves: the Stix dielectric tensor, dispersion relations, and CMA mapping.
2
+
3
+ Linearizes the multi-fluid cold-plasma equations around a uniform
4
+ background threaded by a uniform :math:`\\mathbf{B}_0` to get the
5
+ dielectric tensor components :math:`S`, :math:`D`, :math:`P` (Stix, 1962)
6
+ in :func:`stix_parameters`, then solves the general dispersion relation
7
+ :math:`\\mathbf{n}\\times(\\mathbf{n}\\times\\mathbf{E}) + \\mathbf{K}\\cdot\\mathbf{E}=0`
8
+ for the refractive index :math:`n=ck/\\omega` at any propagation angle
9
+ :math:`\\theta` to :math:`\\mathbf{B}_0` with :func:`cold_plasma_dispersion`.
10
+ Every named mode -- the parallel-propagating R- and L-waves, the
11
+ perpendicular O- and X-modes, and the low-frequency whistler branch -- is
12
+ a special case of that one quartic in :math:`n^2`.
13
+ :func:`cma_coordinates` maps a plasma state onto the two dimensionless
14
+ axes of the Clemmow-Mullaly-Allis diagram that organizes all of them.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import numpy as np
20
+
21
+ from physicskit import constants as _const
22
+
23
+ __all__ = [
24
+ "QE",
25
+ "ME",
26
+ "MP",
27
+ "EPS0",
28
+ "plasma_frequency",
29
+ "stix_parameters",
30
+ "rl_parameters",
31
+ "cold_plasma_dispersion",
32
+ "whistler_dispersion",
33
+ "cma_coordinates",
34
+ "ion_acoustic_soliton_profile",
35
+ "ion_acoustic_soliton_evolve",
36
+ "alfven_wave_pulse_ic",
37
+ "simulate_alfven_wave",
38
+ ]
39
+
40
+ QE = _const.ELEMENTARY_CHARGE
41
+ """Elementary charge, in Coulombs."""
42
+
43
+ ME = _const.ELECTRON_MASS
44
+ """Electron mass, in kilograms."""
45
+
46
+ MP = _const.PROTON_MASS
47
+ """Proton mass, in kilograms."""
48
+
49
+ EPS0 = _const.VACUUM_PERMITTIVITY
50
+ """Vacuum permittivity, in F/m."""
51
+
52
+
53
+ def plasma_frequency(n: float, q: float = QE, m: float = ME) -> float:
54
+ """Species plasma frequency :math:`\\omega_p = \\sqrt{nq^2/(\\varepsilon_0 m)}`.
55
+
56
+ The natural oscillation frequency of a species displaced from
57
+ quasineutrality: the restoring electric field it builds up is
58
+ proportional to the displacement, making every unmagnetized plasma a
59
+ harmonic oscillator at this frequency -- the very phenomenon Langmuir
60
+ identified in 1928.
61
+
62
+ Parameters
63
+ ----------
64
+ n : float
65
+ Number density in m^-3.
66
+ q : float, default=QE
67
+ Species charge magnitude in Coulombs.
68
+ m : float, default=ME
69
+ Species mass in kilograms.
70
+
71
+ Returns
72
+ -------
73
+ float
74
+ Angular plasma frequency in rad/s.
75
+
76
+ Examples
77
+ --------
78
+ >>> round(float(plasma_frequency(1e19)) / 1e9, 3)
79
+ 178.399
80
+ """
81
+ return np.sqrt(n * q**2 / (EPS0 * m))
82
+
83
+
84
+ def stix_parameters(omega: float, B: float, species) -> tuple:
85
+ """Stix cold-plasma dielectric tensor components :math:`S`, :math:`D`, :math:`P`.
86
+
87
+ Summing each species' contribution to the linearized fluid response
88
+ gives the Hermitian dielectric tensor
89
+
90
+ .. math::
91
+
92
+ \\mathbf{K} = \\begin{pmatrix} S & -iD & 0 \\\\ iD & S & 0 \\\\ 0 & 0 & P \\end{pmatrix},
93
+ \\qquad
94
+ S = 1 - \\sum_s \\frac{\\omega_{ps}^2}{\\omega^2-\\omega_{cs}^2}, \\quad
95
+ D = \\sum_s \\frac{\\omega_{cs}}{\\omega}\\frac{\\omega_{ps}^2}{\\omega^2-\\omega_{cs}^2}, \\quad
96
+ P = 1 - \\sum_s \\frac{\\omega_{ps}^2}{\\omega^2},
97
+
98
+ with each species' signed cyclotron frequency :math:`\\omega_{cs}=q_sB/m_s`
99
+ entering :math:`D` with its own sign -- the source of the
100
+ circular-polarization asymmetry between the R- and L-waves.
101
+
102
+ Parameters
103
+ ----------
104
+ omega : float
105
+ Wave angular frequency in rad/s.
106
+ B : float
107
+ Background magnetic field magnitude in Tesla.
108
+ species : sequence of (float, float, float)
109
+ ``(n, q, m)`` for each plasma species: number density in m^-3,
110
+ signed charge in Coulombs, mass in kilograms.
111
+
112
+ Returns
113
+ -------
114
+ S, D, P : float
115
+ Stix dielectric tensor components (dimensionless).
116
+
117
+ See Also
118
+ --------
119
+ cold_plasma_dispersion : Solves the dispersion relation built from these.
120
+ rl_parameters : The right/left-hand combinations :math:`R=S+D`, :math:`L=S-D`.
121
+
122
+ Examples
123
+ --------
124
+ >>> electrons = (1e19, -QE, ME)
125
+ >>> ions = (1e19, QE, MP)
126
+ >>> S, D, P = stix_parameters(omega=2e9, B=1.0, species=[electrons, ions])
127
+ >>> round(S, 4), round(D, 4), round(P, 4)
128
+ (-2.3143, 90.6954, -7959.8516)
129
+ """
130
+ S, D, P = 1.0, 0.0, 1.0
131
+ for n, q, m in species:
132
+ wp2 = n * q**2 / (EPS0 * m)
133
+ wc = q * B / m
134
+ S -= wp2 / (omega**2 - wc**2)
135
+ D += (wc / omega) * wp2 / (omega**2 - wc**2)
136
+ P -= wp2 / omega**2
137
+ return S, D, P
138
+
139
+
140
+ def rl_parameters(S: float, D: float) -> tuple:
141
+ """Right- and left-hand Stix parameters :math:`R = S+D`, :math:`L = S-D`.
142
+
143
+ :math:`R` and :math:`L` are the dielectric response seen by a purely
144
+ right- or left-hand circularly polarized wave propagating exactly
145
+ along :math:`\\mathbf{B}_0`; the R-wave resonates at the electron
146
+ cyclotron frequency and the L-wave at the ion cyclotron frequency.
147
+
148
+ Parameters
149
+ ----------
150
+ S, D : float
151
+ Stix parameters from :func:`stix_parameters`.
152
+
153
+ Returns
154
+ -------
155
+ R, L : float
156
+ Right- and left-hand dielectric parameters.
157
+
158
+ Examples
159
+ --------
160
+ >>> rl_parameters(S=1.0, D=0.5)
161
+ (1.5, 0.5)
162
+ """
163
+ return S + D, S - D
164
+
165
+
166
+ def cold_plasma_dispersion(theta: float, S: float, D: float, P: float) -> tuple:
167
+ """Solve the cold-plasma dispersion relation for the squared refractive index :math:`n^2`.
168
+
169
+ Substituting a plane wave into
170
+ :math:`\\mathbf{n}\\times(\\mathbf{n}\\times\\mathbf{E})+\\mathbf{K}\\cdot\\mathbf{E}=0`
171
+ for propagation at angle :math:`\\theta` to :math:`\\mathbf{B}_0` gives
172
+ the Appleton-Hartree biquadratic :math:`An^4 - Bn^2 + C = 0` with
173
+
174
+ .. math::
175
+
176
+ A = S\\sin^2\\theta + P\\cos^2\\theta, \\quad
177
+ B = RL\\sin^2\\theta + PS(1+\\cos^2\\theta), \\quad
178
+ C = PRL,
179
+
180
+ which reduces at :math:`\\theta=0` to the decoupled R- and L-waves
181
+ (:math:`n^2=R` or :math:`L`) and at :math:`\\theta=\\pi/2` to the
182
+ O-mode (:math:`n^2=P`) and X-mode (:math:`n^2=RL/S`).
183
+
184
+ Parameters
185
+ ----------
186
+ theta : float
187
+ Angle between the wavevector and :math:`\\mathbf{B}_0`, in radians.
188
+ S, D, P : float
189
+ Stix parameters from :func:`stix_parameters`.
190
+
191
+ Returns
192
+ -------
193
+ n_sq_plus, n_sq_minus : float
194
+ The two roots of the biquadratic (the two cold-plasma wave
195
+ branches at this angle and frequency). A negative root means that
196
+ branch is evanescent rather than propagating.
197
+
198
+ See Also
199
+ --------
200
+ stix_parameters : Supplies ``S``, ``D``, ``P``.
201
+
202
+ Examples
203
+ --------
204
+ Parallel propagation recovers the pure R- and L-wave refractive indices:
205
+
206
+ >>> import numpy as np
207
+ >>> S, D, P = -2.314262935091991, 90.69535621969021, -7959.851640342367
208
+ >>> n2_plus, n2_minus = cold_plasma_dispersion(theta=0.0, S=S, D=D, P=P)
209
+ >>> R, L = rl_parameters(S, D)
210
+ >>> bool(np.isclose(sorted([n2_plus, n2_minus]), sorted([R, L])).all())
211
+ True
212
+ """
213
+ R, L = rl_parameters(S, D)
214
+ A = S * np.sin(theta) ** 2 + P * np.cos(theta) ** 2
215
+ Bc = R * L * np.sin(theta) ** 2 + P * S * (1.0 + np.cos(theta) ** 2)
216
+ C = P * R * L
217
+ disc = Bc**2 - 4.0 * A * C
218
+ sqrt_disc = np.sqrt(disc)
219
+ return (Bc + sqrt_disc) / (2.0 * A), (Bc - sqrt_disc) / (2.0 * A)
220
+
221
+
222
+ def whistler_dispersion(omega: float, wpe: float, wce: float) -> float:
223
+ """Electron-only, parallel-propagation whistler-mode refractive index :math:`n^2 = \\omega_{pe}^2/[\\omega(\\omega_{ce}-\\omega)]`.
224
+
225
+ The low-frequency (:math:`\\omega \\ll \\omega_{ce}`), right-hand
226
+ circularly polarized branch of the R-wave, with ion motion neglected.
227
+ Because :math:`n^2` grows without bound as :math:`\\omega\\to\\omega_{ce}`,
228
+ whistlers slow down sharply as they approach the electron cyclotron
229
+ frequency -- the falling-tone "whistle" heard in radio receivers after
230
+ a lightning stroke launches a broadband pulse that disperses along
231
+ Earth's field lines, with the highest frequencies (closest to
232
+ :math:`\\omega_{ce}`) arriving last.
233
+
234
+ Parameters
235
+ ----------
236
+ omega : float
237
+ Wave angular frequency in rad/s, with :math:`\\omega \\ll \\omega_{ce}`.
238
+ wpe : float
239
+ Electron plasma frequency in rad/s, from :func:`plasma_frequency`.
240
+ wce : float
241
+ Electron cyclotron frequency in rad/s (positive).
242
+
243
+ Returns
244
+ -------
245
+ float
246
+ Squared refractive index :math:`n^2`.
247
+
248
+ See Also
249
+ --------
250
+ cold_plasma_dispersion : The general dispersion relation this is a limit of.
251
+
252
+ Examples
253
+ --------
254
+ Well below the electron cyclotron frequency, it agrees closely with
255
+ the exact electron-only R-wave root of :func:`cold_plasma_dispersion`:
256
+
257
+ >>> wpe, wce = 1.784e11, 1.759e11
258
+ >>> omega = 0.001 * wce
259
+ >>> S, D, P = stix_parameters(omega, B=1.0, species=[(wpe ** 2 * EPS0 * ME / QE ** 2, -QE, ME)])
260
+ >>> R, _ = rl_parameters(S, D)
261
+ >>> n2_approx = whistler_dispersion(omega, wpe, wce)
262
+ >>> round(abs(n2_approx - R) / R, 2)
263
+ 0.0
264
+ """
265
+ return wpe**2 / (omega * (wce - omega))
266
+
267
+
268
+ def cma_coordinates(omega: float, wpe: float, wce: float) -> tuple:
269
+ """Dimensionless :math:`(X, Y)` coordinates of the Clemmow-Mullaly-Allis (CMA) diagram.
270
+
271
+ The CMA diagram partitions the plane :math:`X=\\omega_{pe}^2/\\omega^2`
272
+ (density axis) vs. :math:`Y=\\omega_{ce}/\\omega` (field-strength axis)
273
+ into regions of distinct wave topology -- cutoffs, resonances, and the
274
+ number and polarization of propagating modes -- giving a single map
275
+ of every cold-plasma wave regime from ordinary light waves
276
+ (:math:`X, Y \\to 0`) to the Alfven wave and whistler branches
277
+ (:math:`Y \\gg 1`).
278
+
279
+ Parameters
280
+ ----------
281
+ omega : float
282
+ Wave angular frequency in rad/s.
283
+ wpe : float
284
+ Electron plasma frequency in rad/s.
285
+ wce : float
286
+ Electron cyclotron frequency in rad/s.
287
+
288
+ Returns
289
+ -------
290
+ X, Y : float
291
+ CMA diagram coordinates.
292
+
293
+ Examples
294
+ --------
295
+ >>> cma_coordinates(omega=1.0, wpe=2.0, wce=3.0)
296
+ (4.0, 3.0)
297
+ """
298
+ return (wpe / omega) ** 2, wce / omega
299
+
300
+
301
+ def ion_acoustic_soliton_profile(x: np.ndarray, speed: float, x0: float = 0.0) -> np.ndarray:
302
+ """Exact single-soliton solution of the ion-acoustic Korteweg-de Vries reduction.
303
+
304
+ The reductive-perturbation (Washimi & Taniuti, 1966) expansion of the
305
+ cold-ion-fluid/Boltzmann-electron equations in the weakly nonlinear,
306
+ weakly dispersive limit reduces the ion-acoustic wave problem to the
307
+ KdV equation for the normalized density (or potential) perturbation
308
+ :math:`u` in a frame moving at the ion-sound speed; after the standard
309
+ rescaling of the stretched coordinates it takes the canonical form
310
+ :math:`u_t + 6uu_\\xi + u_{\\xi\\xi\\xi} = 0` -- the same normal form
311
+ every weakly-dispersive weakly-nonlinear wave problem reduces to,
312
+ with the ion-acoustic-specific physics (electron Boltzmann response
313
+ supplying the nonlinearity, ion inertia and Debye-length dispersion
314
+ supplying the :math:`\\partial_\\xi^3` term) fixing only the physical
315
+ unit conversions between :math:`u,\\xi,t` and density, position, and
316
+ time in the ion-sound-speed frame. Its exact traveling-wave solution
317
+ is a single soliton of speed :math:`c` (in the stretched frame) and
318
+ amplitude :math:`c/2`, propagating without change of shape --
319
+ consistent with a real ion-acoustic soliton, whose speed always
320
+ exceeds the linear sound speed by an amount set by its amplitude.
321
+
322
+ Parameters
323
+ ----------
324
+ x : ndarray
325
+ Spatial grid, in the stretched (ion-sound-speed) frame.
326
+ speed : float
327
+ Soliton speed :math:`c` in the stretched frame (amplitude
328
+ :math:`=c/2`); must be positive.
329
+ x0 : float, default=0.0
330
+ Initial center position.
331
+
332
+ Returns
333
+ -------
334
+ ndarray
335
+ :math:`u(x, 0) = \\tfrac{c}{2}\\,\\mathrm{sech}^2\\!\\big(\\tfrac{\\sqrt{c}}{2}(x-x_0)\\big)`.
336
+
337
+ See Also
338
+ --------
339
+ ion_acoustic_soliton_evolve : Propagate this (or any) initial condition forward in time.
340
+
341
+ Examples
342
+ --------
343
+ >>> round(float(ion_acoustic_soliton_profile(0.0, speed=4.0)), 6)
344
+ 2.0
345
+ """
346
+ return (speed / 2.0) * (1.0 / np.cosh(np.sqrt(speed) / 2.0 * (x - x0))) ** 2
347
+
348
+
349
+ def _ion_acoustic_kdv_rhs_hat(u_hat: np.ndarray, k: np.ndarray) -> np.ndarray:
350
+ u = np.real(np.fft.ifft(u_hat))
351
+ ux = np.real(np.fft.ifft(1j * k * u_hat))
352
+ return np.fft.fft(-6.0 * u * ux)
353
+
354
+
355
+ def ion_acoustic_soliton_evolve(u0: np.ndarray, x: np.ndarray, dt: float, steps: int) -> np.ndarray:
356
+ """Evolve an ion-acoustic KdV initial condition forward in time on a periodic domain.
357
+
358
+ A pseudo-spectral Strang-split scheme: the stiff linear dispersion
359
+ :math:`\\partial_\\xi^3` is advanced exactly in Fourier space, and the
360
+ non-stiff nonlinear advection :math:`6uu_\\xi` with RK4 in between --
361
+ structurally the standard splitting for any KdV-type equation, applied
362
+ here directly to the ion-acoustic reduction rather than by importing a
363
+ generic KdV solver, since the physical field this equation governs
364
+ (a Debye-length-normalized density/potential perturbation moving at
365
+ order the ion-sound speed) is specific to this module.
366
+
367
+ Parameters
368
+ ----------
369
+ u0 : ndarray
370
+ Initial field, sampled on the periodic grid ``x``.
371
+ x : ndarray
372
+ Uniformly spaced periodic spatial grid.
373
+ dt : float
374
+ Time step.
375
+ steps : int
376
+ Number of steps to advance.
377
+
378
+ Returns
379
+ -------
380
+ ndarray
381
+ Field after ``steps * dt`` time units.
382
+
383
+ See Also
384
+ --------
385
+ ion_acoustic_soliton_profile : Exact traveling-wave solution this reproduces.
386
+
387
+ Examples
388
+ --------
389
+ A soliton launched at speed :math:`c=4` has advanced by very close to
390
+ :math:`c\\cdot(\\text{steps}\\cdot dt)` and kept its amplitude, since
391
+ KdV solitons propagate without changing shape:
392
+
393
+ >>> import numpy as np
394
+ >>> N, L = 512, 60.0
395
+ >>> x = np.linspace(-L / 2, L / 2, N, endpoint=False)
396
+ >>> u0 = ion_acoustic_soliton_profile(x, speed=4.0, x0=-15.0)
397
+ >>> u = ion_acoustic_soliton_evolve(u0, x, dt=0.0005, steps=4000)
398
+ >>> shift = x[np.argmax(u)] - x[np.argmax(u0)]
399
+ >>> bool(abs(shift - 4.0 * 4000 * 0.0005) < 0.5)
400
+ True
401
+ >>> bool(abs(u.max() - u0.max()) < 0.05)
402
+ True
403
+ """
404
+ k = 2.0 * np.pi * np.fft.fftfreq(len(x), d=x[1] - x[0])
405
+ ik3 = 1j * k**3
406
+ u_hat = np.fft.fft(u0)
407
+ for _ in range(steps):
408
+ u_hat = u_hat * np.exp(ik3 * dt / 2.0)
409
+ k1 = _ion_acoustic_kdv_rhs_hat(u_hat, k)
410
+ k2 = _ion_acoustic_kdv_rhs_hat(u_hat + dt / 2.0 * k1, k)
411
+ k3 = _ion_acoustic_kdv_rhs_hat(u_hat + dt / 2.0 * k2, k)
412
+ k4 = _ion_acoustic_kdv_rhs_hat(u_hat + dt * k3, k)
413
+ u_hat = u_hat + dt / 6.0 * (k1 + 2.0 * k2 + 2.0 * k3 + k4)
414
+ u_hat = u_hat * np.exp(ik3 * dt / 2.0)
415
+ return np.real(np.fft.ifft(u_hat))
416
+
417
+
418
+ def alfven_wave_pulse_ic(x: np.ndarray, x0: float, width: float, amplitude: float) -> tuple:
419
+ """Initial condition for a transverse Alfven-wave pulse launched from rest.
420
+
421
+ A Gaussian transverse-field pulse :math:`B_y(x,0)=B_1 e^{-[(x-x_0)/w]^2}`
422
+ with the transverse velocity perturbation initially zero -- a "plucked
423
+ string" initial condition. Because the linearized ideal-MHD Alfven-wave
424
+ equations (:func:`simulate_alfven_wave`) are the same non-dispersive wave
425
+ equation a string obeys, a disturbance released from rest splits exactly
426
+ in half and propagates as two identical, oppositely directed pulses at
427
+ :math:`\\pm v_A` -- exactly the field-line-plucking picture Alfven's
428
+ original 1942 analogy describes.
429
+
430
+ Parameters
431
+ ----------
432
+ x : ndarray
433
+ Spatial grid (periodic).
434
+ x0 : float
435
+ Pulse center.
436
+ width : float
437
+ Gaussian pulse width.
438
+ amplitude : float
439
+ Peak transverse field perturbation :math:`B_1`.
440
+
441
+ Returns
442
+ -------
443
+ By0, vy0 : ndarray
444
+ Initial transverse magnetic field and velocity perturbations, same
445
+ shape as `x` (`vy0` identically zero).
446
+
447
+ See Also
448
+ --------
449
+ simulate_alfven_wave : Evolves this initial condition forward in time.
450
+
451
+ Examples
452
+ --------
453
+ >>> import numpy as np
454
+ >>> x = np.linspace(-10, 10, 64, endpoint=False)
455
+ >>> By0, vy0 = alfven_wave_pulse_ic(x, x0=0.0, width=1.0, amplitude=0.1)
456
+ >>> bool(np.all(vy0 == 0.0))
457
+ True
458
+ """
459
+ By0 = amplitude * np.exp(-(((x - x0) / width) ** 2))
460
+ vy0 = np.zeros_like(x)
461
+ return By0, vy0
462
+
463
+
464
+ def _alfven_rhs(By: np.ndarray, vy: np.ndarray, k: np.ndarray, B0: float, rho0: float, mu0: float) -> tuple:
465
+ dBy_dx = np.real(np.fft.ifft(1j * k * np.fft.fft(By)))
466
+ dvy_dx = np.real(np.fft.ifft(1j * k * np.fft.fft(vy)))
467
+ dBy_dt = B0 * dvy_dx
468
+ dvy_dt = (B0 / (mu0 * rho0)) * dBy_dx
469
+ return dBy_dt, dvy_dt
470
+
471
+
472
+ def simulate_alfven_wave(By0: np.ndarray, vy0: np.ndarray, x: np.ndarray, dt: float, steps: int, B0: float, rho0: float, mu0: float = 1.0) -> dict:
473
+ """Time-step the linearized 1D ideal-MHD Alfven-wave equations with a pseudo-spectral RK4 scheme.
474
+
475
+ Advances the coupled transverse induction and momentum equations
476
+
477
+ .. math::
478
+
479
+ \\partial_t B_y = B_0\\,\\partial_x v_y, \\qquad
480
+ \\rho_0\\,\\partial_t v_y = \\frac{B_0}{\\mu_0}\\,\\partial_x B_y,
481
+
482
+ which combine into the non-dispersive wave equation
483
+ :math:`\\partial_t^2 B_y = v_A^2\\,\\partial_x^2 B_y` with
484
+ :math:`v_A=B_0/\\sqrt{\\mu_0\\rho_0}` (:func:`physicskit.plasma.mhd.alfven_speed`).
485
+ Spatial derivatives are evaluated exactly via FFT (as elsewhere in this
486
+ package's periodic-domain solvers) and advanced in time with classical
487
+ RK4; a uniform background field and density are assumed throughout
488
+ (linear, ideal, cold-background MHD -- no thermal pressure term enters
489
+ a purely transverse, incompressible perturbation like this one).
490
+
491
+ Unlike :func:`physicskit.plasma.mhd.alfven_speed` (SI units), this
492
+ solver defaults to normalized units (``mu0=1.0``, matching order-unity
493
+ `B0`/`rho0`) since with the true SI :math:`\\mu_0\\approx1.26\\times10^{-6}`
494
+ a Tesla-scale field gives an Alfven speed of order :math:`10^5`-:math:`10^6`
495
+ m/s, requiring correspondingly tiny time steps to satisfy the CFL bound
496
+ below; pass ``mu0=physicskit.plasma.mhd.MU0`` explicitly for SI-consistent
497
+ parameters and scale `dt` accordingly.
498
+
499
+ Parameters
500
+ ----------
501
+ By0, vy0 : ndarray
502
+ Initial transverse field and velocity perturbations, e.g. from
503
+ :func:`alfven_wave_pulse_ic`.
504
+ x : ndarray
505
+ Uniformly spaced periodic spatial grid.
506
+ dt : float
507
+ Time step; the CFL condition :math:`v_A\\,dt \\le dx` should be
508
+ respected for the explicit RK4 stepping to remain stable.
509
+ steps : int
510
+ Number of RK4 steps to advance.
511
+ B0 : float
512
+ Background field magnitude.
513
+ rho0 : float
514
+ Background mass density.
515
+ mu0 : float, default=1.0
516
+ Vacuum permeability (normalized units by default; see above).
517
+
518
+ Returns
519
+ -------
520
+ dict
521
+ ``{"By": final transverse field, "vy": final transverse velocity}``.
522
+
523
+ See Also
524
+ --------
525
+ alfven_wave_pulse_ic : Builds the initial condition consumed here.
526
+ physicskit.plasma.mhd.alfven_speed : The propagation speed this recovers.
527
+
528
+ Examples
529
+ --------
530
+ >>> import numpy as np
531
+ >>> x = np.linspace(-20, 20, 256, endpoint=False)
532
+ >>> By0, vy0 = alfven_wave_pulse_ic(x, x0=0.0, width=1.0, amplitude=0.1)
533
+ >>> result = simulate_alfven_wave(By0, vy0, x, dt=0.002, steps=2000, B0=1.0, rho0=1.0)
534
+ >>> result["By"].shape
535
+ (256,)
536
+ >>> bool(np.isfinite(result["By"]).all())
537
+ True
538
+ """
539
+ k = 2.0 * np.pi * np.fft.fftfreq(len(x), d=x[1] - x[0])
540
+ By = np.array(By0, dtype=float, copy=True)
541
+ vy = np.array(vy0, dtype=float, copy=True)
542
+ for _ in range(steps):
543
+ k1B, k1v = _alfven_rhs(By, vy, k, B0, rho0, mu0)
544
+ k2B, k2v = _alfven_rhs(By + dt / 2 * k1B, vy + dt / 2 * k1v, k, B0, rho0, mu0)
545
+ k3B, k3v = _alfven_rhs(By + dt / 2 * k2B, vy + dt / 2 * k2v, k, B0, rho0, mu0)
546
+ k4B, k4v = _alfven_rhs(By + dt * k3B, vy + dt * k3v, k, B0, rho0, mu0)
547
+ By = By + dt / 6 * (k1B + 2 * k2B + 2 * k3B + k4B)
548
+ vy = vy + dt / 6 * (k1v + 2 * k2v + 2 * k3v + k4v)
549
+ return {"By": By, "vy": vy}