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,91 @@
1
+ """Coverage for physicskit.fluids.visualizers's static plotting functions
2
+ (previously entirely untested): plot_shock_tube_profiles, plot_streamlines,
3
+ plot_vorticity_field, plot_pressure_coefficient, plot_energy_spectrum --
4
+ including the ax=<given> branch and the optional-overlay branches. All pure
5
+ matplotlib, small inputs -- fast."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import matplotlib.pyplot as plt
10
+ import numpy as np
11
+ from matplotlib.figure import Figure
12
+
13
+ from physicskit.fluids.systems.compressible_flow import sod_shock_tube
14
+ from physicskit.fluids.systems.potential_flow import pressure_coefficient
15
+ from physicskit.fluids.utils.spectral_analysis import energy_spectrum
16
+ from physicskit.fluids.visualizers.compressible import plot_shock_tube_profiles
17
+ from physicskit.fluids.visualizers.flow_fields import plot_streamlines, plot_vorticity_field
18
+ from physicskit.fluids.visualizers.potential_flow import plot_pressure_coefficient
19
+ from physicskit.fluids.visualizers.spectra import plot_energy_spectrum
20
+
21
+
22
+ def test_plot_shock_tube_profiles_returns_three_axes():
23
+ result = sod_shock_tube(nx=50, t_final=0.15)
24
+ fig, axes = plot_shock_tube_profiles(result["x"], result["rho"], result["u"], result["p"])
25
+ assert isinstance(fig, Figure)
26
+ assert len(axes) == 3
27
+ for ax in axes:
28
+ assert len(ax.lines) == 1
29
+
30
+
31
+ def test_plot_streamlines_default_and_given_ax():
32
+ x = np.linspace(-1, 1, 10)
33
+ X, Y = np.meshgrid(x, x, indexing="ij")
34
+ u, v = -Y, X
35
+ fig0, ax0 = plot_streamlines(X, Y, u, v)
36
+ assert isinstance(fig0, Figure)
37
+
38
+ fig, ax = plt.subplots()
39
+ _, ax_given = plot_streamlines(X, Y, u, v, ax=ax)
40
+ assert ax_given is ax
41
+
42
+
43
+ def test_plot_vorticity_field_given_ax_and_with_streamline_overlay():
44
+ x = np.linspace(-1, 1, 10)
45
+ X, Y = np.meshgrid(x, x, indexing="ij")
46
+ omega = np.sin(X) * np.cos(Y)
47
+ u, v = -Y, X
48
+
49
+ fig0, ax0 = plot_vorticity_field(X, Y, omega)
50
+ assert isinstance(fig0, Figure)
51
+
52
+ fig, ax = plt.subplots()
53
+ _, ax_given = plot_vorticity_field(X, Y, omega, ax=ax)
54
+ assert ax_given is ax
55
+ assert len(ax.lines) == 0 # no streamlines without u, v
56
+
57
+ fig2, ax2 = plt.subplots()
58
+ _, ax2_given = plot_vorticity_field(X, Y, omega, u=u, v=v, ax=ax2)
59
+ assert ax2_given is ax2
60
+ assert ax2.lines or ax2.collections # streamplot overlay was drawn
61
+
62
+
63
+ def test_plot_pressure_coefficient_given_ax():
64
+ theta = np.linspace(0, 2 * np.pi, 30)
65
+ Cp = pressure_coefficient(u=np.cos(theta), v=np.sin(theta), U_inf=1.0)
66
+ fig0, ax0 = plot_pressure_coefficient(theta, Cp)
67
+ assert isinstance(fig0, Figure)
68
+
69
+ fig, ax = plt.subplots()
70
+ _, ax_given = plot_pressure_coefficient(theta, Cp, ax=ax)
71
+ assert ax_given is ax
72
+
73
+
74
+ def test_plot_energy_spectrum_given_ax_and_without_kolmogorov_line():
75
+ n, length = 32, 2 * np.pi
76
+ x = np.linspace(0, length, n, endpoint=False)
77
+ X, Y = np.meshgrid(x, x, indexing="ij")
78
+ u, v = np.sin(3 * Y), np.sin(3 * X)
79
+ k, E = energy_spectrum(u, v, length)
80
+
81
+ fig0, ax0 = plot_energy_spectrum(k, E)
82
+ assert isinstance(fig0, Figure)
83
+
84
+ fig, ax = plt.subplots()
85
+ _, ax_given = plot_energy_spectrum(k, E, ax=ax)
86
+ assert ax_given is ax
87
+ assert len(ax.lines) == 2 # spectrum + Kolmogorov reference
88
+
89
+ fig2, ax2 = plt.subplots()
90
+ plot_energy_spectrum(k, E, ax=ax2, show_kolmogorov=False)
91
+ assert len(ax2.lines) == 1 # spectrum only
@@ -0,0 +1,100 @@
1
+ import numpy as np
2
+ import pytest
3
+
4
+ from physicskit.fluids.exceptions import InvalidParameterError
5
+ from physicskit.fluids.utils.dimensionless import (
6
+ froude_number,
7
+ mach_number,
8
+ reynolds_number,
9
+ strouhal_number,
10
+ weber_number,
11
+ )
12
+ from physicskit.fluids.utils.spectral_analysis import energy_spectrum, kolmogorov_reference_slope
13
+
14
+
15
+ def test_reynolds_number_formula():
16
+ assert reynolds_number(velocity=2.0, length=0.1, nu=0.02) == pytest.approx(10.0)
17
+
18
+
19
+ def test_reynolds_number_rejects_nonpositive_viscosity():
20
+ with pytest.raises(InvalidParameterError):
21
+ reynolds_number(velocity=1.0, length=1.0, nu=0.0)
22
+
23
+
24
+ def test_reynolds_number_rejects_nonpositive_length():
25
+ with pytest.raises(InvalidParameterError):
26
+ reynolds_number(velocity=1.0, length=0.0, nu=1.0)
27
+
28
+
29
+ def test_froude_number_rejects_nonpositive_length_and_g():
30
+ with pytest.raises(InvalidParameterError):
31
+ froude_number(velocity=1.0, length=0.0, g=9.81)
32
+ with pytest.raises(InvalidParameterError):
33
+ froude_number(velocity=1.0, length=1.0, g=0.0)
34
+
35
+
36
+ def test_mach_number_rejects_nonpositive_speed_of_sound():
37
+ with pytest.raises(InvalidParameterError):
38
+ mach_number(velocity=100.0, speed_of_sound=0.0)
39
+
40
+
41
+ def test_strouhal_number_rejects_nonpositive_velocity():
42
+ with pytest.raises(InvalidParameterError):
43
+ strouhal_number(frequency=5.0, length=0.02, velocity=0.0)
44
+
45
+
46
+ def test_weber_number_rejects_nonpositive_surface_tension():
47
+ with pytest.raises(InvalidParameterError):
48
+ weber_number(rho=1000.0, velocity=1.0, length=0.001, surface_tension=0.0)
49
+
50
+
51
+ def test_froude_number_formula():
52
+ U, L, g = 4.0, 2.0, 9.81
53
+ assert froude_number(U, L, g) == pytest.approx(U / np.sqrt(g * L))
54
+
55
+
56
+ def test_mach_number_transonic_threshold():
57
+ assert mach_number(velocity=343.0, speed_of_sound=343.0) == pytest.approx(1.0)
58
+ assert mach_number(velocity=100.0, speed_of_sound=343.0) < 1.0
59
+
60
+
61
+ def test_strouhal_number_formula():
62
+ assert strouhal_number(frequency=5.0, length=0.02, velocity=0.5) == pytest.approx(0.2)
63
+
64
+
65
+ def test_weber_number_formula():
66
+ We = weber_number(rho=1000.0, velocity=2.0, length=0.002, surface_tension=0.072)
67
+ assert We == pytest.approx(1000.0 * 4.0 * 0.002 / 0.072)
68
+
69
+
70
+ def test_energy_spectrum_is_isotropic_for_a_radially_symmetric_field():
71
+ """A single-wavenumber flow deposits essentially all its energy in the
72
+ shell matching |k|, regardless of the direction of the wavevector."""
73
+ n, length = 64, 2 * np.pi
74
+ x = np.linspace(0, length, n, endpoint=False)
75
+ X, Y = np.meshgrid(x, x, indexing="ij")
76
+ u, v = np.sin(3 * Y), np.sin(3 * X) # |k| = 3
77
+ k, E = energy_spectrum(u, v, length)
78
+ assert np.argmax(E) == 3
79
+ assert E[3] > 100 * np.sum(E[np.arange(len(E)) != 3])
80
+
81
+
82
+ def test_energy_spectrum_rejects_mismatched_shapes():
83
+ with pytest.raises(InvalidParameterError):
84
+ energy_spectrum(np.zeros((16, 16)), np.zeros((8, 8)), length=1.0)
85
+
86
+
87
+ def test_energy_spectrum_rejects_non_square_arrays():
88
+ with pytest.raises(InvalidParameterError):
89
+ energy_spectrum(np.zeros((8, 16)), np.zeros((8, 16)), length=1.0)
90
+
91
+
92
+ def test_kolmogorov_reference_slope_matches_power_law():
93
+ k = np.array([1.0, 8.0])
94
+ ref = kolmogorov_reference_slope(k, k0=1.0, E0=1.0)
95
+ assert ref[1] == pytest.approx(8.0 ** (-5.0 / 3.0))
96
+
97
+
98
+ def test_kolmogorov_reference_slope_rejects_nonpositive_anchor():
99
+ with pytest.raises(InvalidParameterError):
100
+ kolmogorov_reference_slope(np.array([1.0]), k0=0.0, E0=1.0)
@@ -0,0 +1,110 @@
1
+ import numpy as np
2
+ import pytest
3
+
4
+ from physicskit.fluids.exceptions import InvalidParameterError
5
+ from physicskit.fluids.systems.viscous_flow import (
6
+ blasius_boundary_layer_thickness,
7
+ blasius_skin_friction_coefficient,
8
+ blasius_solve,
9
+ couette_flow_velocity,
10
+ poiseuille_flow_rate,
11
+ poiseuille_flow_velocity,
12
+ stokes_drag,
13
+ )
14
+
15
+
16
+ def test_couette_profile_is_linear_and_matches_wall_speeds():
17
+ y = np.linspace(0, 2.0, 21)
18
+ u = couette_flow_velocity(y, U_wall=3.0, h=2.0)
19
+ assert u[0] == 0.0
20
+ assert u[-1] == pytest.approx(3.0)
21
+ np.testing.assert_allclose(np.diff(u), np.diff(u)[0]) # constant slope
22
+
23
+
24
+ def test_poiseuille_flow_rate_matches_integral_of_velocity_profile():
25
+ dpdx, mu, h = -6.0, 0.8, 1.3
26
+ y = np.linspace(0, h, 20001)
27
+ u = poiseuille_flow_velocity(y, dpdx, mu, h)
28
+ Q_numeric = np.trapz(u, y) if hasattr(np, "trapz") else np.sum(u) * (y[1] - y[0])
29
+ Q_formula = poiseuille_flow_rate(dpdx, mu, h)
30
+ assert Q_numeric == pytest.approx(Q_formula, rel=1e-3)
31
+
32
+
33
+ def test_stokes_drag_scales_linearly_with_velocity_and_radius():
34
+ F1 = stokes_drag(mu=1e-3, radius=1e-4, velocity=0.01)
35
+ F2 = stokes_drag(mu=1e-3, radius=1e-4, velocity=0.02)
36
+ assert F2 == pytest.approx(2 * F1)
37
+ F3 = stokes_drag(mu=1e-3, radius=2e-4, velocity=0.01)
38
+ assert F3 == pytest.approx(2 * F1)
39
+
40
+
41
+ def test_blasius_wall_shear_matches_classic_constant():
42
+ """f''(0), the Blasius shooting solution's wall-curvature, is the
43
+ textbook constant ~0.332."""
44
+ result = blasius_solve()
45
+ assert result["fpp"][0] == pytest.approx(0.33206, abs=1e-4)
46
+
47
+
48
+ def test_blasius_far_field_velocity_recovers_free_stream():
49
+ result = blasius_solve()
50
+ assert result["fp"][-1] == pytest.approx(1.0, abs=1e-6)
51
+
52
+
53
+ def test_blasius_boundary_layer_thickness_grows_like_sqrt_x():
54
+ x = np.array([1.0, 4.0, 9.0])
55
+ delta = blasius_boundary_layer_thickness(x, U_inf=1.0, nu=1e-4)
56
+ ratios = delta / np.sqrt(x)
57
+ assert np.allclose(ratios, ratios[0], rtol=1e-8)
58
+
59
+
60
+ def test_blasius_skin_friction_decreases_with_reynolds_number():
61
+ Re = np.array([1e3, 1e4, 1e5])
62
+ cf = blasius_skin_friction_coefficient(Re)
63
+ assert np.all(np.diff(cf) < 0)
64
+
65
+
66
+ def test_viscous_flow_rejects_nonpositive_parameters():
67
+ with pytest.raises(InvalidParameterError):
68
+ couette_flow_velocity(y=0.5, U_wall=1.0, h=0.0)
69
+ with pytest.raises(InvalidParameterError):
70
+ stokes_drag(mu=-1.0, radius=1.0, velocity=1.0)
71
+ with pytest.raises(InvalidParameterError):
72
+ blasius_boundary_layer_thickness(x=-1.0, U_inf=1.0, nu=1e-4)
73
+
74
+
75
+ def test_poiseuille_flow_velocity_rejects_nonpositive_mu_and_h():
76
+ with pytest.raises(InvalidParameterError):
77
+ poiseuille_flow_velocity(y=0.5, dpdx=-1.0, mu=0.0, h=1.0)
78
+ with pytest.raises(InvalidParameterError):
79
+ poiseuille_flow_velocity(y=0.5, dpdx=-1.0, mu=1.0, h=0.0)
80
+
81
+
82
+ def test_poiseuille_flow_rate_rejects_nonpositive_mu_and_h():
83
+ with pytest.raises(InvalidParameterError):
84
+ poiseuille_flow_rate(dpdx=-1.0, mu=0.0, h=1.0)
85
+ with pytest.raises(InvalidParameterError):
86
+ poiseuille_flow_rate(dpdx=-1.0, mu=1.0, h=0.0)
87
+
88
+
89
+ def test_stokes_drag_rejects_nonpositive_radius():
90
+ with pytest.raises(InvalidParameterError):
91
+ stokes_drag(mu=1.0, radius=0.0, velocity=1.0)
92
+
93
+
94
+ def test_blasius_boundary_layer_thickness_rejects_nonpositive_u_inf_and_nu():
95
+ with pytest.raises(InvalidParameterError):
96
+ blasius_boundary_layer_thickness(x=1.0, U_inf=0.0, nu=1e-4)
97
+ with pytest.raises(InvalidParameterError):
98
+ blasius_boundary_layer_thickness(x=1.0, U_inf=1.0, nu=0.0)
99
+
100
+
101
+ def test_blasius_skin_friction_coefficient_rejects_nonpositive_reynolds():
102
+ with pytest.raises(InvalidParameterError):
103
+ blasius_skin_friction_coefficient(reynolds_x=np.array([1e4, -1.0]))
104
+
105
+
106
+ def test_blasius_solve_expands_bracket_when_default_guess_undershoots():
107
+ # eta_max=1.0 is too short for fpp0=1.0's shooting guess to reach f'=1,
108
+ # forcing the initial bracket-expansion loop before bisection.
109
+ result = blasius_solve(eta_max=1.0, n_points=50)
110
+ assert result["fp"][-1] == pytest.approx(1.0, abs=1e-6)
@@ -0,0 +1,34 @@
1
+ """Animation smoke tests for physicskit.fluids.visualizers.flow_fields, previously untested
2
+ (no visualizer in physicskit.fluids had any test coverage before this). These run headlessly
3
+ (see conftest.py's Agg backend) and check that the Kelvin-Helmholtz and Rayleigh-Taylor
4
+ animations build and save correctly.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import numpy as np
10
+ import pytest
11
+ from matplotlib.animation import PillowWriter
12
+
13
+ from physicskit.fluids.systems.instabilities import kelvin_helmholtz_ic, rayleigh_taylor_ic
14
+ from physicskit.fluids.visualizers.flow_fields import animate_kelvin_helmholtz, animate_rayleigh_taylor
15
+
16
+
17
+ @pytest.mark.slow
18
+ def test_animate_kelvin_helmholtz_saves_to_gif(tmp_path):
19
+ n, length = 64, 2 * np.pi
20
+ omega0 = kelvin_helmholtz_ic(n, length, shear_width=0.1, perturbation_amplitude=0.05)
21
+ anim = animate_kelvin_helmholtz(omega0, nu=0.001, dt=0.0025, steps_per_frame=20, n_frames=5, length=length)
22
+ out = tmp_path / "kelvin_helmholtz.gif"
23
+ anim.save(out, writer=PillowWriter(fps=10))
24
+ assert out.exists() and out.stat().st_size > 0
25
+
26
+
27
+ @pytest.mark.slow
28
+ def test_animate_rayleigh_taylor_saves_to_gif(tmp_path):
29
+ n, length = 64, 2 * np.pi
30
+ omega0, buoyancy0 = rayleigh_taylor_ic(n, length, atwood_number=0.3, perturbation_amplitude=0.01)
31
+ anim = animate_rayleigh_taylor(omega0, buoyancy0, nu=0.002, kappa=0.002, g=1.0, dt=0.01, steps_per_frame=20, n_frames=5, length=length)
32
+ out = tmp_path / "rayleigh_taylor.gif"
33
+ anim.save(out, writer=PillowWriter(fps=10))
34
+ assert out.exists() and out.stat().st_size > 0
@@ -0,0 +1,88 @@
1
+ import numpy as np
2
+ import pytest
3
+
4
+ from physicskit.fluids.exceptions import InvalidParameterError
5
+ from physicskit.fluids.systems.vortex_dynamics import (
6
+ PointVortexSystem,
7
+ point_vortex_velocities,
8
+ von_karman_vortex_street,
9
+ )
10
+
11
+
12
+ def test_two_equal_vortices_orbit_at_the_analytic_angular_velocity():
13
+ """Two point vortices of equal strength Gamma separated by distance d
14
+ rotate rigidly about their midpoint at angular velocity Omega = Gamma / (pi d^2)."""
15
+ Gamma, d = 1.0, 1.0
16
+ positions0 = np.array([[d / 2, 0.0], [-d / 2, 0.0]])
17
+ system = PointVortexSystem(positions=positions0, circulations=[Gamma, Gamma])
18
+ omega_expected = Gamma / (np.pi * d**2)
19
+ t_final = 0.2
20
+ dt, n_steps = 1e-4, round(t_final / 1e-4)
21
+ _, trajectory = system.trajectory(dt=dt, n_steps=n_steps)
22
+ final = trajectory[-1]
23
+ d_final = np.hypot(*(final[0] - final[1]))
24
+ assert d_final == pytest.approx(d, rel=1e-3) # separation is conserved
25
+ angle_final = np.arctan2(final[0, 1], final[0, 0])
26
+ assert angle_final == pytest.approx(omega_expected * t_final, abs=1e-3)
27
+
28
+
29
+ def test_opposite_sign_vortex_pair_translates_without_rotating():
30
+ """A vortex dipole (equal and opposite circulation) advects itself in a
31
+ straight line at constant velocity Gamma / (2 pi d), rather than orbiting."""
32
+ Gamma, d = 1.0, 1.0
33
+ positions0 = np.array([[0.0, d / 2], [0.0, -d / 2]])
34
+ system = PointVortexSystem(positions=positions0, circulations=[Gamma, -Gamma])
35
+ dt, n_steps = 1e-3, 200
36
+ _, trajectory = system.trajectory(dt=dt, n_steps=n_steps)
37
+ displacement = trajectory[-1] - trajectory[0]
38
+ # both vortices move by (nearly) the same vector: rigid translation
39
+ np.testing.assert_allclose(displacement[0], displacement[1], atol=1e-3)
40
+ speed_expected = Gamma / (2 * np.pi * d)
41
+ speed_numeric = np.hypot(*displacement[0]) / (dt * n_steps)
42
+ assert speed_numeric == pytest.approx(speed_expected, rel=1e-2)
43
+
44
+
45
+ def test_point_vortex_velocities_rejects_mismatched_lengths():
46
+ with pytest.raises(InvalidParameterError):
47
+ point_vortex_velocities(positions=[[0.0, 0.0], [1.0, 0.0]], circulations=[1.0])
48
+
49
+
50
+ def test_point_vortex_system_rejects_mismatched_lengths():
51
+ with pytest.raises(InvalidParameterError):
52
+ PointVortexSystem(positions=[[0.0, 0.0], [1.0, 0.0]], circulations=[1.0])
53
+
54
+
55
+ def test_point_vortex_system_velocities_matches_module_function():
56
+ positions = [[0.0, 0.0], [1.0, 0.0]]
57
+ circulations = [1.0, -1.0]
58
+ system = PointVortexSystem(positions=positions, circulations=circulations)
59
+ np.testing.assert_allclose(system.velocities(), point_vortex_velocities(positions, circulations))
60
+
61
+
62
+ def test_point_vortex_system_repr():
63
+ system = PointVortexSystem(positions=[[0.0, 0.0]], circulations=[2.0])
64
+ assert repr(system) == "PointVortexSystem(n_vortices=1, circulations=array([2.]))"
65
+
66
+
67
+ def test_von_karman_street_rejects_nonpositive_spacing():
68
+ with pytest.raises(InvalidParameterError):
69
+ von_karman_vortex_street(n_pairs=3, spacing_l=0.0)
70
+
71
+
72
+ def test_von_karman_street_alternates_sign_across_rows():
73
+ positions, circulations = von_karman_vortex_street(n_pairs=4, spacing_l=1.0)
74
+ top_row = circulations[0::2]
75
+ bottom_row = circulations[1::2]
76
+ np.testing.assert_allclose(top_row, -bottom_row)
77
+
78
+
79
+ def test_von_karman_street_uses_the_stable_spacing_ratio_by_default():
80
+ spacing_l = 2.0
81
+ positions, _ = von_karman_vortex_street(n_pairs=3, spacing_l=spacing_l)
82
+ h = positions[0, 1] - positions[1, 1]
83
+ assert h / spacing_l == pytest.approx(0.2805, abs=1e-4)
84
+
85
+
86
+ def test_von_karman_street_rejects_too_few_pairs():
87
+ with pytest.raises(InvalidParameterError):
88
+ von_karman_vortex_street(n_pairs=1, spacing_l=1.0)
@@ -0,0 +1,18 @@
1
+ from physicskit.fluids.utils.dimensionless import (
2
+ froude_number,
3
+ mach_number,
4
+ reynolds_number,
5
+ strouhal_number,
6
+ weber_number,
7
+ )
8
+ from physicskit.fluids.utils.spectral_analysis import energy_spectrum, kolmogorov_reference_slope
9
+
10
+ __all__ = [
11
+ "energy_spectrum",
12
+ "froude_number",
13
+ "kolmogorov_reference_slope",
14
+ "mach_number",
15
+ "reynolds_number",
16
+ "strouhal_number",
17
+ "weber_number",
18
+ ]
@@ -0,0 +1,239 @@
1
+ """Dimensionless numbers: Reynolds, Froude, Mach, Strouhal, and Weber.
2
+
3
+ Fluid mechanics is governed by ratios, not absolute scales: two flows with
4
+ the same dimensionless numbers behave identically regardless of their size,
5
+ speed, or fluid, which is what makes wind-tunnel testing of a model
6
+ airplane meaningful for a full-size one. Each function here computes one
7
+ such ratio, and each result's magnitude is what determines which regime
8
+ (and which module of this package) actually applies -- a low Reynolds
9
+ number licenses :func:`physicskit.fluids.systems.viscous_flow.stokes_drag`,
10
+ a high one calls for
11
+ :class:`physicskit.fluids.systems.navier_stokes.NavierStokes2D` or the
12
+ turbulence tools in :mod:`physicskit.fluids.utils.spectral_analysis`.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from physicskit.fluids.exceptions import InvalidParameterError
18
+
19
+ __all__ = [
20
+ "reynolds_number",
21
+ "froude_number",
22
+ "mach_number",
23
+ "strouhal_number",
24
+ "weber_number",
25
+ ]
26
+
27
+
28
+ def reynolds_number(velocity: float, length: float, nu: float) -> float:
29
+ """The Reynolds number: inertial forces over viscous forces.
30
+
31
+ .. math::
32
+
33
+ Re = \\frac{U L}{\\nu}
34
+
35
+ Osborne Reynolds' 1883 pipe-flow experiments identified this ratio as
36
+ the single parameter controlling the transition from smooth (laminar)
37
+ to chaotic (turbulent) flow, regardless of the pipe's size or the
38
+ fluid's identity -- the founding result of dimensional-similarity
39
+ reasoning in fluid mechanics.
40
+
41
+ Parameters
42
+ ----------
43
+ velocity : float
44
+ Characteristic flow speed `U`.
45
+ length : float
46
+ Characteristic length scale `L`.
47
+ nu : float
48
+ Kinematic viscosity.
49
+
50
+ Returns
51
+ -------
52
+ float
53
+ Reynolds number `Re`.
54
+
55
+ Raises
56
+ ------
57
+ InvalidParameterError
58
+ If `length` or `nu` is not positive.
59
+
60
+ Examples
61
+ --------
62
+ >>> reynolds_number(velocity=2.0, length=0.5, nu=1e-6)
63
+ 1000000.0
64
+ """
65
+ if length <= 0:
66
+ raise InvalidParameterError(f"length must be positive, got {length}")
67
+ if nu <= 0:
68
+ raise InvalidParameterError(f"nu must be positive, got {nu}")
69
+ return velocity * length / nu
70
+
71
+
72
+ def froude_number(velocity: float, length: float, g: float = 9.81) -> float:
73
+ """The Froude number: inertial forces over gravitational forces.
74
+
75
+ .. math::
76
+
77
+ Fr = \\frac{U}{\\sqrt{gL}}
78
+
79
+ Governs free-surface (gravity wave) flows the way the Reynolds number
80
+ governs viscous ones: a ship model and its full-size counterpart make
81
+ the same waves, relative to their length, only if `Fr` matches. William
82
+ Froude's 1868 ship-hull towing-tank experiments established exactly
83
+ this scaling law.
84
+
85
+ Parameters
86
+ ----------
87
+ velocity : float
88
+ Characteristic flow speed `U`.
89
+ length : float
90
+ Characteristic length scale `L`.
91
+ g : float, default 9.81
92
+ Gravitational acceleration.
93
+
94
+ Returns
95
+ -------
96
+ float
97
+ Froude number `Fr`.
98
+
99
+ Raises
100
+ ------
101
+ InvalidParameterError
102
+ If `length` or `g` is not positive.
103
+
104
+ Examples
105
+ --------
106
+ >>> round(froude_number(velocity=3.0, length=9.81, g=9.81), 4)
107
+ 0.3058
108
+ """
109
+ if length <= 0:
110
+ raise InvalidParameterError(f"length must be positive, got {length}")
111
+ if g <= 0:
112
+ raise InvalidParameterError(f"g must be positive, got {g}")
113
+ return velocity / (g * length) ** 0.5
114
+
115
+
116
+ def mach_number(velocity: float, speed_of_sound: float) -> float:
117
+ """The Mach number: flow speed over the local speed of sound.
118
+
119
+ .. math::
120
+
121
+ M = \\frac{U}{c}
122
+
123
+ The single number that decides whether compressibility can be ignored
124
+ (:math:`M \\ll 1`, the regime of every other module in this package
125
+ except :mod:`physicskit.fluids.systems.compressible_flow`) or dominates
126
+ the flow (:math:`M \\gtrsim 1`, where :func:`~physicskit.fluids.systems.compressible_flow.normal_shock_relations`
127
+ applies).
128
+
129
+ Parameters
130
+ ----------
131
+ velocity : float
132
+ Flow speed `U`.
133
+ speed_of_sound : float
134
+ Local speed of sound `c`.
135
+
136
+ Returns
137
+ -------
138
+ float
139
+ Mach number `M`.
140
+
141
+ Raises
142
+ ------
143
+ InvalidParameterError
144
+ If `speed_of_sound` is not positive.
145
+
146
+ Examples
147
+ --------
148
+ >>> mach_number(velocity=340.0, speed_of_sound=340.0)
149
+ 1.0
150
+ """
151
+ if speed_of_sound <= 0:
152
+ raise InvalidParameterError(f"speed_of_sound must be positive, got {speed_of_sound}")
153
+ return velocity / speed_of_sound
154
+
155
+
156
+ def strouhal_number(frequency: float, length: float, velocity: float) -> float:
157
+ """The Strouhal number: a dimensionless vortex-shedding frequency.
158
+
159
+ .. math::
160
+
161
+ St = \\frac{f L}{U}
162
+
163
+ For flow past a bluff body shedding a
164
+ :func:`~physicskit.fluids.systems.vortex_dynamics.von_karman_vortex_street`
165
+ at frequency `f`, `St` stays remarkably constant (near 0.2 for a
166
+ circular cylinder) over a wide range of Reynolds number, letting a
167
+ single scaled model predict the shedding frequency at full scale.
168
+
169
+ Parameters
170
+ ----------
171
+ frequency : float
172
+ Vortex-shedding frequency `f`.
173
+ length : float
174
+ Characteristic length scale `L` (e.g. the body's cross-stream width).
175
+ velocity : float
176
+ Characteristic flow speed `U`.
177
+
178
+ Returns
179
+ -------
180
+ float
181
+ Strouhal number `St`.
182
+
183
+ Raises
184
+ ------
185
+ InvalidParameterError
186
+ If `velocity` is not positive.
187
+
188
+ Examples
189
+ --------
190
+ >>> round(strouhal_number(frequency=2.0, length=0.1, velocity=1.0), 4)
191
+ 0.2
192
+ """
193
+ if velocity <= 0:
194
+ raise InvalidParameterError(f"velocity must be positive, got {velocity}")
195
+ return frequency * length / velocity
196
+
197
+
198
+ def weber_number(rho: float, velocity: float, length: float, surface_tension: float) -> float:
199
+ """The Weber number: inertial forces over surface-tension forces.
200
+
201
+ .. math::
202
+
203
+ We = \\frac{\\rho U^2 L}{\\sigma}
204
+
205
+ Governs whether a free liquid surface (a droplet, a jet, a bubble)
206
+ deforms and breaks up under its own inertia (:math:`We \\gg 1`) or is
207
+ held together by surface tension (:math:`We \\lesssim 1`) -- the
208
+ parameter that decides, for instance, whether a jet of liquid breaks
209
+ into droplets.
210
+
211
+ Parameters
212
+ ----------
213
+ rho : float
214
+ Fluid density.
215
+ velocity : float
216
+ Characteristic flow speed `U`.
217
+ length : float
218
+ Characteristic length scale `L` (e.g. a droplet diameter).
219
+ surface_tension : float
220
+ Surface tension coefficient :math:`\\sigma`.
221
+
222
+ Returns
223
+ -------
224
+ float
225
+ Weber number `We`.
226
+
227
+ Raises
228
+ ------
229
+ InvalidParameterError
230
+ If `surface_tension` is not positive.
231
+
232
+ Examples
233
+ --------
234
+ >>> round(weber_number(rho=1000.0, velocity=1.0, length=0.001, surface_tension=0.072), 4)
235
+ 13.8889
236
+ """
237
+ if surface_tension <= 0:
238
+ raise InvalidParameterError(f"surface_tension must be positive, got {surface_tension}")
239
+ return rho * velocity**2 * length / surface_tension