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,417 @@
1
+ """Time-evolving current-sheet instabilities: magnetic reconnection and Weibel filamentation.
2
+
3
+ Both problems in this module involve a current-carrying layer that breaks up
4
+ under a collective instability, but at opposite ends of the fluid-kinetic
5
+ spectrum. Magnetic reconnection (:func:`reconnection_harris_ic`,
6
+ :func:`simulate_reconnection`) is treated here as a *kinematic resistive-MHD*
7
+ problem: the induction equation for the flux function :math:`\\psi(x,y,t)` is
8
+ evolved with a prescribed inflow velocity rather than a self-consistently
9
+ solved momentum equation, which is the standard first simplification made
10
+ before attempting full two-fluid or MHD reconnection (the prescribed-flow
11
+ approximation underlying, e.g., the original Sweet-Parker and Petschek
12
+ estimates in :mod:`physicskit.plasma.mhd`). The Weibel/filamentation
13
+ instability (:func:`weibel_growth_rate`, :func:`simulate_weibel_filamentation`)
14
+ is treated as a *reduced linear/quasi-linear* problem: rather than extending
15
+ the 1D-space/1D-velocity PIC machinery of :mod:`physicskit.plasma.kinetic` to
16
+ a full 2D-in-velocity, electromagnetic PIC code (a much larger undertaking),
17
+ a spectrum of transverse-current Fourier modes is seeded with random phases
18
+ and each mode's amplitude is evolved analytically according to the known
19
+ linear Weibel growth rate -- exact for as long as the linear approximation
20
+ holds, and sufficient to show the characteristic real-space current
21
+ filaments forming and growing.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import numpy as np
27
+
28
+ from physicskit import constants as _const
29
+
30
+ __all__ = [
31
+ "reconnection_harris_ic",
32
+ "reconnection_inflow_velocity",
33
+ "reconnection_field_from_flux",
34
+ "simulate_reconnection",
35
+ "weibel_growth_rate",
36
+ "weibel_fastest_growing_mode",
37
+ "simulate_weibel_filamentation",
38
+ ]
39
+
40
+
41
+ def reconnection_harris_ic(nx: int, ny: int, Lx: float, Ly: float, sheet_width: float, perturbation_amplitude: float, k_modes: int = 1) -> np.ndarray:
42
+ """Flux-function initial condition: a Harris current sheet with an X-point-seeding ripple.
43
+
44
+ The unperturbed Harris sheet :math:`\\psi_0(y) = -B_0 L\\ln\\cosh(y/L)`
45
+ gives an antiparallel reconnecting field
46
+ :math:`B_x = -\\partial_y\\psi_0 = B_0\\tanh(y/L)` that reverses sign
47
+ across :math:`y=0` -- the classic current-sheet configuration in which
48
+ reconnection is normally studied. Adding a small ripple
49
+ :math:`\\psi_1 = \\epsilon\\cos(k x)\\,\\mathrm{sech}^2(y/L)`, localized to
50
+ the sheet and periodic in :math:`x`, is the standard tearing-mode-like
51
+ seed: it breaks the translational symmetry along the sheet just enough
52
+ to create one X-point/O-point pair per wavelength, without which the
53
+ sheet would stay a stationary equilibrium forever regardless of
54
+ resistivity.
55
+
56
+ Parameters
57
+ ----------
58
+ nx, ny : int
59
+ Grid points along `x` (periodic, along the sheet) and `y`
60
+ (across the sheet).
61
+ Lx, Ly : float
62
+ Domain size in `x` and `y`; the domain spans
63
+ ``[0, Lx) x [-Ly/2, Ly/2)``.
64
+ sheet_width : float
65
+ Current-sheet half-thickness :math:`L` (with :math:`B_0=1` in these
66
+ normalized units).
67
+ perturbation_amplitude : float
68
+ Amplitude :math:`\\epsilon` of the seeding ripple.
69
+ k_modes : int, default=1
70
+ Number of full wavelengths of the ripple fit into `Lx`.
71
+
72
+ Returns
73
+ -------
74
+ ndarray, shape (nx, ny)
75
+ Flux function :math:`\\psi(x, y)`.
76
+
77
+ See Also
78
+ --------
79
+ simulate_reconnection : Evolves this initial condition forward in time.
80
+
81
+ Examples
82
+ --------
83
+ >>> psi0 = reconnection_harris_ic(64, 64, Lx=20.0, Ly=20.0, sheet_width=1.0, perturbation_amplitude=0.1)
84
+ >>> psi0.shape
85
+ (64, 64)
86
+ """
87
+ x = np.linspace(0.0, Lx, nx, endpoint=False)
88
+ y = np.linspace(-Ly / 2.0, Ly / 2.0, ny, endpoint=False)
89
+ X, Y = np.meshgrid(x, y, indexing="ij")
90
+ psi0 = -sheet_width * np.log(np.cosh(Y / sheet_width))
91
+ k = 2.0 * np.pi * k_modes / Lx
92
+ psi1 = perturbation_amplitude * np.cos(k * X) / np.cosh(Y / sheet_width) ** 2
93
+ return psi0 + psi1
94
+
95
+
96
+ def reconnection_inflow_velocity(X: np.ndarray, Y: np.ndarray, v0: float, Lx: float, Ly: float) -> tuple:
97
+ """Prescribed stagnation-point inflow/outflow velocity field around the reconnection X-point.
98
+
99
+ A simple incompressible stagnation flow, :math:`v_x=+v_0 x'/L_x`,
100
+ :math:`v_y=-v_0 y'/L_y` (with :math:`x', y'` measured from the nearest
101
+ X-point at the domain center), that converges onto the X-point from
102
+ above and below and squirts back out sideways as reconnection outflow
103
+ "jets" -- exactly the inflow/outflow pattern Sweet-Parker and Petschek
104
+ reconnection assume, here imposed directly rather than derived from a
105
+ momentum equation (see the module docstring).
106
+
107
+ Parameters
108
+ ----------
109
+ X, Y : ndarray
110
+ Coordinate grids, as built by :func:`reconnection_harris_ic`.
111
+ v0 : float
112
+ Characteristic inflow speed.
113
+ Lx, Ly : float
114
+ Domain size in `x` and `y`, used to center the stagnation point.
115
+
116
+ Returns
117
+ -------
118
+ vx, vy : ndarray
119
+ Velocity components, same shape as `X`.
120
+
121
+ Examples
122
+ --------
123
+ >>> import numpy as np
124
+ >>> X, Y = np.meshgrid(np.linspace(0, 20, 8, endpoint=False), np.linspace(-10, 10, 8, endpoint=False), indexing="ij")
125
+ >>> vx, vy = reconnection_inflow_velocity(X, Y, v0=0.1, Lx=20.0, Ly=20.0)
126
+ >>> vx.shape
127
+ (8, 8)
128
+ """
129
+ Xc = np.mod(X - Lx / 2.0 + Lx / 2.0, Lx) - Lx / 2.0
130
+ vx = v0 * Xc / (Lx / 2.0)
131
+ vy = -v0 * Y / (Ly / 2.0)
132
+ return vx, vy
133
+
134
+
135
+ def reconnection_field_from_flux(psi: np.ndarray, dx: float, dy: float) -> tuple:
136
+ """Recover the in-plane magnetic field :math:`(B_x, B_y) = (\\partial_y\\psi, -\\partial_x\\psi)` from the flux function.
137
+
138
+ Parameters
139
+ ----------
140
+ psi : ndarray, shape (nx, ny)
141
+ Flux function, periodic in both directions.
142
+ dx, dy : float
143
+ Grid spacing along `x` and `y`.
144
+
145
+ Returns
146
+ -------
147
+ Bx, By : ndarray, shape (nx, ny)
148
+ In-plane magnetic field components.
149
+
150
+ Examples
151
+ --------
152
+ >>> import numpy as np
153
+ >>> psi = reconnection_harris_ic(32, 32, Lx=20.0, Ly=20.0, sheet_width=1.0, perturbation_amplitude=0.0)
154
+ >>> Bx, By = reconnection_field_from_flux(psi, dx=20.0 / 32, dy=20.0 / 32)
155
+ >>> bool(np.all(Bx[:, 16] * Bx[:, 15] <= 0))
156
+ True
157
+ """
158
+ dpsi_dy = (np.roll(psi, -1, axis=1) - np.roll(psi, 1, axis=1)) / (2.0 * dy)
159
+ dpsi_dx = (np.roll(psi, -1, axis=0) - np.roll(psi, 1, axis=0)) / (2.0 * dx)
160
+ return dpsi_dy, -dpsi_dx
161
+
162
+
163
+ def _laplacian_periodic(f: np.ndarray, dx: float, dy: float) -> np.ndarray:
164
+ d2x = (np.roll(f, -1, axis=0) - 2.0 * f + np.roll(f, 1, axis=0)) / dx**2
165
+ d2y = (np.roll(f, -1, axis=1) - 2.0 * f + np.roll(f, 1, axis=1)) / dy**2
166
+ return d2x + d2y
167
+
168
+
169
+ def simulate_reconnection(psi0: np.ndarray, eta: float, v0: float, dt: float, steps: int, Lx: float, Ly: float) -> dict:
170
+ """Time-step the kinematic resistive induction equation :math:`\\partial_t\\psi = \\eta\\nabla^2\\psi - \\mathbf{v}\\cdot\\nabla\\psi`.
171
+
172
+ A doubly periodic, second-order central-difference, explicit (forward
173
+ Euler in time) finite-difference solve. With a prescribed velocity
174
+ field rather than one obtained from solving the momentum equation
175
+ (see the module docstring), this reduces reconnection to pure flux
176
+ transport-and-diffusion: the inflow (:func:`reconnection_inflow_velocity`)
177
+ advects oppositely directed flux into the X-point, where resistive
178
+ diffusion (the :math:`\\eta\\nabla^2\\psi` term) is the only mechanism
179
+ that can actually break and reconnect field lines -- exactly Faraday's
180
+ law with an Ohmic (rather than ideal) Ohm's law, restricted to the
181
+ kinematic (fixed-flow) limit.
182
+
183
+ Explicit forward-Euler time-stepping is only conditionally stable:
184
+ the diffusive term requires :math:`\\eta\\,dt \\lesssim \\tfrac{1}{4}\\min(dx,dy)^2`
185
+ and the advective term requires the Courant condition
186
+ :math:`v_0\\,dt \\lesssim \\min(dx, dy)`. Both are the caller's
187
+ responsibility to satisfy by choosing `dt` appropriately; unstable
188
+ combinations manifest as exponentially growing grid-scale noise.
189
+
190
+ Parameters
191
+ ----------
192
+ psi0 : ndarray, shape (nx, ny)
193
+ Initial flux function, e.g. from :func:`reconnection_harris_ic`.
194
+ eta : float
195
+ Resistivity (magnetic diffusivity).
196
+ v0 : float
197
+ Characteristic inflow speed for :func:`reconnection_inflow_velocity`.
198
+ dt : float
199
+ Time step.
200
+ steps : int
201
+ Number of forward-Euler steps to advance.
202
+ Lx, Ly : float
203
+ Domain size in `x` and `y`.
204
+
205
+ Returns
206
+ -------
207
+ dict
208
+ ``{"psi": final flux function, "Bx": ..., "By": ...}``.
209
+
210
+ See Also
211
+ --------
212
+ reconnection_harris_ic : Builds the initial condition consumed here.
213
+ physicskit.plasma.mhd.sweet_parker_rate : The steady-state reconnection
214
+ rate this kinematic model is a simplified, time-dependent analogue of.
215
+
216
+ Examples
217
+ --------
218
+ >>> import numpy as np
219
+ >>> psi0 = reconnection_harris_ic(48, 48, Lx=20.0, Ly=20.0, sheet_width=1.0, perturbation_amplitude=0.2)
220
+ >>> result = simulate_reconnection(psi0, eta=0.02, v0=0.05, dt=0.02, steps=50, Lx=20.0, Ly=20.0)
221
+ >>> result["psi"].shape
222
+ (48, 48)
223
+ >>> bool(np.all(np.isfinite(result["psi"])))
224
+ True
225
+ """
226
+ nx, ny = psi0.shape
227
+ dx, dy = Lx / nx, Ly / ny
228
+ x = np.linspace(0.0, Lx, nx, endpoint=False)
229
+ y = np.linspace(-Ly / 2.0, Ly / 2.0, ny, endpoint=False)
230
+ X, Y = np.meshgrid(x, y, indexing="ij")
231
+ vx, vy = reconnection_inflow_velocity(X, Y, v0, Lx, Ly)
232
+
233
+ psi = np.array(psi0, dtype=float, copy=True)
234
+ for _ in range(steps):
235
+ dpsi_dx = (np.roll(psi, -1, axis=0) - np.roll(psi, 1, axis=0)) / (2.0 * dx)
236
+ dpsi_dy = (np.roll(psi, -1, axis=1) - np.roll(psi, 1, axis=1)) / (2.0 * dy)
237
+ rhs = eta * _laplacian_periodic(psi, dx, dy) - (vx * dpsi_dx + vy * dpsi_dy)
238
+ psi = psi + dt * rhs
239
+
240
+ Bx, By = reconnection_field_from_flux(psi, dx, dy)
241
+ return {"psi": psi, "Bx": Bx, "By": By}
242
+
243
+
244
+ def weibel_growth_rate(k: np.ndarray, wpe: float, temperature_anisotropy: float, c: float = _const.C) -> np.ndarray:
245
+ """Linear growth rate of the (non-relativistic, cold-parallel-limit) Weibel/filamentation instability.
246
+
247
+ For an electron distribution anisotropic between the direction of
248
+ wave propagation (temperature :math:`T_\\parallel`, taken cold here)
249
+ and the transverse direction (temperature :math:`T_\\perp`), the
250
+ electromagnetic mode with wavevector :math:`\\mathbf{k}` transverse to
251
+ the anisotropy axis is purely growing (Weibel, 1959) with
252
+
253
+ .. math::
254
+
255
+ \\gamma(k)^2 = \\omega_{pe}^2\\left(\\frac{T_\\perp}{T_\\parallel}-1\\right) - k^2 c^2,
256
+
257
+ unstable for :math:`T_\\perp > T_\\parallel` and only up to the cutoff
258
+ :math:`k_{max} = (\\omega_{pe}/c)\\sqrt{T_\\perp/T_\\parallel - 1}` --
259
+ beyond which the field's magnetic tension (the :math:`k^2c^2` term)
260
+ overcomes the free energy the anisotropy supplies. Growing transverse
261
+ magnetic perturbations pinch counter-streaming electron sub-populations
262
+ into spatially separated current channels: the filaments this
263
+ instability is named for.
264
+
265
+ Parameters
266
+ ----------
267
+ k : ndarray or float
268
+ Wavenumber(s), transverse to the anisotropy axis.
269
+ wpe : float
270
+ Electron plasma frequency.
271
+ temperature_anisotropy : float
272
+ The ratio :math:`T_\\perp/T_\\parallel`; must exceed 1 for any
273
+ instability.
274
+ c : float, default=physicskit.constants.C
275
+ Speed of light, in the same units `k` and `wpe` combine to give
276
+ (SI by default).
277
+
278
+ Returns
279
+ -------
280
+ ndarray or float
281
+ Growth rate :math:`\\gamma(k)`, clipped to zero for stable (real
282
+ or imaginary-:math:`\\gamma^2<0`) wavenumbers.
283
+
284
+ See Also
285
+ --------
286
+ weibel_fastest_growing_mode : The wavenumber maximizing this growth rate.
287
+ simulate_weibel_filamentation : Superposes modes growing at this rate.
288
+
289
+ Examples
290
+ --------
291
+ >>> import numpy as np
292
+ >>> round(float(weibel_growth_rate(k=0.0, wpe=1.0, temperature_anisotropy=4.0)), 6)
293
+ 1.732051
294
+ >>> bool(weibel_growth_rate(k=1e10, wpe=1.0, temperature_anisotropy=4.0) == 0.0)
295
+ True
296
+ """
297
+ k = np.asarray(k, dtype=float)
298
+ gamma_sq = wpe**2 * (temperature_anisotropy - 1.0) - (k * c) ** 2
299
+ return np.sqrt(np.clip(gamma_sq, 0.0, None))
300
+
301
+
302
+ def weibel_fastest_growing_mode(wpe: float, temperature_anisotropy: float, c: float = _const.C) -> tuple:
303
+ """Wavenumber and growth rate of the fastest-growing Weibel mode.
304
+
305
+ For the growth-rate law of :func:`weibel_growth_rate`,
306
+ :math:`\\gamma(k)^2` is maximized at :math:`k=0` (long wavelength,
307
+ where the stabilizing field-tension term vanishes), giving
308
+ :math:`\\gamma_{max}=\\omega_{pe}\\sqrt{T_\\perp/T_\\parallel-1}` -- the
309
+ growth rate used to set the overall filament-growth timescale in
310
+ :func:`simulate_weibel_filamentation`, even though the *dominant
311
+ filament spacing* in a real (finite-seed) simulation is set by which
312
+ finite-:math:`k` modes happen to be seeded with the largest initial
313
+ amplitude, since every :math:`k` below cutoff grows, just more slowly
314
+ farther from :math:`k=0`.
315
+
316
+ Parameters
317
+ ----------
318
+ wpe : float
319
+ Electron plasma frequency.
320
+ temperature_anisotropy : float
321
+ The ratio :math:`T_\\perp/T_\\parallel`; must exceed 1.
322
+ c : float, default=physicskit.constants.C
323
+ Speed of light.
324
+
325
+ Returns
326
+ -------
327
+ k_max_growth, gamma_max : float
328
+ The (zero) wavenumber of maximum growth and the corresponding
329
+ growth rate, and the cutoff wavenumber :func:`weibel_growth_rate`
330
+ vanishes beyond.
331
+
332
+ Examples
333
+ --------
334
+ >>> k0, gamma_max = weibel_fastest_growing_mode(wpe=1.0, temperature_anisotropy=4.0)
335
+ >>> k0
336
+ 0.0
337
+ >>> round(gamma_max, 6)
338
+ 1.732051
339
+ """
340
+ if temperature_anisotropy <= 1.0:
341
+ return 0.0, 0.0
342
+ gamma_max = wpe * np.sqrt(temperature_anisotropy - 1.0)
343
+ return 0.0, float(gamma_max)
344
+
345
+
346
+ def simulate_weibel_filamentation(
347
+ x: np.ndarray, t: np.ndarray, wpe: float, temperature_anisotropy: float, n_modes: int = 12, k_max_factor: float = 0.9, seed: int = 0
348
+ ) -> np.ndarray:
349
+ """Reduced quasi-linear Weibel filamentation model: a spectrum of independently growing current modes.
350
+
351
+ Seeds `n_modes` transverse-current Fourier modes with small random
352
+ amplitudes and phases, spanning wavenumbers up to
353
+ ``k_max_factor`` times the linear cutoff :math:`k_{max}` of
354
+ :func:`weibel_growth_rate`, and evolves each mode's amplitude
355
+ independently as :math:`a_k(t) = a_k(0)\\,e^{\\gamma(k)t}` -- exact
356
+ linear theory, valid until the fastest-growing filaments approach
357
+ nonlinear saturation (order-unity current perturbation), at which
358
+ point real filamentation departs from this superposition (mode
359
+ coupling, filament merging) that this reduced model does not capture.
360
+ This stands in for a full 2D-in-velocity electromagnetic PIC
361
+ simulation; see the module docstring for why.
362
+
363
+ Parameters
364
+ ----------
365
+ x : ndarray, shape (nx,)
366
+ Spatial grid (periodic).
367
+ t : ndarray, shape (nt,)
368
+ Times at which to evaluate the current pattern.
369
+ wpe : float
370
+ Electron plasma frequency.
371
+ temperature_anisotropy : float
372
+ The ratio :math:`T_\\perp/T_\\parallel`; must exceed 1.
373
+ n_modes : int, default=12
374
+ Number of Fourier modes to seed.
375
+ k_max_factor : float, default=0.9
376
+ Fraction of the linear cutoff wavenumber up to which modes are
377
+ seeded (kept below 1 so every seeded mode is genuinely unstable).
378
+ seed : int, default=0
379
+ Random seed for the initial mode amplitudes and phases.
380
+
381
+ Returns
382
+ -------
383
+ ndarray, shape (nt, nx)
384
+ Transverse current density :math:`J_y(x, t)`, in units where the
385
+ initial per-mode amplitude is order unity (i.e. a normalized,
386
+ not absolute, current).
387
+
388
+ See Also
389
+ --------
390
+ weibel_growth_rate : The per-mode growth rate used here.
391
+
392
+ Examples
393
+ --------
394
+ >>> import numpy as np
395
+ >>> x = np.linspace(0, 20.0, 128, endpoint=False)
396
+ >>> t = np.linspace(0, 5.0, 10)
397
+ >>> J = simulate_weibel_filamentation(x, t, wpe=1.0, temperature_anisotropy=4.0, n_modes=6, seed=0)
398
+ >>> J.shape
399
+ (10, 128)
400
+ >>> bool(np.std(J[-1]) > np.std(J[0]))
401
+ True
402
+ """
403
+ rng = np.random.default_rng(seed)
404
+ c = _const.C
405
+ k_max = (wpe / c) * np.sqrt(max(temperature_anisotropy - 1.0, 1e-12))
406
+ k_modes = np.linspace(k_max / n_modes, k_max_factor * k_max, n_modes)
407
+ amplitudes0 = rng.uniform(0.5, 1.0, n_modes)
408
+ phases = rng.uniform(0.0, 2.0 * np.pi, n_modes)
409
+ gammas = weibel_growth_rate(k_modes, wpe, temperature_anisotropy, c=c)
410
+
411
+ t = np.asarray(t, dtype=float)
412
+ x = np.asarray(x, dtype=float)
413
+ growth = np.exp(np.outer(t, gammas))
414
+ amplitudes = amplitudes0[None, :] * growth
415
+ phase_arg = k_modes[None, None, :] * x[None, :, None] + phases[None, None, :]
416
+ J = np.sum(amplitudes[:, None, :] * np.cos(phase_arg), axis=2)
417
+ return J