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.
- physicskit/__init__.py +51 -0
- physicskit/astro/__init__.py +66 -0
- physicskit/astro/cosmic_web.py +395 -0
- physicskit/astro/galactic_dynamics.py +137 -0
- physicskit/astro/nbody.py +208 -0
- physicskit/astro/orbital_mechanics.py +220 -0
- physicskit/astro/stellar_dynamo.py +628 -0
- physicskit/astro/stellar_structure.py +198 -0
- physicskit/astro/tests/__init__.py +0 -0
- physicskit/astro/tests/conftest.py +7 -0
- physicskit/astro/tests/test_cosmic_web.py +159 -0
- physicskit/astro/tests/test_galactic_dynamics.py +46 -0
- physicskit/astro/tests/test_nbody.py +81 -0
- physicskit/astro/tests/test_orbital_mechanics.py +73 -0
- physicskit/astro/tests/test_stellar_dynamo.py +198 -0
- physicskit/astro/tests/test_stellar_structure.py +52 -0
- physicskit/astro/tests/test_visualizers.py +159 -0
- physicskit/astro/visualizers.py +628 -0
- physicskit/chaos/__init__.py +55 -0
- physicskit/chaos/core/__init__.py +3 -0
- physicskit/chaos/core/base_system.py +342 -0
- physicskit/chaos/core/integrators.py +40 -0
- physicskit/chaos/exceptions.py +24 -0
- physicskit/chaos/quantum/__init__.py +38 -0
- physicskit/chaos/quantum/billiards.py +274 -0
- physicskit/chaos/quantum/husimi.py +85 -0
- physicskit/chaos/quantum/maps.py +366 -0
- physicskit/chaos/systems/__init__.py +38 -0
- physicskit/chaos/systems/billiards.py +1131 -0
- physicskit/chaos/systems/continuous.py +1276 -0
- physicskit/chaos/systems/maps.py +557 -0
- physicskit/chaos/tests/__init__.py +0 -0
- physicskit/chaos/tests/test_basins.py +76 -0
- physicskit/chaos/tests/test_bifurcation.py +132 -0
- physicskit/chaos/tests/test_billiards.py +115 -0
- physicskit/chaos/tests/test_continuous.py +224 -0
- physicskit/chaos/tests/test_dimension.py +69 -0
- physicskit/chaos/tests/test_divergence.py +90 -0
- physicskit/chaos/tests/test_dynamic_plots.py +269 -0
- physicskit/chaos/tests/test_integrators.py +96 -0
- physicskit/chaos/tests/test_io.py +41 -0
- physicskit/chaos/tests/test_maps.py +110 -0
- physicskit/chaos/tests/test_metrics.py +115 -0
- physicskit/chaos/tests/test_phase_space.py +73 -0
- physicskit/chaos/tests/test_properties.py +116 -0
- physicskit/chaos/tests/test_quantum_billiards.py +94 -0
- physicskit/chaos/tests/test_quantum_maps.py +144 -0
- physicskit/chaos/tests/test_recurrence.py +51 -0
- physicskit/chaos/tests/test_repr_and_api_consistency.py +134 -0
- physicskit/chaos/tests/test_section.py +49 -0
- physicskit/chaos/tests/test_spectral.py +48 -0
- physicskit/chaos/tests/test_streamlit_app.py +45 -0
- physicskit/chaos/tests/test_timeseries.py +131 -0
- physicskit/chaos/tests/test_viewer3d.py +41 -0
- physicskit/chaos/utils/__init__.py +46 -0
- physicskit/chaos/utils/dimension.py +139 -0
- physicskit/chaos/utils/io.py +95 -0
- physicskit/chaos/utils/metrics.py +304 -0
- physicskit/chaos/utils/recurrence.py +122 -0
- physicskit/chaos/utils/spectral.py +69 -0
- physicskit/chaos/utils/timeseries.py +303 -0
- physicskit/chaos/visualizers/__init__.py +85 -0
- physicskit/chaos/visualizers/basins.py +185 -0
- physicskit/chaos/visualizers/bifurcation.py +273 -0
- physicskit/chaos/visualizers/divergence.py +374 -0
- physicskit/chaos/visualizers/dynamic_plots.py +1372 -0
- physicskit/chaos/visualizers/phase_space.py +133 -0
- physicskit/chaos/visualizers/quantum.py +299 -0
- physicskit/chaos/visualizers/recurrence.py +91 -0
- physicskit/chaos/visualizers/section.py +161 -0
- physicskit/chaos/visualizers/theme.py +31 -0
- physicskit/chaos/visualizers/viewer3d.py +82 -0
- physicskit/classical/__init__.py +55 -0
- physicskit/classical/core/__init__.py +17 -0
- physicskit/classical/core/base_system.py +510 -0
- physicskit/classical/core/integrators.py +397 -0
- physicskit/classical/systems/__init__.py +32 -0
- physicskit/classical/systems/chains.py +334 -0
- physicskit/classical/systems/hamiltonian.py +215 -0
- physicskit/classical/systems/lagrangian.py +308 -0
- physicskit/classical/systems/newtonian.py +536 -0
- physicskit/classical/systems/rotations.py +614 -0
- physicskit/classical/tests/__init__.py +0 -0
- physicskit/classical/tests/conftest.py +7 -0
- physicskit/classical/tests/test_base_system.py +113 -0
- physicskit/classical/tests/test_chains.py +84 -0
- physicskit/classical/tests/test_conservation.py +244 -0
- physicskit/classical/tests/test_conservation_utils.py +47 -0
- physicskit/classical/tests/test_hamiltonian.py +44 -0
- physicskit/classical/tests/test_integrators.py +123 -0
- physicskit/classical/tests/test_lagrangian.py +69 -0
- physicskit/classical/tests/test_newtonian.py +45 -0
- physicskit/classical/tests/test_rotations.py +160 -0
- physicskit/classical/tests/test_stepsize.py +149 -0
- physicskit/classical/tests/test_symbolic.py +125 -0
- physicskit/classical/tests/test_visualizers.py +172 -0
- physicskit/classical/utils/__init__.py +20 -0
- physicskit/classical/utils/conservation.py +126 -0
- physicskit/classical/utils/stepsize.py +187 -0
- physicskit/classical/utils/symbolic.py +235 -0
- physicskit/classical/visualizers/__init__.py +25 -0
- physicskit/classical/visualizers/animations.py +508 -0
- physicskit/classical/visualizers/interactive.py +113 -0
- physicskit/classical/visualizers/modal_analysis.py +97 -0
- physicskit/classical/visualizers/phase_space.py +214 -0
- physicskit/condensed/__init__.py +122 -0
- physicskit/condensed/anderson_localization.py +155 -0
- physicskit/condensed/correlated.py +284 -0
- physicskit/condensed/ginzburg_landau.py +220 -0
- physicskit/condensed/landau_levels.py +246 -0
- physicskit/condensed/laughlin.py +229 -0
- physicskit/condensed/models.py +627 -0
- physicskit/condensed/tests/__init__.py +0 -0
- physicskit/condensed/tests/test_condensed.py +518 -0
- physicskit/condensed/tests/test_visualizers.py +87 -0
- physicskit/condensed/tight_binding.py +445 -0
- physicskit/condensed/topological_insulator_3d.py +178 -0
- physicskit/condensed/topology.py +217 -0
- physicskit/condensed/visualizers.py +296 -0
- physicskit/condensed/weyl.py +180 -0
- physicskit/constants.py +184 -0
- physicskit/fields/__init__.py +111 -0
- physicskit/fields/electrodynamics.py +671 -0
- physicskit/fields/quantum_fields.py +510 -0
- physicskit/fields/solitons.py +527 -0
- physicskit/fields/tests/__init__.py +0 -0
- physicskit/fields/tests/conftest.py +7 -0
- physicskit/fields/tests/test_field_animations.py +154 -0
- physicskit/fields/tests/test_fields.py +439 -0
- physicskit/fields/tests/test_visualizers.py +101 -0
- physicskit/fields/visualizers.py +503 -0
- physicskit/fluids/__init__.py +134 -0
- physicskit/fluids/core/__init__.py +23 -0
- physicskit/fluids/core/grid.py +165 -0
- physicskit/fluids/core/timestepping.py +231 -0
- physicskit/fluids/exceptions.py +26 -0
- physicskit/fluids/systems/__init__.py +70 -0
- physicskit/fluids/systems/compressible_flow.py +281 -0
- physicskit/fluids/systems/instabilities.py +343 -0
- physicskit/fluids/systems/navier_stokes.py +221 -0
- physicskit/fluids/systems/potential_flow.py +440 -0
- physicskit/fluids/systems/viscous_flow.py +425 -0
- physicskit/fluids/systems/vortex_dynamics.py +304 -0
- physicskit/fluids/tests/__init__.py +0 -0
- physicskit/fluids/tests/conftest.py +7 -0
- physicskit/fluids/tests/test_compressible_flow.py +66 -0
- physicskit/fluids/tests/test_instabilities.py +115 -0
- physicskit/fluids/tests/test_navier_stokes.py +67 -0
- physicskit/fluids/tests/test_potential_flow.py +92 -0
- physicskit/fluids/tests/test_static_visualizers.py +91 -0
- physicskit/fluids/tests/test_utils.py +100 -0
- physicskit/fluids/tests/test_viscous_flow.py +110 -0
- physicskit/fluids/tests/test_visualizers.py +34 -0
- physicskit/fluids/tests/test_vortex_dynamics.py +88 -0
- physicskit/fluids/utils/__init__.py +18 -0
- physicskit/fluids/utils/dimensionless.py +239 -0
- physicskit/fluids/utils/spectral_analysis.py +142 -0
- physicskit/fluids/visualizers/__init__.py +14 -0
- physicskit/fluids/visualizers/compressible.py +39 -0
- physicskit/fluids/visualizers/flow_fields.py +252 -0
- physicskit/fluids/visualizers/potential_flow.py +51 -0
- physicskit/fluids/visualizers/spectra.py +62 -0
- physicskit/fluids/visualizers/theme.py +38 -0
- physicskit/integrators/__init__.py +52 -0
- physicskit/integrators/adaptive.py +199 -0
- physicskit/integrators/fixed_step.py +360 -0
- physicskit/integrators/tests/__init__.py +0 -0
- physicskit/integrators/tests/test_integrators.py +101 -0
- physicskit/optics/__init__.py +124 -0
- physicskit/optics/_compat.py +5 -0
- physicskit/optics/gaussian.py +382 -0
- physicskit/optics/quantum_optics.py +428 -0
- physicskit/optics/ray.py +469 -0
- physicskit/optics/tests/__init__.py +0 -0
- physicskit/optics/tests/test_diffraction_animation.py +38 -0
- physicskit/optics/tests/test_gaussian.py +170 -0
- physicskit/optics/tests/test_quantum_optics.py +147 -0
- physicskit/optics/tests/test_ray.py +177 -0
- physicskit/optics/tests/test_visualizers.py +58 -0
- physicskit/optics/tests/test_wave.py +146 -0
- physicskit/optics/visualizers.py +264 -0
- physicskit/optics/wave.py +365 -0
- physicskit/particle/__init__.py +152 -0
- physicskit/particle/collider.py +382 -0
- physicskit/particle/confinement.py +125 -0
- physicskit/particle/decays.py +357 -0
- physicskit/particle/electroweak.py +300 -0
- physicskit/particle/kinematics.py +271 -0
- physicskit/particle/neutrinos.py +84 -0
- physicskit/particle/nuclear.py +100 -0
- physicskit/particle/scattering.py +159 -0
- physicskit/particle/tests/__init__.py +0 -0
- physicskit/particle/tests/conftest.py +7 -0
- physicskit/particle/tests/test_collider.py +119 -0
- physicskit/particle/tests/test_confinement.py +42 -0
- physicskit/particle/tests/test_decays.py +112 -0
- physicskit/particle/tests/test_electroweak.py +97 -0
- physicskit/particle/tests/test_kinematics.py +138 -0
- physicskit/particle/tests/test_neutrinos.py +36 -0
- physicskit/particle/tests/test_nuclear.py +45 -0
- physicskit/particle/tests/test_scattering.py +64 -0
- physicskit/particle/tests/test_visualizers.py +214 -0
- physicskit/particle/visualizers/__init__.py +38 -0
- physicskit/particle/visualizers/animations.py +705 -0
- physicskit/particle/visualizers/static.py +101 -0
- physicskit/plasma/__init__.py +176 -0
- physicskit/plasma/acceleration.py +152 -0
- physicskit/plasma/instabilities.py +417 -0
- physicskit/plasma/kinetic.py +588 -0
- physicskit/plasma/mhd.py +463 -0
- physicskit/plasma/single_particle.py +562 -0
- physicskit/plasma/tests/__init__.py +0 -0
- physicskit/plasma/tests/conftest.py +7 -0
- physicskit/plasma/tests/test_new_time_domain_features.py +222 -0
- physicskit/plasma/tests/test_plasma.py +232 -0
- physicskit/plasma/tests/test_visualizers.py +79 -0
- physicskit/plasma/turbulence.py +219 -0
- physicskit/plasma/visualizers.py +868 -0
- physicskit/plasma/waves.py +549 -0
- physicskit/quantum/__init__.py +180 -0
- physicskit/quantum/_compat.py +20 -0
- physicskit/quantum/chapters/__init__.py +0 -0
- physicskit/quantum/chapters/entanglement.py +489 -0
- physicskit/quantum/chapters/harmonic_spin.py +517 -0
- physicskit/quantum/chapters/hydrogen_am.py +292 -0
- physicskit/quantum/chapters/perturbation.py +350 -0
- physicskit/quantum/chapters/potentials.py +997 -0
- physicskit/quantum/chapters/spin.py +306 -0
- physicskit/quantum/chapters/wave_packets.py +541 -0
- physicskit/quantum/core/__init__.py +0 -0
- physicskit/quantum/core/eigensolvers.py +311 -0
- physicskit/quantum/core/operators.py +296 -0
- physicskit/quantum/core/solvers.py +271 -0
- physicskit/quantum/tests/__init__.py +0 -0
- physicskit/quantum/tests/conftest.py +7 -0
- physicskit/quantum/tests/test_animations.py +225 -0
- physicskit/quantum/tests/test_compat.py +43 -0
- physicskit/quantum/tests/test_eigensolvers.py +24 -0
- physicskit/quantum/tests/test_entanglement.py +127 -0
- physicskit/quantum/tests/test_harmonic_spin.py +140 -0
- physicskit/quantum/tests/test_hydrogen_am.py +48 -0
- physicskit/quantum/tests/test_measure.py +110 -0
- physicskit/quantum/tests/test_operators.py +105 -0
- physicskit/quantum/tests/test_perturbation.py +112 -0
- physicskit/quantum/tests/test_physics_checks.py +131 -0
- physicskit/quantum/tests/test_potentials.py +191 -0
- physicskit/quantum/tests/test_solvers.py +70 -0
- physicskit/quantum/tests/test_spin.py +22 -0
- physicskit/quantum/tests/test_unitarity.py +84 -0
- physicskit/quantum/tests/test_wave_packets.py +53 -0
- physicskit/quantum/utils/__init__.py +0 -0
- physicskit/quantum/utils/measure.py +253 -0
- physicskit/quantum/visualizers/__init__.py +0 -0
- physicskit/quantum/visualizers/bloch_sphere.py +205 -0
- physicskit/quantum/visualizers/entanglement.py +58 -0
- physicskit/quantum/visualizers/orbitals.py +187 -0
- physicskit/quantum/visualizers/phase_space.py +179 -0
- physicskit/quantum/visualizers/wavefunctions.py +230 -0
- physicskit/relativity/__init__.py +61 -0
- physicskit/relativity/chapters/__init__.py +33 -0
- physicskit/relativity/chapters/cosmology.py +190 -0
- physicskit/relativity/chapters/gw_merger.py +399 -0
- physicskit/relativity/chapters/kerr.py +371 -0
- physicskit/relativity/chapters/lensing.py +196 -0
- physicskit/relativity/chapters/neutron_star.py +149 -0
- physicskit/relativity/chapters/schwarzschild.py +412 -0
- physicskit/relativity/chapters/timekeeping.py +133 -0
- physicskit/relativity/core/__init__.py +12 -0
- physicskit/relativity/core/geodesics.py +216 -0
- physicskit/relativity/core/kerr_raytracer.py +259 -0
- physicskit/relativity/core/raytracer.py +241 -0
- physicskit/relativity/core/tensors.py +468 -0
- physicskit/relativity/tests/__init__.py +0 -0
- physicskit/relativity/tests/test_conservations.py +54 -0
- physicskit/relativity/tests/test_constants.py +34 -0
- physicskit/relativity/tests/test_cosmology.py +61 -0
- physicskit/relativity/tests/test_gw_merger.py +117 -0
- physicskit/relativity/tests/test_kerr.py +116 -0
- physicskit/relativity/tests/test_kerr_raytracer.py +103 -0
- physicskit/relativity/tests/test_lensing.py +75 -0
- physicskit/relativity/tests/test_neutron_star.py +48 -0
- physicskit/relativity/tests/test_raytracer.py +67 -0
- physicskit/relativity/tests/test_schwarzschild.py +126 -0
- physicskit/relativity/tests/test_shadow_render.py +81 -0
- physicskit/relativity/tests/test_tensors.py +86 -0
- physicskit/relativity/tests/test_timekeeping.py +51 -0
- physicskit/relativity/tests/test_visualizers_misc.py +115 -0
- physicskit/relativity/utils/__init__.py +1 -0
- physicskit/relativity/utils/constants.py +232 -0
- physicskit/relativity/visualizers/__init__.py +46 -0
- physicskit/relativity/visualizers/interactive.py +127 -0
- physicskit/relativity/visualizers/shadow_render.py +367 -0
- physicskit/relativity/visualizers/spacetime_3d.py +92 -0
- physicskit/relativity/visualizers/spacetime_diagrams.py +198 -0
- physicskit/relativity/visualizers/wave_plots.py +185 -0
- physicskit/rmt/__init__.py +8 -0
- physicskit/rmt/ensembles/__init__.py +108 -0
- physicskit/rmt/ensembles/banded.py +114 -0
- physicskit/rmt/ensembles/base.py +135 -0
- physicskit/rmt/ensembles/bdg.py +218 -0
- physicskit/rmt/ensembles/chiral.py +308 -0
- physicskit/rmt/ensembles/circular.py +104 -0
- physicskit/rmt/ensembles/crossover.py +82 -0
- physicskit/rmt/ensembles/density_matrix.py +148 -0
- physicskit/rmt/ensembles/effective_hamiltonian.py +230 -0
- physicskit/rmt/ensembles/embedded.py +207 -0
- physicskit/rmt/ensembles/gaussian.py +153 -0
- physicskit/rmt/ensembles/ginibre.py +110 -0
- physicskit/rmt/ensembles/girko.py +190 -0
- physicskit/rmt/ensembles/graph_laplacian.py +92 -0
- physicskit/rmt/ensembles/haar.py +57 -0
- physicskit/rmt/ensembles/jacobi.py +182 -0
- physicskit/rmt/ensembles/poisson.py +77 -0
- physicskit/rmt/ensembles/polynomial.py +139 -0
- physicskit/rmt/ensembles/pt_symmetric.py +120 -0
- physicskit/rmt/ensembles/single_ring.py +170 -0
- physicskit/rmt/ensembles/sparse.py +95 -0
- physicskit/rmt/ensembles/syk.py +170 -0
- physicskit/rmt/ensembles/truncated_unitary.py +80 -0
- physicskit/rmt/ensembles/universality.py +92 -0
- physicskit/rmt/ensembles/wishart.py +88 -0
- physicskit/rmt/py.typed +0 -0
- physicskit/rmt/spectrum.py +82 -0
- physicskit/rmt/stats/__init__.py +160 -0
- physicskit/rmt/stats/characteristic_polynomial.py +77 -0
- physicskit/rmt/stats/circular_law.py +54 -0
- physicskit/rmt/stats/correlations.py +162 -0
- physicskit/rmt/stats/density.py +70 -0
- physicskit/rmt/stats/entanglement.py +36 -0
- physicskit/rmt/stats/free_probability.py +202 -0
- physicskit/rmt/stats/localization.py +338 -0
- physicskit/rmt/stats/marchenko_pastur.py +55 -0
- physicskit/rmt/stats/pt_symmetric.py +265 -0
- physicskit/rmt/stats/ratios.py +110 -0
- physicskit/rmt/stats/real_ginibre.py +134 -0
- physicskit/rmt/stats/rigidity.py +272 -0
- physicskit/rmt/stats/single_ring.py +95 -0
- physicskit/rmt/stats/spacing.py +150 -0
- physicskit/rmt/stats/tracy_widom.py +175 -0
- physicskit/rmt/stats/truncated_unitary.py +40 -0
- physicskit/rmt/stats/unfolding.py +37 -0
- physicskit/rmt/stats/wachter.py +67 -0
- physicskit/rmt/tests/__init__.py +0 -0
- physicskit/rmt/tests/cache_utils.py +107 -0
- physicskit/rmt/tests/conftest.py +8 -0
- physicskit/rmt/tests/test_banded.py +86 -0
- physicskit/rmt/tests/test_base.py +29 -0
- physicskit/rmt/tests/test_bdg.py +133 -0
- physicskit/rmt/tests/test_characteristic_polynomial.py +50 -0
- physicskit/rmt/tests/test_chiral.py +273 -0
- physicskit/rmt/tests/test_circular.py +225 -0
- physicskit/rmt/tests/test_crossover.py +72 -0
- physicskit/rmt/tests/test_density.py +23 -0
- physicskit/rmt/tests/test_density_matrix.py +181 -0
- physicskit/rmt/tests/test_effective_hamiltonian.py +140 -0
- physicskit/rmt/tests/test_embedded.py +169 -0
- physicskit/rmt/tests/test_free_probability.py +81 -0
- physicskit/rmt/tests/test_gaussian_ensembles.py +22 -0
- physicskit/rmt/tests/test_gaussian_semicircle.py +127 -0
- physicskit/rmt/tests/test_ginibre_circular_law.py +131 -0
- physicskit/rmt/tests/test_girko.py +178 -0
- physicskit/rmt/tests/test_graph_laplacian.py +102 -0
- physicskit/rmt/tests/test_haar.py +118 -0
- physicskit/rmt/tests/test_jacobi_wachter.py +136 -0
- physicskit/rmt/tests/test_localization.py +240 -0
- physicskit/rmt/tests/test_poisson.py +149 -0
- physicskit/rmt/tests/test_polynomial.py +107 -0
- physicskit/rmt/tests/test_pt_symmetric.py +178 -0
- physicskit/rmt/tests/test_random_state.py +19 -0
- physicskit/rmt/tests/test_real_ginibre.py +112 -0
- physicskit/rmt/tests/test_rigidity_universality.py +167 -0
- physicskit/rmt/tests/test_single_ring.py +132 -0
- physicskit/rmt/tests/test_spacing_and_ratios.py +122 -0
- physicskit/rmt/tests/test_sparse.py +71 -0
- physicskit/rmt/tests/test_spectrum.py +27 -0
- physicskit/rmt/tests/test_syk.py +136 -0
- physicskit/rmt/tests/test_tracy_widom.py +113 -0
- physicskit/rmt/tests/test_tridiagonal.py +41 -0
- physicskit/rmt/tests/test_truncated_unitary.py +80 -0
- physicskit/rmt/tests/test_validation_base.py +25 -0
- physicskit/rmt/tests/test_validation_misc.py +67 -0
- physicskit/rmt/tests/test_wishart_marchenko_pastur.py +120 -0
- physicskit/rmt/utils/__init__.py +0 -0
- physicskit/rmt/utils/haar.py +128 -0
- physicskit/rmt/utils/random_state.py +24 -0
- physicskit/rmt/utils/tridiagonal.py +167 -0
- physicskit/rmt/validation/__init__.py +36 -0
- physicskit/rmt/validation/base.py +126 -0
- physicskit/rmt/validation/circular_law.py +80 -0
- physicskit/rmt/validation/marchenko_pastur.py +53 -0
- physicskit/rmt/validation/ratio_distribution.py +53 -0
- physicskit/rmt/validation/real_ginibre.py +60 -0
- physicskit/rmt/validation/sine_kernel.py +57 -0
- physicskit/rmt/validation/single_ring.py +68 -0
- physicskit/rmt/validation/tracy_widom.py +89 -0
- physicskit/rmt/validation/universality.py +100 -0
- physicskit/rmt/validation/wachter.py +52 -0
- physicskit/rmt/validation/wigner_semicircle.py +40 -0
- physicskit/rmt/validation/wigner_surmise.py +58 -0
- physicskit/semiclassical/__init__.py +94 -0
- physicskit/semiclassical/_compat.py +5 -0
- physicskit/semiclassical/core/__init__.py +41 -0
- physicskit/semiclassical/core/gutzwiller.py +215 -0
- physicskit/semiclassical/core/path_integral.py +594 -0
- physicskit/semiclassical/core/propagators.py +579 -0
- physicskit/semiclassical/core/wkb.py +308 -0
- physicskit/semiclassical/systems/__init__.py +13 -0
- physicskit/semiclassical/systems/scarring.py +278 -0
- physicskit/semiclassical/tests/__init__.py +0 -0
- physicskit/semiclassical/tests/test_gutzwiller.py +35 -0
- physicskit/semiclassical/tests/test_path_integral.py +194 -0
- physicskit/semiclassical/tests/test_propagators.py +82 -0
- physicskit/semiclassical/tests/test_scarring.py +43 -0
- physicskit/semiclassical/tests/test_visualizers.py +89 -0
- physicskit/semiclassical/tests/test_wkb.py +30 -0
- physicskit/semiclassical/visualizers/__init__.py +17 -0
- physicskit/semiclassical/visualizers/gutzwiller.py +55 -0
- physicskit/semiclassical/visualizers/path_integral.py +195 -0
- physicskit/semiclassical/visualizers/propagators.py +89 -0
- physicskit/semiclassical/visualizers/scarring.py +146 -0
- physicskit/semiclassical/visualizers/wkb.py +55 -0
- physicskit/statphys/__init__.py +80 -0
- physicskit/statphys/chapters/__init__.py +43 -0
- physicskit/statphys/chapters/ehrenfest_urn.py +112 -0
- physicskit/statphys/chapters/ising_lattice.py +431 -0
- physicskit/statphys/chapters/kpz_growth.py +129 -0
- physicskit/statphys/chapters/molecular_dynamics.py +258 -0
- physicskit/statphys/chapters/nonequilibrium_work.py +146 -0
- physicskit/statphys/chapters/percolation.py +305 -0
- physicskit/statphys/chapters/random_walk.py +142 -0
- physicskit/statphys/chapters/renormalization.py +148 -0
- physicskit/statphys/chapters/sandpile.py +109 -0
- physicskit/statphys/chapters/spin_glass.py +275 -0
- physicskit/statphys/core/__init__.py +10 -0
- physicskit/statphys/core/kpz_engine.py +53 -0
- physicskit/statphys/core/md_engine.py +157 -0
- physicskit/statphys/core/monte_carlo.py +462 -0
- physicskit/statphys/core/random_walk_engine.py +68 -0
- physicskit/statphys/core/sandpile_engine.py +52 -0
- physicskit/statphys/tests/__init__.py +0 -0
- physicskit/statphys/tests/test_dynamics.py +66 -0
- physicskit/statphys/tests/test_ehrenfest_urn.py +44 -0
- physicskit/statphys/tests/test_finite_size_scaling.py +62 -0
- physicskit/statphys/tests/test_interactive.py +33 -0
- physicskit/statphys/tests/test_ising.py +68 -0
- physicskit/statphys/tests/test_kpz.py +55 -0
- physicskit/statphys/tests/test_landau_theory.py +49 -0
- physicskit/statphys/tests/test_md_engine.py +31 -0
- physicskit/statphys/tests/test_molecular_dynamics.py +72 -0
- physicskit/statphys/tests/test_nonequilibrium_work.py +33 -0
- physicskit/statphys/tests/test_partition_function.py +26 -0
- physicskit/statphys/tests/test_percolation.py +116 -0
- physicskit/statphys/tests/test_potts_model.py +46 -0
- physicskit/statphys/tests/test_random_walk.py +50 -0
- physicskit/statphys/tests/test_renormalization.py +44 -0
- physicskit/statphys/tests/test_sandpile.py +44 -0
- physicskit/statphys/tests/test_spin_glass.py +73 -0
- physicskit/statphys/tests/test_thermodynamics.py +121 -0
- physicskit/statphys/tests/test_xy_model.py +45 -0
- physicskit/statphys/utils/__init__.py +1 -0
- physicskit/statphys/utils/dynamics.py +100 -0
- physicskit/statphys/utils/finite_size_scaling.py +171 -0
- physicskit/statphys/utils/landau_theory.py +151 -0
- physicskit/statphys/utils/partition_function.py +109 -0
- physicskit/statphys/utils/thermodynamics.py +356 -0
- physicskit/statphys/visualizers/__init__.py +87 -0
- physicskit/statphys/visualizers/interactive.py +161 -0
- physicskit/statphys/visualizers/jarzynski_render.py +44 -0
- physicskit/statphys/visualizers/kpz_render.py +65 -0
- physicskit/statphys/visualizers/lattice_render.py +212 -0
- physicskit/statphys/visualizers/particle_render.py +121 -0
- physicskit/statphys/visualizers/random_walk_render.py +106 -0
- physicskit/statphys/visualizers/rg_render.py +45 -0
- physicskit/statphys/visualizers/sandpile_render.py +65 -0
- physicskit/statphys/visualizers/spin_glass_render.py +40 -0
- physicskit/statphys/visualizers/urn_render.py +38 -0
- physicskit/statphys/visualizers/vortex_render.py +84 -0
- physicskit/tests/__init__.py +0 -0
- physicskit/tests/test_constants.py +38 -0
- physicskit-0.1.0.dist-info/METADATA +196 -0
- physicskit-0.1.0.dist-info/RECORD +484 -0
- physicskit-0.1.0.dist-info/WHEEL +5 -0
- physicskit-0.1.0.dist-info/licenses/LICENSE +21 -0
- 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
|