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,425 @@
1
+ """Classic exact solutions of the viscous (Navier-Stokes) equations.
2
+
3
+ Four textbook problems simple enough to solve in closed form (or, for
4
+ Blasius, by reducing an entire boundary layer to a single ordinary
5
+ differential equation): plane Couette flow, plane Poiseuille flow, Stokes
6
+ drag on a sphere, and the Blasius laminar boundary layer. Each is a limit
7
+ where the full nonlinear Navier-Stokes equations collapse to something
8
+ tractable -- steady unidirectional shear flow (Couette, Poiseuille),
9
+ vanishing Reynolds number (Stokes), or a self-similar boundary layer
10
+ (Blasius) -- and each remains a standard benchmark for validating a general
11
+ solver, since it is one of the few cases where "the answer" is known exactly.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import numpy as np
17
+ from numba import njit
18
+ from numpy.typing import ArrayLike, NDArray
19
+
20
+ from physicskit.fluids.exceptions import InvalidParameterError
21
+
22
+ __all__ = [
23
+ "couette_flow_velocity",
24
+ "poiseuille_flow_velocity",
25
+ "poiseuille_flow_rate",
26
+ "stokes_drag",
27
+ "blasius_solve",
28
+ "blasius_boundary_layer_thickness",
29
+ "blasius_skin_friction_coefficient",
30
+ ]
31
+
32
+
33
+ def couette_flow_velocity(y: ArrayLike, U_wall: float, h: float) -> NDArray[np.float64]:
34
+ """Velocity profile of steady plane Couette flow.
35
+
36
+ The flow between two infinite parallel plates, the lower one at rest
37
+ and the upper one (at ``y = h``) moving at speed `U_wall`, with no
38
+ imposed pressure gradient. The steady Navier-Stokes equations reduce to
39
+ :math:`\\mu\\, d^2u/dy^2 = 0`, whose solution subject to no-slip at both
40
+ walls is the linear profile below -- shear stress
41
+ :math:`\\tau = \\mu\\,U_{wall}/h` is exactly uniform across the gap.
42
+
43
+ Parameters
44
+ ----------
45
+ y : array_like of float
46
+ Height above the lower (stationary) plate, ``0 <= y <= h``.
47
+ U_wall : float
48
+ Speed of the upper, moving plate.
49
+ h : float
50
+ Gap between the plates.
51
+
52
+ Returns
53
+ -------
54
+ ndarray of float
55
+ Velocity :math:`u(y) = U_{wall}\\,y/h`.
56
+
57
+ Raises
58
+ ------
59
+ InvalidParameterError
60
+ If `h` is not positive.
61
+
62
+ Examples
63
+ --------
64
+ >>> couette_flow_velocity(y=[0.0, 0.5, 1.0], U_wall=2.0, h=1.0)
65
+ array([0., 1., 2.])
66
+ """
67
+ if h <= 0:
68
+ raise InvalidParameterError(f"h must be positive, got {h}")
69
+ y = np.asarray(y, dtype=np.float64)
70
+ return U_wall * y / h
71
+
72
+
73
+ def poiseuille_flow_velocity(y: ArrayLike, dpdx: float, mu: float, h: float) -> NDArray[np.float64]:
74
+ """Velocity profile of steady plane Poiseuille flow.
75
+
76
+ The flow between two stationary infinite parallel plates driven by a
77
+ constant imposed pressure gradient `dpdx`. The steady Navier-Stokes
78
+ equations reduce to :math:`\\mu\\,d^2u/dy^2 = dp/dx`, whose solution
79
+ subject to no-slip at both walls (``y=0`` and ``y=h``) is the parabolic
80
+ profile below, maximal at the channel centerline.
81
+
82
+ Parameters
83
+ ----------
84
+ y : array_like of float
85
+ Height above the lower plate, ``0 <= y <= h``.
86
+ dpdx : float
87
+ Imposed pressure gradient (negative drives flow in ``+x``).
88
+ mu : float
89
+ Dynamic viscosity.
90
+ h : float
91
+ Gap between the plates.
92
+
93
+ Returns
94
+ -------
95
+ ndarray of float
96
+ Velocity :math:`u(y) = -\\frac{1}{2\\mu}\\frac{dp}{dx}\\,y\\,(h-y)`.
97
+
98
+ Raises
99
+ ------
100
+ InvalidParameterError
101
+ If `mu` or `h` is not positive.
102
+
103
+ See Also
104
+ --------
105
+ poiseuille_flow_rate : The volumetric flow rate driven by this profile.
106
+
107
+ Examples
108
+ --------
109
+ >>> y = np.linspace(0, 1, 5)
110
+ >>> u = poiseuille_flow_velocity(y, dpdx=-8.0, mu=1.0, h=1.0)
111
+ >>> round(float(u[2]), 4) # peak at centerline
112
+ 1.0
113
+ >>> bool(u[0] == 0.0 and u[-1] == 0.0) # no-slip at both walls
114
+ True
115
+ """
116
+ if mu <= 0:
117
+ raise InvalidParameterError(f"mu must be positive, got {mu}")
118
+ if h <= 0:
119
+ raise InvalidParameterError(f"h must be positive, got {h}")
120
+ y = np.asarray(y, dtype=np.float64)
121
+ return -(1.0 / (2.0 * mu)) * dpdx * y * (h - y)
122
+
123
+
124
+ def poiseuille_flow_rate(dpdx: float, mu: float, h: float) -> float:
125
+ """Volumetric flow rate per unit depth of plane Poiseuille flow.
126
+
127
+ The integral of :func:`poiseuille_flow_velocity` across the channel:
128
+
129
+ .. math::
130
+
131
+ Q = -\\frac{h^3}{12\\mu}\\frac{dp}{dx}
132
+
133
+ Parameters
134
+ ----------
135
+ dpdx : float
136
+ Imposed pressure gradient.
137
+ mu : float
138
+ Dynamic viscosity.
139
+ h : float
140
+ Gap between the plates.
141
+
142
+ Returns
143
+ -------
144
+ float
145
+ Volumetric flow rate per unit depth, `Q`.
146
+
147
+ Raises
148
+ ------
149
+ InvalidParameterError
150
+ If `mu` or `h` is not positive.
151
+
152
+ Examples
153
+ --------
154
+ >>> round(poiseuille_flow_rate(dpdx=-12.0, mu=1.0, h=1.0), 4)
155
+ 1.0
156
+ """
157
+ if mu <= 0:
158
+ raise InvalidParameterError(f"mu must be positive, got {mu}")
159
+ if h <= 0:
160
+ raise InvalidParameterError(f"h must be positive, got {h}")
161
+ return -(h**3 / (12.0 * mu)) * dpdx
162
+
163
+
164
+ def stokes_drag(mu: float, radius: float, velocity: float) -> float:
165
+ """Stokes' law: drag force on a sphere at low Reynolds number.
166
+
167
+ .. math::
168
+
169
+ F_D = 6\\pi\\mu R v
170
+
171
+ Valid in the creeping-flow limit :math:`Re = 2R|v|/\\nu \\ll 1`, where
172
+ the nonlinear advection term in Navier-Stokes is negligible next to
173
+ viscous diffusion, leaving the linear Stokes equations
174
+ :math:`\\mu\\nabla^2\\mathbf{u}=\\nabla p` -- George Stokes' 1851 exact
175
+ solution for uniform flow past a sphere.
176
+
177
+ Parameters
178
+ ----------
179
+ mu : float
180
+ Dynamic viscosity.
181
+ radius : float
182
+ Sphere radius.
183
+ velocity : float
184
+ Relative speed between the sphere and the fluid far away.
185
+
186
+ Returns
187
+ -------
188
+ float
189
+ Drag force magnitude :math:`F_D`.
190
+
191
+ Raises
192
+ ------
193
+ InvalidParameterError
194
+ If `mu` or `radius` is not positive.
195
+
196
+ Examples
197
+ --------
198
+ >>> round(stokes_drag(mu=1.0, radius=1.0, velocity=1.0), 4)
199
+ 18.8496
200
+ """
201
+ if mu <= 0:
202
+ raise InvalidParameterError(f"mu must be positive, got {mu}")
203
+ if radius <= 0:
204
+ raise InvalidParameterError(f"radius must be positive, got {radius}")
205
+ return 6.0 * np.pi * mu * radius * velocity
206
+
207
+
208
+ @njit(cache=True)
209
+ def _blasius_rhs(state: NDArray[np.float64]) -> NDArray[np.float64]:
210
+ """Blasius ODE as a first-order system: ``(f, f', f'')' = (f', f'', -f f''/2)``.
211
+
212
+ Parameters
213
+ ----------
214
+ state : ndarray of float, shape (3,)
215
+ ``(f, f', f'')`` at the current similarity coordinate `eta`.
216
+
217
+ Returns
218
+ -------
219
+ ndarray of float, shape (3,)
220
+ Derivative of `state` with respect to `eta`.
221
+ """
222
+ f, fp, fpp = state[0], state[1], state[2]
223
+ out = np.empty(3)
224
+ out[0] = fp
225
+ out[1] = fpp
226
+ out[2] = -0.5 * f * fpp
227
+ return out
228
+
229
+
230
+ @njit(cache=True)
231
+ def _blasius_integrate(fpp0: float, eta_max: float, n_points: int) -> NDArray[np.float64]:
232
+ """Integrate the Blasius ODE with RK4 from ``eta=0`` given a guessed ``f''(0)``.
233
+
234
+ Parameters
235
+ ----------
236
+ fpp0 : float
237
+ Guessed shooting parameter :math:`f''(0)`.
238
+ eta_max : float
239
+ Similarity coordinate at which to stop integrating.
240
+ n_points : int
241
+ Number of output points (including ``eta=0``).
242
+
243
+ Returns
244
+ -------
245
+ ndarray of float, shape (n_points, 3)
246
+ ``(f, f', f'')`` at each of `n_points` equally spaced `eta` in
247
+ ``[0, eta_max]``.
248
+ """
249
+ states = np.empty((n_points, 3))
250
+ state = np.array([0.0, 0.0, fpp0])
251
+ states[0] = state
252
+ deta = eta_max / (n_points - 1)
253
+ for i in range(n_points - 1):
254
+ k1 = _blasius_rhs(state)
255
+ k2 = _blasius_rhs(state + 0.5 * deta * k1)
256
+ k3 = _blasius_rhs(state + 0.5 * deta * k2)
257
+ k4 = _blasius_rhs(state + deta * k3)
258
+ state = state + (deta / 6.0) * (k1 + 2.0 * k2 + 2.0 * k3 + k4)
259
+ states[i + 1] = state
260
+ return states
261
+
262
+
263
+ def blasius_solve(eta_max: float = 10.0, n_points: int = 2001, tol: float = 1e-10, max_iter: int = 100) -> dict[str, NDArray[np.float64]]:
264
+ """Solve the Blasius laminar boundary-layer equation by shooting.
265
+
266
+ The Blasius similarity reduction of the steady, 2D, zero-pressure-gradient
267
+ boundary-layer equations collapses them to the single third-order ODE
268
+
269
+ .. math::
270
+
271
+ f''' + \\tfrac{1}{2} f f'' = 0, \\qquad
272
+ f(0) = f'(0) = 0, \\qquad f'(\\infty) = 1,
273
+
274
+ for the dimensionless streamfunction :math:`f(\\eta)` of the similarity
275
+ variable :math:`\\eta = y\\sqrt{U_\\infty/(\\nu x)}`; the streamwise
276
+ velocity is :math:`u/U_\\infty = f'(\\eta)`. Since :math:`f''(0)` (rather
277
+ than the far-field condition) is the free parameter needed to start an
278
+ initial-value integration, this is a two-point boundary value problem
279
+ solved here by shooting: bisect on :math:`f''(0)` until the resulting
280
+ :func:`_blasius_integrate` solution satisfies :math:`f'(\\eta_{max})
281
+ \\approx 1`.
282
+
283
+ Parameters
284
+ ----------
285
+ eta_max : float, default 10.0
286
+ Similarity coordinate treated as "infinity"; large enough that
287
+ :math:`f'` has converged to 1 to within `tol`.
288
+ n_points : int, default 2001
289
+ Number of output points between ``eta=0`` and `eta_max`.
290
+ tol : float, default 1e-10
291
+ Bisection tolerance on :math:`f'(\\eta_{max}) - 1`.
292
+ max_iter : int, default 100
293
+ Maximum number of bisection iterations.
294
+
295
+ Returns
296
+ -------
297
+ dict
298
+ ``{"eta": ..., "f": ..., "fp": ..., "fpp": ...}``, each an array of
299
+ length `n_points`. ``fpp[0]`` is the classic Blasius constant,
300
+ :math:`f''(0) \\approx 0.332`.
301
+
302
+ Examples
303
+ --------
304
+ >>> result = blasius_solve()
305
+ >>> round(float(result["fpp"][0]), 3)
306
+ 0.332
307
+ >>> round(float(result["fp"][-1]), 4)
308
+ 1.0
309
+ """
310
+ lo, hi = 0.1, 1.0
311
+ solution = _blasius_integrate(hi, eta_max, n_points)
312
+ while solution[-1, 1] < 1.0:
313
+ hi *= 2.0
314
+ solution = _blasius_integrate(hi, eta_max, n_points)
315
+
316
+ for _ in range(max_iter):
317
+ mid = 0.5 * (lo + hi)
318
+ solution = _blasius_integrate(mid, eta_max, n_points)
319
+ residual = solution[-1, 1] - 1.0
320
+ if abs(residual) < tol:
321
+ break
322
+ if residual > 0:
323
+ hi = mid
324
+ else:
325
+ lo = mid
326
+
327
+ eta = np.linspace(0.0, eta_max, n_points)
328
+ return {"eta": eta, "f": solution[:, 0], "fp": solution[:, 1], "fpp": solution[:, 2]}
329
+
330
+
331
+ def blasius_boundary_layer_thickness(x: ArrayLike, U_inf: float, nu: float, eta_99: float = 4.91) -> NDArray[np.float64]:
332
+ """Blasius laminar boundary-layer thickness :math:`\\delta_{99}(x)`.
333
+
334
+ The height at which :math:`u/U_\\infty` first reaches 0.99 occurs, in
335
+ similarity coordinates, at :math:`\\eta \\approx 4.91` (a property of
336
+ the Blasius profile from :func:`blasius_solve`, not re-derived here), so
337
+
338
+ .. math::
339
+
340
+ \\delta_{99}(x) = \\eta_{99}\\sqrt{\\frac{\\nu x}{U_\\infty}}
341
+ \\propto \\sqrt{x}.
342
+
343
+ The boundary layer's parabolic-looking growth with downstream distance
344
+ -- much slower than the layer's own streamwise extent -- is exactly the
345
+ "thin layer" assumption Ludwig Prandtl's 1904 boundary-layer theory
346
+ used to simplify Navier-Stokes into the boundary-layer equations Blasius
347
+ then solved.
348
+
349
+ Parameters
350
+ ----------
351
+ x : array_like of float
352
+ Downstream distance from the leading edge; must be positive.
353
+ U_inf : float
354
+ Free-stream speed.
355
+ nu : float
356
+ Kinematic viscosity.
357
+ eta_99 : float, default 4.91
358
+ Similarity coordinate at which :math:`f'(\\eta)=0.99`.
359
+
360
+ Returns
361
+ -------
362
+ ndarray of float
363
+ Boundary-layer thickness :math:`\\delta_{99}(x)`.
364
+
365
+ Raises
366
+ ------
367
+ InvalidParameterError
368
+ If `U_inf` or `nu` is not positive, or any entry of `x` is not positive.
369
+
370
+ Examples
371
+ --------
372
+ >>> round(float(blasius_boundary_layer_thickness(x=1.0, U_inf=1.0, nu=1e-4)), 4)
373
+ 0.0491
374
+ """
375
+ if U_inf <= 0:
376
+ raise InvalidParameterError(f"U_inf must be positive, got {U_inf}")
377
+ if nu <= 0:
378
+ raise InvalidParameterError(f"nu must be positive, got {nu}")
379
+ x = np.asarray(x, dtype=np.float64)
380
+ if np.any(x <= 0):
381
+ raise InvalidParameterError("x must be positive (measured from the leading edge)")
382
+ return eta_99 * np.sqrt(nu * x / U_inf)
383
+
384
+
385
+ def blasius_skin_friction_coefficient(reynolds_x: ArrayLike, fpp0: float = 0.33206) -> NDArray[np.float64]:
386
+ """Local skin-friction coefficient of the Blasius boundary layer.
387
+
388
+ The wall shear stress :math:`\\tau_w = \\mu U_\\infty f''(0)\\sqrt{U_\\infty/(\\nu x)}`
389
+ gives a local skin-friction coefficient
390
+
391
+ .. math::
392
+
393
+ c_f(x) = \\frac{\\tau_w}{\\tfrac{1}{2}\\rho U_\\infty^2}
394
+ = \\frac{2 f''(0)}{\\sqrt{Re_x}}, \\qquad
395
+ Re_x = \\frac{U_\\infty x}{\\nu},
396
+
397
+ the classic :math:`c_f \\propto Re_x^{-1/2}` scaling of a laminar
398
+ boundary layer.
399
+
400
+ Parameters
401
+ ----------
402
+ reynolds_x : array_like of float
403
+ Local Reynolds number :math:`Re_x = U_\\infty x/\\nu`; must be positive.
404
+ fpp0 : float, default 0.33206
405
+ The Blasius constant :math:`f''(0)`, as returned by :func:`blasius_solve`.
406
+
407
+ Returns
408
+ -------
409
+ ndarray of float
410
+ Local skin-friction coefficient :math:`c_f(x)`.
411
+
412
+ Raises
413
+ ------
414
+ InvalidParameterError
415
+ If any entry of `reynolds_x` is not positive.
416
+
417
+ Examples
418
+ --------
419
+ >>> round(float(blasius_skin_friction_coefficient(reynolds_x=1e4)), 5)
420
+ 0.00664
421
+ """
422
+ reynolds_x = np.asarray(reynolds_x, dtype=np.float64)
423
+ if np.any(reynolds_x <= 0):
424
+ raise InvalidParameterError("reynolds_x must be positive")
425
+ return 2.0 * fpp0 / np.sqrt(reynolds_x)