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,258 @@
1
+ """N-body Lennard-Jones gas: Velocity Verlet dynamics and Boltzmann's H-theorem.
2
+
3
+ :class:`LennardJonesGas` simulates a 2D periodic gas of Lennard-Jones
4
+ particles and lets it relax toward equilibrium from an arbitrary initial
5
+ velocity distribution. Along the way it tracks Boltzmann's H-function, whose
6
+ monotonic decrease is the classic microscopic demonstration that
7
+ time-reversible molecular dynamics nonetheless produces macroscopic
8
+ irreversibility (an arrow of time) as the velocity distribution relaxes to
9
+ the Maxwell-Boltzmann form.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import numpy as np
15
+
16
+ from physicskit.statphys.core.md_engine import lj_forces, velocity_verlet_step
17
+
18
+ __all__ = ["LennardJonesGas"]
19
+
20
+
21
+ class LennardJonesGas:
22
+ """A 2D N-particle Lennard-Jones gas in a periodic square box.
23
+
24
+ Particles are initialized on a lattice (to avoid the divergent
25
+ Lennard-Jones repulsion of random overlapping placements) and given
26
+ velocities drawn from an arbitrary, generally non-equilibrium initial
27
+ distribution, then integrated with the symplectic Velocity Verlet
28
+ scheme.
29
+
30
+ Parameters
31
+ ----------
32
+ n_particles : int, default=100
33
+ Number of particles. Rounded up internally so that
34
+ ``ceil(sqrt(n_particles))**2`` particles fit on a square starting
35
+ lattice; the requested count is used for all physical averages.
36
+ box_size : float, default=20.0
37
+ Side length of the square periodic simulation box.
38
+ temperature_init : float, default=1.0
39
+ Nominal temperature used to set the initial velocity scale (see
40
+ ``initial_velocity_distribution``).
41
+ mass : float, default=1.0
42
+ Common particle mass.
43
+ dt : float, default=0.005
44
+ Integration time step.
45
+ epsilon : float, default=1.0
46
+ Lennard-Jones well depth.
47
+ sigma : float, default=1.0
48
+ Lennard-Jones length scale.
49
+ cutoff : float, default=2.5
50
+ Interaction cutoff radius.
51
+ initial_velocity_distribution : {"maxwell_boltzmann", "uniform", "delta"}, default="uniform"
52
+ Shape of the initial (generally non-equilibrium) velocity
53
+ distribution. ``"uniform"`` and ``"delta"`` are useful starting
54
+ points for watching relaxation toward Maxwell-Boltzmann via the
55
+ H-theorem; ``"maxwell_boltzmann"`` starts already at equilibrium.
56
+ kB : float, default=1.0
57
+ Boltzmann constant.
58
+ seed : int, optional
59
+ Seed for the initial configuration.
60
+
61
+ Attributes
62
+ ----------
63
+ positions : ndarray of shape (N, 2)
64
+ velocities : ndarray of shape (N, 2)
65
+ forces : ndarray of shape (N, 2)
66
+ Forces at the current ``positions``, kept up to date across calls to
67
+ :meth:`step` so each step costs one force evaluation.
68
+ time : float
69
+ Elapsed simulation time.
70
+ """
71
+
72
+ def __init__(
73
+ self,
74
+ n_particles=100,
75
+ box_size=20.0,
76
+ temperature_init=1.0,
77
+ mass=1.0,
78
+ dt=0.005,
79
+ epsilon=1.0,
80
+ sigma=1.0,
81
+ cutoff=2.5,
82
+ initial_velocity_distribution="uniform",
83
+ kB=1.0,
84
+ seed=None,
85
+ ):
86
+ self.n_particles = n_particles
87
+ self.box_size = box_size
88
+ self.mass = mass
89
+ self.dt = dt
90
+ self.epsilon = epsilon
91
+ self.sigma = sigma
92
+ self.cutoff = cutoff
93
+ self.kB = kB
94
+ self.time = 0.0
95
+ self._rng = np.random.default_rng(seed)
96
+
97
+ self.positions = self._lattice_positions(n_particles, box_size, self._rng)
98
+ self.velocities = self._initial_velocities(n_particles, temperature_init, mass, kB, initial_velocity_distribution, self._rng)
99
+ self.forces, self._potential_energy = lj_forces(self.positions, box_size, epsilon=epsilon, sigma=sigma, cutoff=cutoff)
100
+
101
+ @staticmethod
102
+ def _lattice_positions(n_particles, box_size, rng):
103
+ n_side = int(np.ceil(np.sqrt(n_particles)))
104
+ spacing = box_size / n_side
105
+ xs, ys = np.meshgrid((np.arange(n_side) + 0.5) * spacing, (np.arange(n_side) + 0.5) * spacing)
106
+ lattice = np.column_stack([xs.ravel(), ys.ravel()])
107
+ jitter = rng.uniform(-0.05 * spacing, 0.05 * spacing, size=lattice.shape)
108
+ return (lattice + jitter)[:n_particles]
109
+
110
+ @staticmethod
111
+ def _initial_velocities(n_particles, temperature, mass, kB, distribution, rng):
112
+ std = np.sqrt(kB * temperature / mass)
113
+ if distribution == "maxwell_boltzmann":
114
+ v = rng.normal(0.0, std, size=(n_particles, 2))
115
+ elif distribution == "uniform":
116
+ limit = std * np.sqrt(3.0)
117
+ v = rng.uniform(-limit, limit, size=(n_particles, 2))
118
+ elif distribution == "delta":
119
+ speed = std * np.sqrt(2.0)
120
+ angles = rng.uniform(0.0, 2.0 * np.pi, size=n_particles)
121
+ v = speed * np.column_stack([np.cos(angles), np.sin(angles)])
122
+ else:
123
+ raise ValueError("initial_velocity_distribution must be 'maxwell_boltzmann', 'uniform', or 'delta'")
124
+ v -= v.mean(axis=0, keepdims=True)
125
+ return v
126
+
127
+ def step(self, n_steps=1):
128
+ """Advance the simulation by ``n_steps`` Velocity Verlet integration steps.
129
+
130
+ Parameters
131
+ ----------
132
+ n_steps : int, default=1
133
+ Number of integration steps to perform.
134
+ """
135
+ for _ in range(n_steps):
136
+ self.positions, self.velocities, self.forces, self._potential_energy = velocity_verlet_step(
137
+ self.positions,
138
+ self.velocities,
139
+ self.forces,
140
+ self.dt,
141
+ self.box_size,
142
+ mass=self.mass,
143
+ epsilon=self.epsilon,
144
+ sigma=self.sigma,
145
+ cutoff=self.cutoff,
146
+ )
147
+ self.time += self.dt
148
+
149
+ def kinetic_energy(self):
150
+ """Total kinetic energy :math:`\\sum_i \\frac{1}{2} m v_i^2`."""
151
+ return 0.5 * self.mass * np.sum(self.velocities**2)
152
+
153
+ def potential_energy(self):
154
+ """Total Lennard-Jones potential energy at the current configuration."""
155
+ return self._potential_energy
156
+
157
+ def total_energy(self):
158
+ """Total (kinetic + potential) energy, conserved up to integration error."""
159
+ return self.kinetic_energy() + self.potential_energy()
160
+
161
+ def temperature(self):
162
+ """Instantaneous kinetic temperature from equipartition, :math:`T = \\langle m v^2 \\rangle / (d\\, k_B)`.
163
+
164
+ With :math:`d=2` spatial dimensions and 2 degrees of freedom removed
165
+ for the fixed center-of-mass momentum.
166
+ """
167
+ dof = 2 * self.n_particles - 2
168
+ return 2.0 * self.kinetic_energy() / (dof * self.kB)
169
+
170
+ def speeds(self):
171
+ """Instantaneous particle speeds :math:`|v_i|`."""
172
+ return np.linalg.norm(self.velocities, axis=1)
173
+
174
+ def h_function(self, bins=40, v_max=None):
175
+ """Estimate Boltzmann's H-function from the instantaneous speed histogram.
176
+
177
+ .. math::
178
+
179
+ H(t) = \\int_0^\\infty f(v, t) \\ln f(v, t) \\, dv
180
+
181
+ estimated by binning the current particle speeds into a normalized
182
+ density histogram. :math:`H` decreases monotonically (on average) as
183
+ an arbitrary initial velocity distribution relaxes toward the
184
+ Maxwell-Boltzmann equilibrium, which minimizes :math:`H` at fixed
185
+ energy -- the microscopic root of the second law of thermodynamics.
186
+
187
+ Parameters
188
+ ----------
189
+ bins : int, default=40
190
+ Number of histogram bins.
191
+ v_max : float, optional
192
+ Upper edge of the speed histogram. Defaults to
193
+ ``1.5 * speeds().max()``.
194
+
195
+ Returns
196
+ -------
197
+ float
198
+ The estimated value of :math:`H(t)`.
199
+ """
200
+ speeds = self.speeds()
201
+ if v_max is None:
202
+ v_max = 1.5 * speeds.max() if speeds.max() > 0 else 1.0
203
+ density, edges = np.histogram(speeds, bins=bins, range=(0.0, v_max), density=True)
204
+ widths = np.diff(edges)
205
+ mask = density > 0
206
+ return float(np.sum(density[mask] * np.log(density[mask]) * widths[mask]))
207
+
208
+ def run(self, n_steps, steps_per_record=10, bins=40):
209
+ """Integrate forward while recording a time series of thermodynamic observables.
210
+
211
+ Parameters
212
+ ----------
213
+ n_steps : int
214
+ Total number of integration steps to perform.
215
+ steps_per_record : int, default=10
216
+ Number of integration steps between recorded samples.
217
+ bins : int, default=40
218
+ Histogram bins used for each :meth:`h_function` estimate.
219
+
220
+ Returns
221
+ -------
222
+ dict of str -> ndarray
223
+ Keys ``"time"``, ``"H"``, ``"temperature"``, ``"kinetic_energy"``,
224
+ ``"potential_energy"``, ``"total_energy"``, each a 1D array
225
+ sampled every ``steps_per_record`` steps (including the initial
226
+ state).
227
+
228
+ Examples
229
+ --------
230
+ >>> gas = LennardJonesGas(n_particles=64, box_size=15.0, seed=0)
231
+ >>> history = gas.run(n_steps=200, steps_per_record=50)
232
+ >>> history["H"].shape[0]
233
+ 5
234
+ """
235
+ n_records = n_steps // steps_per_record + 1
236
+ history = {
237
+ "time": np.empty(n_records),
238
+ "H": np.empty(n_records),
239
+ "temperature": np.empty(n_records),
240
+ "kinetic_energy": np.empty(n_records),
241
+ "potential_energy": np.empty(n_records),
242
+ "total_energy": np.empty(n_records),
243
+ }
244
+
245
+ def _record(idx):
246
+ history["time"][idx] = self.time
247
+ history["H"][idx] = self.h_function(bins=bins)
248
+ history["temperature"][idx] = self.temperature()
249
+ history["kinetic_energy"][idx] = self.kinetic_energy()
250
+ history["potential_energy"][idx] = self.potential_energy()
251
+ history["total_energy"][idx] = self.total_energy()
252
+
253
+ _record(0)
254
+ for idx in range(1, n_records):
255
+ self.step(steps_per_record)
256
+ _record(idx)
257
+
258
+ return history
@@ -0,0 +1,146 @@
1
+ """Jarzynski's equality: exact free energies from irreversible, nonequilibrium work.
2
+
3
+ The second law only bounds the *average* work done driving a system between
4
+ two equilibrium states: :math:`\\langle W \\rangle \\ge \\Delta F`, with
5
+ equality only in the reversible, infinitely slow limit. Jarzynski (1997)
6
+ found a remarkable equality hiding behind this inequality: averaging not
7
+ :math:`W` itself but :math:`e^{-\\beta W}` over an ensemble of repeated
8
+ *arbitrarily fast*, arbitrarily irreversible realizations of the same
9
+ protocol recovers the equilibrium free energy difference exactly,
10
+
11
+ .. math::
12
+
13
+ e^{-\\beta \\Delta F} = \\left\\langle e^{-\\beta W} \\right\\rangle,
14
+
15
+ no matter how far from equilibrium any individual trajectory is driven.
16
+ Jensen's inequality applied to this identity immediately reproduces the
17
+ second law, :math:`\\langle W \\rangle \\ge \\Delta F`, as a corollary
18
+ rather than an independent postulate -- nonequilibrium work fluctuations
19
+ turn out to carry exact equilibrium information, not just a biased,
20
+ dissipation-corrupted estimate of it.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import numpy as np
26
+
27
+ __all__ = ["JarzynskiHarmonicTrap"]
28
+
29
+
30
+ class JarzynskiHarmonicTrap:
31
+ """A Brownian particle in a harmonic trap dragged at finite speed, verifying the Jarzynski equality.
32
+
33
+ A single overdamped particle sits in the potential :math:`U(x,
34
+ \\lambda) = \\frac{1}{2} k (x - \\lambda)^2`, whose center
35
+ :math:`\\lambda` is the control parameter. :meth:`run_protocol` drags
36
+ :math:`\\lambda` linearly from one value to another over a finite time
37
+ :math:`\\tau`, for many independent realizations starting from thermal
38
+ equilibrium, integrating the overdamped Langevin equation
39
+
40
+ .. math::
41
+
42
+ \\gamma\\, dx = -k(x - \\lambda)\\, dt + \\sqrt{2\\gamma k_B T}\\, dW_t,
43
+
44
+ and accumulating each trajectory's thermodynamic work :math:`W =
45
+ \\int \\frac{\\partial U}{\\partial \\lambda}\\, \\dot\\lambda\\, dt =
46
+ -\\int k(x - \\lambda)\\, d\\lambda`. Because the trap's stiffness never
47
+ changes -- only its center moves -- the true equilibrium free energy is
48
+ identical before and after the protocol, :math:`\\Delta F = 0` exactly,
49
+ by translational invariance. This makes the harmonic trap the cleanest
50
+ possible test case: any protocol speed dissipates heat and drives
51
+ :math:`\\langle W \\rangle` strictly positive (the second law), while
52
+ the exponential average of the *same* work samples should recover
53
+ :math:`\\Delta F = 0` regardless of how fast or slow the drag is.
54
+
55
+ Parameters
56
+ ----------
57
+ k : float, default=1.0
58
+ Trap stiffness.
59
+ gamma : float, default=1.0
60
+ Friction (drag) coefficient.
61
+ kB : float, default=1.0
62
+ Boltzmann constant.
63
+ T : float, default=1.0
64
+ Temperature.
65
+ seed : int, optional
66
+ Seed for the initial equilibrium sampling and the thermal noise.
67
+ """
68
+
69
+ def __init__(self, k=1.0, gamma=1.0, kB=1.0, T=1.0, seed=None):
70
+ self.k = k
71
+ self.gamma = gamma
72
+ self.kB = kB
73
+ self.T = T
74
+ self._rng = np.random.default_rng(seed)
75
+
76
+ def run_protocol(self, lambda_0=0.0, lambda_1=3.0, tau=5.0, n_steps=1000, n_trajectories=5000):
77
+ """Drag the trap center from lambda_0 to lambda_1 over time tau, recording each trajectory's work.
78
+
79
+ Every trajectory starts from an independent sample of the
80
+ equilibrium Boltzmann distribution at the initial trap position,
81
+ :math:`x_0 \\sim \\mathcal{N}(\\lambda_0, k_B T / k)`, then is
82
+ integrated forward by Euler-Maruyama while the trap center advances
83
+ linearly in time.
84
+
85
+ Parameters
86
+ ----------
87
+ lambda_0, lambda_1 : float, default=0.0, 3.0
88
+ Initial and final trap-center positions.
89
+ tau : float, default=5.0
90
+ Protocol duration. Smaller ``tau`` drags the system further
91
+ from equilibrium and dissipates more heat, but should not
92
+ change the Jarzynski free-energy estimate.
93
+ n_steps : int, default=1000
94
+ Number of Euler-Maruyama integration steps.
95
+ n_trajectories : int, default=5000
96
+ Number of independent realizations. The exponential average
97
+ underlying the Jarzynski estimator is dominated by rare,
98
+ low-work trajectories, so it converges slowly (more
99
+ trajectories are needed for a longer or more violent protocol).
100
+
101
+ Returns
102
+ -------
103
+ ndarray of shape (n_trajectories,)
104
+ Accumulated work :math:`W` for each realization.
105
+ """
106
+ dt = tau / n_steps
107
+ D = self.kB * self.T / self.gamma
108
+ noise_scale = np.sqrt(2.0 * D * dt)
109
+ centers = np.linspace(lambda_0, lambda_1, n_steps + 1)
110
+
111
+ x = self._rng.normal(loc=lambda_0, scale=np.sqrt(self.kB * self.T / self.k), size=n_trajectories)
112
+ work = np.zeros(n_trajectories)
113
+
114
+ for step in range(n_steps):
115
+ lam, lam_next = centers[step], centers[step + 1]
116
+ d_lambda = lam_next - lam
117
+ work += -self.k * (x - lam) * d_lambda
118
+ force = -self.k * (x - lam)
119
+ x = x + (force / self.gamma) * dt + noise_scale * self._rng.standard_normal(n_trajectories)
120
+
121
+ return work
122
+
123
+ def jarzynski_free_energy_estimate(self, work):
124
+ """Estimate :math:`\\Delta F = -k_B T \\ln \\langle e^{-\\beta W} \\rangle` from work samples.
125
+
126
+ Uses the log-sum-exp trick for numerical stability, since
127
+ individual :math:`e^{-\\beta W}` terms can otherwise under- or
128
+ overflow long before the average itself does.
129
+
130
+ Parameters
131
+ ----------
132
+ work : array_like
133
+ Work samples, e.g. from :meth:`run_protocol`.
134
+
135
+ Returns
136
+ -------
137
+ float
138
+ Estimated free energy difference. For :class:`JarzynskiHarmonicTrap`,
139
+ the true value is exactly 0 regardless of the protocol.
140
+ """
141
+ work = np.asarray(work, dtype=np.float64)
142
+ beta = 1.0 / (self.kB * self.T)
143
+ exponents = -beta * work
144
+ m = np.max(exponents)
145
+ log_mean = m + np.log(np.mean(np.exp(exponents - m)))
146
+ return float(-self.kB * self.T * log_mean)