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,217 @@
1
+ """Berry curvature, Chern numbers, Zak phase, and Z2 invariants.
2
+
3
+ The workhorse here is the Fukui-Hatsugai-Suzuki (FHS) lattice algorithm,
4
+ which computes an exactly quantized, gauge-invariant Chern number from a
5
+ finite grid of Bloch eigenvectors -- no smooth gauge choice required. The
6
+ per-plaquette flux accumulation is numba-jitted since it is the inner loop
7
+ of a double sum over the whole Brillouin-zone grid.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import numpy as np
13
+ from numba import njit
14
+
15
+ __all__ = ["compute_berry_curvature", "compute_chern_number", "zak_phase", "z2_invariant"]
16
+
17
+
18
+ def _bloch_eigensystem(hamiltonian_func, grid_size: int):
19
+ """Diagonalize ``hamiltonian_func`` on a closed (grid_size+1)^2 k-grid.
20
+
21
+ The extra row/column closes the discretized Brillouin-zone torus so
22
+ that plaquette (a, n) reuses the same eigenvectors as plaquette (a, 0).
23
+ """
24
+ n = grid_size
25
+ sample = np.asarray(hamiltonian_func(0.0, 0.0), dtype=complex)
26
+ norb = sample.shape[0]
27
+ U = np.empty((n + 1, n + 1, norb, norb), dtype=complex)
28
+ for a in range(n + 1):
29
+ k1 = 2 * np.pi * a / n
30
+ for b in range(n + 1):
31
+ k2 = 2 * np.pi * b / n
32
+ H = np.asarray(hamiltonian_func(k1, k2), dtype=complex)
33
+ _, v = np.linalg.eigh(H)
34
+ U[a, b] = v.T # U[a, b, band, :] is the band-th eigenvector (contiguous)
35
+ return U
36
+
37
+
38
+ @njit(cache=True)
39
+ def _fhs_curvature_grid(U, n, band):
40
+ F = np.zeros((n, n))
41
+ for a in range(n):
42
+ for b in range(n):
43
+ v00 = U[a, b, band, :]
44
+ v10 = U[a + 1, b, band, :]
45
+ v11 = U[a + 1, b + 1, band, :]
46
+ v01 = U[a, b + 1, band, :]
47
+ u1 = np.vdot(v00, v10)
48
+ u1 = u1 / abs(u1)
49
+ u2 = np.vdot(v10, v11)
50
+ u2 = u2 / abs(u2)
51
+ u3 = np.vdot(v11, v01)
52
+ u3 = u3 / abs(u3)
53
+ u4 = np.vdot(v01, v00)
54
+ u4 = u4 / abs(u4)
55
+ F[a, b] = np.angle(u1 * u2 * u3 * u4)
56
+ return F
57
+
58
+
59
+ def compute_berry_curvature(hamiltonian_func, grid_size: int = 50, band_index: int = 0) -> np.ndarray:
60
+ """Compute the discretized Berry curvature of one band over the Brillouin zone.
61
+
62
+ Uses the Fukui-Hatsugai-Suzuki (FHS) link-variable formula, which is
63
+ gauge invariant plaquette by plaquette and needs no smooth choice of
64
+ eigenvector phase.
65
+
66
+ Parameters
67
+ ----------
68
+ hamiltonian_func : callable
69
+ A function ``H(k1, k2)`` returning the ``(N, N)`` complex Bloch
70
+ Hamiltonian at reduced crystal momentum ``(k1, k2)``, each
71
+ periodic on :math:`[0, 2\\pi)` (see :mod:`physicskit.condensed.tight_binding`).
72
+ grid_size : int, default=50
73
+ Number of plaquettes along each of :math:`k_1, k_2`.
74
+ band_index : int, default=0
75
+ Band index (0 = lowest energy) to compute the curvature for.
76
+
77
+ Returns
78
+ -------
79
+ ndarray, shape (grid_size, grid_size)
80
+ Berry flux through each plaquette, in :math:`(-\\pi, \\pi]`. Summing
81
+ and dividing by :math:`2\\pi` gives the band's Chern number.
82
+
83
+ See Also
84
+ --------
85
+ compute_chern_number : Integrates this curvature over the full zone for every band.
86
+
87
+ Examples
88
+ --------
89
+ >>> import numpy as np
90
+ >>> from physicskit.condensed.models import haldane_model
91
+ >>> H_func = lambda k1, k2: haldane_model(k1, k2, t=1.0, t2=0.2, phi=np.pi / 2, M=0.0)
92
+ >>> F = compute_berry_curvature(H_func, grid_size=30, band_index=0)
93
+ >>> F.shape
94
+ (30, 30)
95
+ >>> round(float(F.sum() / (2 * np.pi)))
96
+ 1
97
+ """
98
+ U = _bloch_eigensystem(hamiltonian_func, grid_size)
99
+ return _fhs_curvature_grid(U, grid_size, band_index)
100
+
101
+
102
+ def compute_chern_number(hamiltonian_func, grid_size: int = 50) -> list:
103
+ """Compute the Chern number of every band using the Fukui-Hatsugai-Suzuki method.
104
+
105
+ Parameters
106
+ ----------
107
+ hamiltonian_func : callable
108
+ A function ``H(k1, k2)`` returning an ``(N, N)`` complex Bloch
109
+ Hamiltonian, using the reduced-momentum convention of
110
+ :mod:`physicskit.condensed.tight_binding`.
111
+ grid_size : int, default=50
112
+ Discretization resolution for :math:`k_1` and :math:`k_2` across
113
+ :math:`[0, 2\\pi)`.
114
+
115
+ Returns
116
+ -------
117
+ list of int
118
+ Chern integer for each energy band, ordered from lowest to highest energy.
119
+
120
+ Examples
121
+ --------
122
+ >>> import numpy as np
123
+ >>> from physicskit.condensed.models import haldane_model
124
+ >>> H_func = lambda k1, k2: haldane_model(k1, k2, t=1.0, t2=0.2, phi=np.pi / 2, M=0.0)
125
+ >>> chern_numbers = compute_chern_number(H_func, grid_size=30)
126
+ >>> print(chern_numbers)
127
+ [1, -1]
128
+ """
129
+ U = _bloch_eigensystem(hamiltonian_func, grid_size)
130
+ norb = U.shape[-1]
131
+ return [int(round(_fhs_curvature_grid(U, grid_size, band).sum() / (2 * np.pi))) for band in range(norb)]
132
+
133
+
134
+ def zak_phase(hamiltonian_func_1d, grid_size: int = 200, band_index: int = 0) -> float:
135
+ """Compute the Zak phase of a 1D band: the Berry phase accumulated across the BZ.
136
+
137
+ Parameters
138
+ ----------
139
+ hamiltonian_func_1d : callable
140
+ A function ``H(k)`` returning the ``(N, N)`` complex Bloch Hamiltonian
141
+ at reduced momentum ``k``, periodic on :math:`[0, 2\\pi)`.
142
+ grid_size : int, default=200
143
+ Number of discretization steps around the 1D Brillouin zone.
144
+ band_index : int, default=0
145
+ Band index (0 = lowest energy).
146
+
147
+ Returns
148
+ -------
149
+ float
150
+ The Zak phase, wrapped to :math:`(-\\pi, \\pi]`. For a chiral-symmetric
151
+ model such as SSH, this is quantized to :math:`0` (trivial) or
152
+ :math:`\\pi` (topological).
153
+
154
+ Examples
155
+ --------
156
+ >>> import numpy as np
157
+ >>> from physicskit.condensed.models import ssh_hamiltonian
158
+ >>> topological = lambda k: ssh_hamiltonian(k, v=0.5, w=1.0)
159
+ >>> trivial = lambda k: ssh_hamiltonian(k, v=1.0, w=0.5)
160
+ >>> round(abs(zak_phase(topological)), 4)
161
+ 3.1416
162
+ >>> round(abs(zak_phase(trivial)), 4)
163
+ 0.0
164
+ """
165
+ n = grid_size
166
+ vecs = np.empty((n + 1, hamiltonian_func_1d(0.0).shape[0]), dtype=complex)
167
+ for i in range(n + 1):
168
+ k = 2 * np.pi * i / n
169
+ _, v = np.linalg.eigh(np.asarray(hamiltonian_func_1d(k), dtype=complex))
170
+ vecs[i] = v[:, band_index]
171
+ prod = 1.0 + 0j
172
+ for i in range(n):
173
+ overlap = np.vdot(vecs[i], vecs[i + 1])
174
+ prod *= overlap / abs(overlap)
175
+ return float(-np.angle(prod))
176
+
177
+
178
+ def z2_invariant(hamiltonian_func, grid_size: int = 30, spin_block: tuple = (0, 2)) -> int:
179
+ """Compute the :math:`\\mathbb{Z}_2` invariant of an :math:`s_z`-conserving spinful model.
180
+
181
+ Valid whenever ``hamiltonian_func`` is block-diagonal in spin (e.g. the
182
+ Kane-Mele or BHZ models with Rashba coupling set to zero), in which case
183
+ the :math:`\\mathbb{Z}_2` invariant reduces to the spin-up sector's Chern
184
+ number modulo 2 (Sheng et al. / spin-Chern-number approach).
185
+
186
+ Parameters
187
+ ----------
188
+ hamiltonian_func : callable
189
+ A function ``H(k1, k2)`` returning the full ``(2N, 2N)`` Bloch
190
+ Hamiltonian with the spin-up block occupying ``spin_block``.
191
+ grid_size : int, default=30
192
+ Discretization resolution for the Chern-number calculation.
193
+ spin_block : tuple of int, default=(0, 2)
194
+ ``(start, stop)`` slice selecting the spin-up block's rows/columns.
195
+
196
+ Returns
197
+ -------
198
+ int
199
+ :math:`\\mathbb{Z}_2` invariant, 0 (trivial) or 1 (topological).
200
+
201
+ Examples
202
+ --------
203
+ >>> from physicskit.condensed.models import kane_mele_hamiltonian
204
+ >>> trivial = lambda k1, k2: kane_mele_hamiltonian(k1, k2, lambda_so=0.0)
205
+ >>> topological = lambda k1, k2: kane_mele_hamiltonian(k1, k2, lambda_so=0.06)
206
+ >>> z2_invariant(trivial, grid_size=20)
207
+ 0
208
+ >>> z2_invariant(topological, grid_size=20)
209
+ 1
210
+ """
211
+ lo, hi = spin_block
212
+
213
+ def h_up(k1, k2):
214
+ return np.asarray(hamiltonian_func(k1, k2), dtype=complex)[lo:hi, lo:hi]
215
+
216
+ chern_up = compute_chern_number(h_up, grid_size)
217
+ return int(chern_up[0]) % 2
@@ -0,0 +1,296 @@
1
+ """Plotting helpers: band structures, Berry curvature heatmaps, edge-state densities, Fermi surfaces.
2
+
3
+ Matplotlib is used for 2D plots (band structures, Berry-curvature heatmaps,
4
+ real-space wavefunction density), and Plotly for interactive 3D Fermi-surface
5
+ isosurfaces. Every function returns its figure object rather than calling
6
+ ``show()``, so it composes cleanly into larger figures or headless pipelines.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import matplotlib.pyplot as plt
12
+ import numpy as np
13
+ import plotly.graph_objects as go
14
+
15
+ __all__ = [
16
+ "plot_band_structure",
17
+ "plot_berry_curvature",
18
+ "plot_edge_state_density",
19
+ "plot_lattice_structure",
20
+ "plot_fermi_surface_3d",
21
+ ]
22
+
23
+
24
+ def plot_band_structure(hamiltonian_func, path_points, labels=None, n_per_segment: int = 100, ax=None):
25
+ """Plot bands along a piecewise-linear path through the Brillouin zone.
26
+
27
+ Parameters
28
+ ----------
29
+ hamiltonian_func : callable
30
+ A function ``H(k1, k2)`` returning the Bloch Hamiltonian.
31
+ path_points : sequence of tuple(float, float)
32
+ High-symmetry points (e.g. :math:`\\Gamma, K, M, \\Gamma`) in reduced
33
+ crystal momentum, connected by straight segments.
34
+ labels : sequence of str, optional
35
+ Tick labels for each point in ``path_points``.
36
+ n_per_segment : int, default=100
37
+ Number of sampled k-points per segment.
38
+ ax : matplotlib.axes.Axes, optional
39
+ Axes to draw into; a new figure is created if omitted.
40
+
41
+ Returns
42
+ -------
43
+ fig : matplotlib.figure.Figure
44
+ ax : matplotlib.axes.Axes
45
+
46
+ Examples
47
+ --------
48
+ >>> import numpy as np
49
+ >>> from physicskit.condensed.models import graphene_hamiltonian
50
+ >>> path = [(0, 0), (2 * np.pi / 3, 4 * np.pi / 3), (2 * np.pi / 3, 2 * np.pi / 3), (0, 0)]
51
+ >>> fig, ax = plot_band_structure(lambda k1, k2: graphene_hamiltonian(k1, k2), path, labels=["G", "K", "M", "G"])
52
+ >>> isinstance(fig, plt.Figure)
53
+ True
54
+ >>> sum(1 for line in ax.lines if line.get_color() == "C0")
55
+ 2
56
+ """
57
+ path_points = [np.asarray(p, dtype=float) for p in path_points]
58
+ ks, distance, ticks = [], [0.0], [0.0]
59
+ for p0, p1 in zip(path_points[:-1], path_points[1:], strict=True):
60
+ for s in np.linspace(0, 1, n_per_segment, endpoint=False):
61
+ ks.append(p0 + s * (p1 - p0))
62
+ seg_len = np.linalg.norm(p1 - p0)
63
+ distance.append(distance[-1] + seg_len)
64
+ ticks.append(distance[-1])
65
+ ks.append(path_points[-1])
66
+
67
+ d = [0.0]
68
+ for k0, k1 in zip(ks[:-1], ks[1:], strict=True):
69
+ d.append(d[-1] + np.linalg.norm(k1 - k0))
70
+
71
+ energies = np.array([np.linalg.eigvalsh(np.asarray(hamiltonian_func(*k), dtype=complex)) for k in ks])
72
+
73
+ if ax is None:
74
+ fig, ax = plt.subplots()
75
+ else:
76
+ fig = ax.figure
77
+ for band in range(energies.shape[1]):
78
+ ax.plot(d, energies[:, band], color="C0")
79
+ for t in ticks:
80
+ ax.axvline(t, color="gray", linewidth=0.5)
81
+ if labels is not None:
82
+ ax.set_xticks(ticks)
83
+ ax.set_xticklabels(labels)
84
+ ax.set_ylabel("Energy")
85
+ return fig, ax
86
+
87
+
88
+ def plot_berry_curvature(curvature: np.ndarray, ax=None):
89
+ """Plot a Berry-curvature field over the Brillouin zone as a heatmap.
90
+
91
+ Parameters
92
+ ----------
93
+ curvature : ndarray, shape (grid_size, grid_size)
94
+ Per-plaquette Berry curvature, as returned by
95
+ :func:`physicskit.condensed.topology.compute_berry_curvature`.
96
+ ax : matplotlib.axes.Axes, optional
97
+ Axes to draw into; a new figure is created if omitted.
98
+
99
+ Returns
100
+ -------
101
+ fig : matplotlib.figure.Figure
102
+ ax : matplotlib.axes.Axes
103
+
104
+ Examples
105
+ --------
106
+ >>> import numpy as np
107
+ >>> from physicskit.condensed.models import haldane_model
108
+ >>> from physicskit.condensed.topology import compute_berry_curvature
109
+ >>> H = lambda k1, k2: haldane_model(k1, k2, phi=np.pi / 2)
110
+ >>> F = compute_berry_curvature(H, grid_size=20, band_index=0)
111
+ >>> fig, ax = plot_berry_curvature(F)
112
+ >>> isinstance(fig, plt.Figure)
113
+ True
114
+ """
115
+ if ax is None:
116
+ fig, ax = plt.subplots()
117
+ else:
118
+ fig = ax.figure
119
+ im = ax.imshow(curvature.T, origin="lower", extent=[0, 2 * np.pi, 0, 2 * np.pi], aspect="auto", cmap="RdBu_r")
120
+ fig.colorbar(im, ax=ax, label="Berry curvature")
121
+ ax.set_xlabel("$k_1$")
122
+ ax.set_ylabel("$k_2$")
123
+ return fig, ax
124
+
125
+
126
+ def plot_edge_state_density(ribbon_hamiltonian_func, k_parallel, ax=None):
127
+ """Plot the real-space density of the mid-gap eigenstate closest to zero energy.
128
+
129
+ Useful for visualizing the exponential localization
130
+ :math:`|\\psi(x)|^2 \\sim e^{-2x/\\xi}` of topological edge states exposed
131
+ by :func:`physicskit.condensed.tight_binding.build_ribbon`.
132
+
133
+ Parameters
134
+ ----------
135
+ ribbon_hamiltonian_func : callable
136
+ A function ``H(k_parallel)`` returning the finite ribbon Hamiltonian,
137
+ as produced by :func:`~physicskit.condensed.tight_binding.build_ribbon`.
138
+ k_parallel : array_like
139
+ Momentum along the periodic direction(s) at which to evaluate the ribbon.
140
+ ax : matplotlib.axes.Axes, optional
141
+ Axes to draw into; a new figure is created if omitted.
142
+
143
+ Returns
144
+ -------
145
+ fig : matplotlib.figure.Figure
146
+ ax : matplotlib.axes.Axes
147
+ density : ndarray
148
+ Per-site probability density of the closest-to-zero eigenstate.
149
+
150
+ Examples
151
+ --------
152
+ >>> import numpy as np
153
+ >>> from physicskit.condensed.models import ssh_lattice_hamiltonian
154
+ >>> from physicskit.condensed.tight_binding import build_ribbon
155
+ >>> H = ssh_lattice_hamiltonian(v=0.5, w=1.0)
156
+ >>> H_wire = build_ribbon(H, open_direction=0, n_cells=15)
157
+ >>> fig, ax, density = plot_edge_state_density(H_wire, k_parallel=[])
158
+ >>> bool(density[0] > density[len(density) // 2])
159
+ True
160
+ """
161
+ H = ribbon_hamiltonian_func(k_parallel)
162
+ eigenvalues, eigenvectors = np.linalg.eigh(H)
163
+ idx = int(np.argmin(np.abs(eigenvalues)))
164
+ psi = eigenvectors[:, idx]
165
+ density = np.abs(psi) ** 2
166
+
167
+ if ax is None:
168
+ fig, ax = plt.subplots()
169
+ else:
170
+ fig = ax.figure
171
+ ax.plot(np.arange(len(density)), density, marker="o")
172
+ ax.set_xlabel("Site index")
173
+ ax.set_ylabel(r"$|\psi(x)|^2$")
174
+ ax.set_title(f"Closest-to-zero eigenstate, E={eigenvalues[idx]:.4f}")
175
+ return fig, ax, density
176
+
177
+
178
+ def plot_lattice_structure(positions, bonds, weights=None, ax=None, cmap: str = "viridis", bond_linewidth_scale: float = 3.0):
179
+ """Draw a finite tight-binding cluster's real-space structure: atoms and bonds.
180
+
181
+ Renders the actual geometry of a finite lattice -- e.g. the output of
182
+ :func:`physicskit.condensed.tight_binding.build_finite_cluster` -- rather
183
+ than an abstract site-index plot: bonds as line segments (linewidth
184
+ proportional to hopping strength, so e.g. SSH's alternating strong/weak
185
+ dimerization is directly visible), atoms as markers optionally colored
186
+ and sized by a per-site weight such as edge-state probability density.
187
+
188
+ Parameters
189
+ ----------
190
+ positions : array_like, shape (n_sites, dim)
191
+ Cartesian coordinates of each site, ``dim`` in ``{1, 2}``.
192
+ bonds : sequence of tuple(int, int, complex)
193
+ Real-space hoppings ``(i, j, amplitude)`` indexing into ``positions``.
194
+ weights : array_like, shape (n_sites,), optional
195
+ Per-site scalar (e.g. :math:`|\\psi|^2`) mapped to marker color and
196
+ size. Defaults to uniform, unweighted markers.
197
+ ax : matplotlib.axes.Axes, optional
198
+ Axes to draw into; a new figure is created if omitted.
199
+ cmap : str, default="viridis"
200
+ Colormap used when ``weights`` is given.
201
+ bond_linewidth_scale : float, default=3.0
202
+ Bonds are drawn with linewidth ``bond_linewidth_scale * |amplitude|
203
+ / max(|amplitude|)``.
204
+
205
+ Returns
206
+ -------
207
+ fig : matplotlib.figure.Figure
208
+ ax : matplotlib.axes.Axes
209
+
210
+ Examples
211
+ --------
212
+ >>> import numpy as np
213
+ >>> from physicskit.condensed.models import ssh_lattice_hamiltonian
214
+ >>> from physicskit.condensed.tight_binding import build_finite_cluster
215
+ >>> H, positions, bonds = build_finite_cluster(ssh_lattice_hamiltonian(v=0.5, w=1.0), n_cells=3)
216
+ >>> _, states = np.linalg.eigh(H)
217
+ >>> density = np.abs(states[:, 0]) ** 2
218
+ >>> fig, ax = plot_lattice_structure(positions, bonds, weights=density)
219
+ >>> isinstance(fig, plt.Figure)
220
+ True
221
+ """
222
+ positions = np.atleast_2d(np.asarray(positions, dtype=float))
223
+ x = positions[:, 0]
224
+ y = positions[:, 1] if positions.shape[1] > 1 else np.zeros(len(positions))
225
+
226
+ if ax is None:
227
+ fig, ax = plt.subplots()
228
+ else:
229
+ fig = ax.figure
230
+
231
+ amplitudes = np.array([abs(amp) for _, _, amp in bonds])
232
+ max_amp = amplitudes.max() if amplitudes.size else 1.0
233
+ for (i, j, _amp), a in zip(bonds, amplitudes, strict=True):
234
+ lw = bond_linewidth_scale * a / max_amp if max_amp > 0 else bond_linewidth_scale
235
+ ax.plot(x[[i, j]], y[[i, j]], color="gray", linewidth=lw, zorder=1, solid_capstyle="round")
236
+
237
+ if weights is None:
238
+ ax.scatter(x, y, s=80, color="C0", edgecolor="k", linewidth=0.6, zorder=2)
239
+ else:
240
+ weights = np.asarray(weights, dtype=float)
241
+ max_w = weights.max()
242
+ sizes = 30 + 300 * weights / max_w if max_w > 0 else np.full_like(weights, 30.0)
243
+ sc = ax.scatter(x, y, s=sizes, c=weights, cmap=cmap, edgecolor="k", linewidth=0.6, zorder=2)
244
+ fig.colorbar(sc, ax=ax, label="weight")
245
+
246
+ ax.set_aspect("equal")
247
+ ax.set_xlabel("x")
248
+ ax.set_ylabel("y")
249
+ return fig, ax
250
+
251
+
252
+ def plot_fermi_surface_3d(dispersion_func, mu: float = 0.0, grid_size: int = 40, k_range: float = np.pi):
253
+ """Render a 3D Fermi-surface isosurface :math:`\\varepsilon(\\mathbf{k}) = \\mu`.
254
+
255
+ Parameters
256
+ ----------
257
+ dispersion_func : callable
258
+ A function ``eps(kx, ky, kz)`` returning the band energy.
259
+ mu : float, default=0.0
260
+ Chemical potential (Fermi energy) defining the isosurface.
261
+ grid_size : int, default=40
262
+ Number of samples along each of :math:`k_x, k_y, k_z`.
263
+ k_range : float, default=pi
264
+ Half-width of the cubic sampling box, ``[-k_range, k_range]``.
265
+
266
+ Returns
267
+ -------
268
+ plotly.graph_objects.Figure
269
+ A figure containing a single ``Isosurface`` trace.
270
+
271
+ Examples
272
+ --------
273
+ >>> import numpy as np
274
+ >>> eps = lambda kx, ky, kz: -2 * (np.cos(kx) + np.cos(ky) + np.cos(kz))
275
+ >>> fig = plot_fermi_surface_3d(eps, mu=0.0, grid_size=20)
276
+ >>> fig.data[0].type
277
+ 'isosurface'
278
+ """
279
+ grid = np.linspace(-k_range, k_range, grid_size)
280
+ kx, ky, kz = np.meshgrid(grid, grid, grid, indexing="ij")
281
+ values = dispersion_func(kx, ky, kz)
282
+ fig = go.Figure(
283
+ data=go.Isosurface(
284
+ x=kx.flatten(),
285
+ y=ky.flatten(),
286
+ z=kz.flatten(),
287
+ value=values.flatten(),
288
+ isomin=mu,
289
+ isomax=mu,
290
+ surface_count=1,
291
+ colorscale="Viridis",
292
+ showscale=False,
293
+ )
294
+ )
295
+ fig.update_layout(scene={"xaxis_title": "kx", "yaxis_title": "ky", "zaxis_title": "kz"})
296
+ return fig
@@ -0,0 +1,180 @@
1
+ r"""Weyl semimetals (2011-2015): momentum-space monopoles and Fermi arcs.
2
+
3
+ Wan, Turner, Vishwanath, and Savrasov predicted that breaking either
4
+ inversion or time-reversal symmetry in a 3D Dirac material splits each
5
+ doubly-degenerate Dirac point into a pair of nondegenerate Weyl nodes of
6
+ opposite chirality -- momentum-space sources and sinks of Berry curvature,
7
+ each the direct 3D generalization of the 2D TKNN invariant
8
+ (:func:`physicskit.condensed.topology.compute_chern_number`) evaluated on a
9
+ small sphere surrounding it. Xu, Lv, and coworkers confirmed the prediction
10
+ by ARPES in TaAs in 2015, directly imaging both the bulk Weyl nodes and the
11
+ open, non-closed "Fermi arcs" of surface states connecting the surface
12
+ projections of opposite-chirality nodes -- a bulk-boundary signature with
13
+ no two-dimensional analogue.
14
+
15
+ This module implements the minimal two-band lattice model with this
16
+ physics, a cubic-lattice generalization of the same Dirac-matrix
17
+ construction used for the 3D topological insulator
18
+ (:mod:`physicskit.condensed.topological_insulator_3d`), reduced from four
19
+ bands to two since a genuine (as opposed to symmetry-protected) Weyl node
20
+ only needs a two-level crossing:
21
+
22
+ .. math::
23
+
24
+ H(\mathbf{k}) = \sin k_x\,\sigma_x + \sin k_y\,\sigma_y +
25
+ \left(m - t\sum_{i=x,y,z}\cos k_i\right)\sigma_z .
26
+
27
+ For :math:`1 < m/t < 3` the mass term vanishes at exactly two points on the
28
+ :math:`k_z` axis, :math:`\mathbf{k}=(0,0,\pm k_0)` with
29
+ :math:`\cos k_0 = m/t - 2` -- a pair of Weyl nodes of opposite chirality.
30
+ Between them, each fixed-:math:`k_z` slice is a 2D Chern insulator; outside
31
+ them, it is trivial. Opening the lattice along ``x`` exposes exactly the
32
+ surface signature of that alternation: a single chiral edge mode crossing
33
+ zero energy for :math:`|k_z| < k_0`, and a full gap for :math:`|k_z| > k_0`
34
+ -- the lattice-model fingerprint of the Fermi arc.
35
+
36
+ Uses the same natural-unit convention (:math:`\hbar=e=1`) as the rest of
37
+ :mod:`physicskit.condensed`.
38
+ """
39
+
40
+ from __future__ import annotations
41
+
42
+ import numpy as np
43
+
44
+ __all__ = ["weyl_semimetal_hamiltonian", "weyl_node_locations", "weyl_semimetal_slab_hamiltonian"]
45
+
46
+ _SIGMA_X = np.array([[0, 1], [1, 0]], dtype=complex)
47
+ _SIGMA_Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
48
+ _SIGMA_Z = np.array([[1, 0], [0, -1]], dtype=complex)
49
+
50
+
51
+ def weyl_semimetal_hamiltonian(kx: float, ky: float, kz: float, m: float, t: float = 1.0) -> np.ndarray:
52
+ r"""Bloch Hamiltonian of the minimal two-band cubic-lattice Weyl semimetal.
53
+
54
+ Parameters
55
+ ----------
56
+ kx, ky, kz : float
57
+ Reduced crystal momenta, each periodic on :math:`[0, 2\pi)`.
58
+ m : float
59
+ Band mass. Two Weyl nodes exist on the :math:`k_z` axis for
60
+ :math:`1 < m/t < 3` (see :func:`weyl_node_locations`); outside that
61
+ window the model is fully gapped.
62
+ t : float, default=1.0
63
+ Hopping amplitude setting the bulk bandwidth.
64
+
65
+ Returns
66
+ -------
67
+ ndarray, shape (2, 2)
68
+ Hermitian Bloch Hamiltonian.
69
+
70
+ See Also
71
+ --------
72
+ weyl_node_locations : Exact :math:`k_z` positions of the two Weyl nodes.
73
+ weyl_semimetal_slab_hamiltonian : Open-boundary slab exposing Fermi-arc surface states.
74
+
75
+ Examples
76
+ --------
77
+ At ``m/t = 2`` the two nodes sit at :math:`k_z = \pm\pi/2`, where the
78
+ bulk gap closes exactly:
79
+
80
+ >>> import numpy as np
81
+ >>> H = weyl_semimetal_hamiltonian(0.0, 0.0, np.pi / 2, m=2.0, t=1.0)
82
+ >>> np.round(np.linalg.eigvalsh(H), 8)
83
+ array([0., 0.])
84
+ >>> H_away = weyl_semimetal_hamiltonian(np.pi, np.pi, np.pi, m=2.0, t=1.0)
85
+ >>> np.round(np.linalg.eigvalsh(H_away), 8)
86
+ array([-5., 5.])
87
+ """
88
+ mass = m - t * (np.cos(kx) + np.cos(ky) + np.cos(kz))
89
+ return np.sin(kx) * _SIGMA_X + np.sin(ky) * _SIGMA_Y + mass * _SIGMA_Z
90
+
91
+
92
+ def weyl_node_locations(m: float, t: float = 1.0) -> tuple:
93
+ r"""Exact :math:`k_z` positions of the two Weyl nodes on the :math:`k_z` axis.
94
+
95
+ Solves :math:`m - t(2 + \cos k_z) = 0` -- the mass term of
96
+ :func:`weyl_semimetal_hamiltonian` at :math:`k_x=k_y=0` -- for
97
+ :math:`k_z`.
98
+
99
+ Parameters
100
+ ----------
101
+ m : float
102
+ Band mass.
103
+ t : float, default=1.0
104
+ Hopping amplitude.
105
+
106
+ Returns
107
+ -------
108
+ tuple of float or None
109
+ ``(-k0, +k0)`` with :math:`k_0 \in (0, \pi)`, or ``None`` if
110
+ :math:`m/t` lies outside :math:`(1, 3)` (no nodes on this axis).
111
+
112
+ Examples
113
+ --------
114
+ >>> import numpy as np
115
+ >>> k0 = weyl_node_locations(m=2.0, t=1.0)
116
+ >>> np.round(k0, 8)
117
+ array([-1.57079633, 1.57079633])
118
+ >>> weyl_node_locations(m=4.0, t=1.0) is None
119
+ True
120
+ """
121
+ ratio = m / t - 2.0
122
+ if not (-1.0 < ratio < 1.0):
123
+ return None
124
+ k0 = float(np.arccos(ratio))
125
+ return np.array([-k0, k0])
126
+
127
+
128
+ def weyl_semimetal_slab_hamiltonian(ky: float, kz: float, n_layers: int, m: float, t: float = 1.0) -> np.ndarray:
129
+ r"""Slab Hamiltonian: periodic in ``y`` and ``z``, open (finite) along ``x``.
130
+
131
+ Truncating the ``x`` direction exposes two open surfaces whose surface
132
+ Brillouin zone is the :math:`(k_y, k_z)` plane the two Weyl nodes
133
+ project onto at :math:`(0, \pm k_0)`. Diagonalizing at fixed
134
+ :math:`k_z` and scanning :math:`k_y` reveals, for
135
+ :math:`|k_z| < k_0`, a single chiral mode crossing zero energy
136
+ (the Fermi arc), and a full gap for :math:`|k_z| > k_0`.
137
+
138
+ Parameters
139
+ ----------
140
+ ky, kz : float
141
+ Reduced crystal momenta, periodic on :math:`[0, 2\pi)`.
142
+ n_layers : int
143
+ Number of layers stacked along ``x``.
144
+ m : float
145
+ Band mass (see :func:`weyl_semimetal_hamiltonian`).
146
+ t : float, default=1.0
147
+ Hopping amplitude.
148
+
149
+ Returns
150
+ -------
151
+ ndarray, shape (2 * n_layers, 2 * n_layers)
152
+ Hermitian, open-boundary slab Hamiltonian.
153
+
154
+ Examples
155
+ --------
156
+ Between the two Weyl nodes (:math:`k_z=0`), a thick slab has a state
157
+ pinned near zero energy at some :math:`k_y` -- the Fermi-arc surface
158
+ mode -- absent outside the node range (:math:`k_z=\pi`):
159
+
160
+ >>> import numpy as np
161
+ >>> ky_grid = np.linspace(0, 2 * np.pi, 200, endpoint=False)
162
+ >>> gaps_inside = [np.min(np.abs(np.linalg.eigvalsh(weyl_semimetal_slab_hamiltonian(ky, 0.0, 40, m=2.0)))) for ky in ky_grid]
163
+ >>> bool(min(gaps_inside) < 1e-6)
164
+ True
165
+ >>> gaps_outside = [np.min(np.abs(np.linalg.eigvalsh(weyl_semimetal_slab_hamiltonian(ky, np.pi, 40, m=2.0)))) for ky in ky_grid]
166
+ >>> bool(min(gaps_outside) > 0.5)
167
+ True
168
+ """
169
+ mass_yz = m - t * (np.cos(ky) + np.cos(kz))
170
+ H0 = np.sin(ky) * _SIGMA_Y + mass_yz * _SIGMA_Z
171
+ Tx = -0.5j * _SIGMA_X - 0.5 * t * _SIGMA_Z
172
+
173
+ N = n_layers
174
+ H = np.zeros((2 * N, 2 * N), dtype=complex)
175
+ for layer in range(N):
176
+ H[2 * layer : 2 * layer + 2, 2 * layer : 2 * layer + 2] = H0
177
+ for layer in range(N - 1):
178
+ H[2 * layer : 2 * layer + 2, 2 * (layer + 1) : 2 * (layer + 1) + 2] = Tx
179
+ H[2 * (layer + 1) : 2 * (layer + 1) + 2, 2 * layer : 2 * layer + 2] = Tx.conj().T
180
+ return H