lfm-physics 0.2.2__tar.gz → 0.4.0__tar.gz
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.
- lfm_physics-0.4.0/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- lfm_physics-0.4.0/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
- lfm_physics-0.4.0/.github/PULL_REQUEST_TEMPLATE.md +19 -0
- lfm_physics-0.4.0/.pre-commit-config.yaml +20 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/CHANGELOG.md +41 -0
- lfm_physics-0.4.0/CODE_OF_CONDUCT.md +31 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/PKG-INFO +51 -1
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/README.md +50 -0
- lfm_physics-0.4.0/SECURITY.md +21 -0
- lfm_physics-0.4.0/docs/Makefile +23 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/conf.py +1 -1
- lfm_physics-0.4.0/docs/make.bat +26 -0
- lfm_physics-0.4.0/docs/primer.md +117 -0
- lfm_physics-0.4.0/docs/troubleshooting.md +159 -0
- lfm_physics-0.4.0/examples/15_visualization.py +93 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/__init__.py +42 -1
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/analysis/__init__.py +40 -0
- lfm_physics-0.4.0/lfm/analysis/angular_momentum.py +146 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/analysis/color.py +2 -1
- lfm_physics-0.4.0/lfm/analysis/metric.py +148 -0
- lfm_physics-0.4.0/lfm/analysis/phase.py +138 -0
- lfm_physics-0.4.0/lfm/analysis/spectrum.py +57 -0
- lfm_physics-0.4.0/lfm/analysis/tracker.py +80 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/core/backends/kernel_source.py +13 -8
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/fields/__init__.py +2 -0
- lfm_physics-0.4.0/lfm/fields/boosted.py +107 -0
- lfm_physics-0.4.0/lfm/sweep.py +155 -0
- lfm_physics-0.4.0/lfm/viz/__init__.py +42 -0
- lfm_physics-0.4.0/lfm/viz/_util.py +14 -0
- lfm_physics-0.4.0/lfm/viz/evolution.py +118 -0
- lfm_physics-0.4.0/lfm/viz/fields.py +78 -0
- lfm_physics-0.4.0/lfm/viz/radial.py +87 -0
- lfm_physics-0.4.0/lfm/viz/slices.py +150 -0
- lfm_physics-0.4.0/lfm/viz/spectrum.py +71 -0
- lfm_physics-0.4.0/lfm/viz/sweep.py +60 -0
- lfm_physics-0.4.0/lfm/viz/tracker.py +75 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/pyproject.toml +16 -1
- lfm_physics-0.4.0/tests/test_coverage_boost.py +304 -0
- lfm_physics-0.4.0/tests/test_edge_cases.py +154 -0
- lfm_physics-0.4.0/tests/test_integration.py +208 -0
- lfm_physics-0.4.0/tests/test_physics_modules.py +275 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/.github/workflows/publish.yml +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/.github/workflows/test.yml +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/.gitignore +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/.readthedocs.yaml +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/CONTRIBUTING.md +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/LICENSE +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/benchmarks/README.md +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/benchmarks/bench_evolver.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/benchmarks/bench_fields.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/api/analysis.rst +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/api/config.rst +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/api/constants.rst +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/api/core.rst +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/api/fields.rst +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/api/io.rst +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/api/simulation.rst +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/api/units.rst +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/changelog.rst +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/contributing.rst +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/examples.md +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/index.rst +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/installation.md +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/quickstart.md +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/docs/requirements.txt +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/01_empty_space.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/02_first_particle.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/03_measuring_gravity.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/04_two_bodies.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/05_electric_charge.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/06_dark_matter.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/07_matter_creation.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/08_universe.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/09_hydrogen_atom.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/10_hydrogen_molecule.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/11_oxygen.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/12_fluid_dynamics.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/13_weak_force.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/examples/14_strong_force.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/analysis/energy.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/analysis/metrics.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/analysis/observables.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/analysis/structure.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/config.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/constants.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/core/__init__.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/core/backends/__init__.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/core/backends/cupy_backend.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/core/backends/numpy_backend.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/core/backends/protocol.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/core/evolver.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/core/integrator.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/core/stencils.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/fields/arrangements.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/fields/equilibrium.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/fields/random.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/fields/soliton.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/io/__init__.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/py.typed +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/simulation.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/lfm/units.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/paper_experiments/why_is_c_what_it_is.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tests/__init__.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tests/conftest.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tests/test_analysis.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tests/test_backends.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tests/test_config.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tests/test_constants.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tests/test_evolver.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tests/test_fields.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tests/test_integrator.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tests/test_simulation.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tests/test_stencils.py +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tutorial_03_3d_lattice.png +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tutorial_07_3d_lattice.png +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tutorial_08_3d_lattice.png +0 -0
- {lfm_physics-0.2.2 → lfm_physics-0.4.0}/tutorial_12_3d_lattice.png +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug Report
|
|
3
|
+
about: Report a bug in lfm-physics
|
|
4
|
+
title: "[BUG] "
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ""
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Describe the bug**
|
|
10
|
+
A clear description of what the bug is.
|
|
11
|
+
|
|
12
|
+
**To Reproduce**
|
|
13
|
+
```python
|
|
14
|
+
import lfm
|
|
15
|
+
|
|
16
|
+
config = lfm.SimulationConfig(grid_size=64)
|
|
17
|
+
sim = lfm.Simulation(config)
|
|
18
|
+
# ... steps to reproduce
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Expected behavior**
|
|
22
|
+
What you expected to happen.
|
|
23
|
+
|
|
24
|
+
**Environment**
|
|
25
|
+
- OS: [e.g. Windows 11, Ubuntu 22.04]
|
|
26
|
+
- Python: [e.g. 3.12]
|
|
27
|
+
- lfm-physics version: [e.g. 0.3.0]
|
|
28
|
+
- GPU (if applicable): [e.g. RTX 4060]
|
|
29
|
+
- CuPy version (if applicable): [e.g. 13.0]
|
|
30
|
+
|
|
31
|
+
**Additional context**
|
|
32
|
+
Any other context — stack traces, screenshots, etc.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature Request
|
|
3
|
+
about: Suggest a new physics module or enhancement
|
|
4
|
+
title: "[FEATURE] "
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: ""
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**What physics / feature is missing?**
|
|
10
|
+
Describe the capability you need.
|
|
11
|
+
|
|
12
|
+
**Use case**
|
|
13
|
+
What simulation or analysis would this enable?
|
|
14
|
+
|
|
15
|
+
**Proposed API**
|
|
16
|
+
```python
|
|
17
|
+
import lfm
|
|
18
|
+
|
|
19
|
+
# How you'd like to use it:
|
|
20
|
+
result = lfm.some_new_function(...)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**References**
|
|
24
|
+
Links to relevant LFM papers, equations, or external references.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
Brief description of the change and why it's needed.
|
|
4
|
+
|
|
5
|
+
## Changes
|
|
6
|
+
|
|
7
|
+
-
|
|
8
|
+
|
|
9
|
+
## Testing
|
|
10
|
+
|
|
11
|
+
- [ ] All existing tests pass (`pytest tests/`)
|
|
12
|
+
- [ ] New tests added for new functionality
|
|
13
|
+
- [ ] Tested with GPU backend (if kernel changes)
|
|
14
|
+
|
|
15
|
+
## Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Code follows project style (run `ruff check`)
|
|
18
|
+
- [ ] Docstrings added for public functions
|
|
19
|
+
- [ ] CHANGELOG.md updated
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Pre-commit hooks for lfm-physics
|
|
2
|
+
# Install: pip install pre-commit && pre-commit install
|
|
3
|
+
# Run all: pre-commit run --all-files
|
|
4
|
+
repos:
|
|
5
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
6
|
+
rev: v4.6.0
|
|
7
|
+
hooks:
|
|
8
|
+
- id: trailing-whitespace
|
|
9
|
+
- id: end-of-file-fixer
|
|
10
|
+
- id: check-yaml
|
|
11
|
+
- id: check-toml
|
|
12
|
+
- id: check-merge-conflict
|
|
13
|
+
- id: debug-statements
|
|
14
|
+
|
|
15
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
16
|
+
rev: v0.4.8
|
|
17
|
+
hooks:
|
|
18
|
+
- id: ruff # lint
|
|
19
|
+
args: [--fix]
|
|
20
|
+
- id: ruff-format # format
|
|
@@ -4,6 +4,47 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
6
6
|
|
|
7
|
+
## [0.4.0] - 2026-03-22
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Metric analysis** (`lfm.analysis.metric`): `effective_metric_00`, `metric_perturbation`, `time_dilation_factor`, `gravitational_potential`, `schwarzschild_chi` — extract spacetime geometry from χ field
|
|
11
|
+
- **Phase/charge analysis** (`lfm.analysis.phase`): `phase_field`, `charge_density`, `phase_coherence`, `coulomb_interaction_energy` — electromagnetic observables from complex fields
|
|
12
|
+
- **Angular momentum** (`lfm.analysis.angular_momentum`): `angular_momentum_density`, `total_angular_momentum`, `precession_rate` — orbital and spin analysis
|
|
13
|
+
- **Boosted solitons** (`lfm.fields.boosted`): `boosted_soliton` — momentum-encoded solitons with phase gradient (complex) or time-derivative kick (real) for scattering experiments
|
|
14
|
+
- **2D parameter sweeps** (`lfm.sweep`): `sweep_2d()` — run all (v1, v2) combinations and collect metrics
|
|
15
|
+
- **GitHub governance**: issue/PR templates, SECURITY.md, CODE_OF_CONDUCT.md
|
|
16
|
+
- **Pre-commit hooks**: `.pre-commit-config.yaml` with ruff linting and formatting
|
|
17
|
+
- **Docs build**: `docs/Makefile` and `docs/make.bat` for local Sphinx builds
|
|
18
|
+
- **Coverage config**: `pyproject.toml` [tool.coverage.*] sections (excluding viz/ and kernel_source.py)
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- **GPU NaN bug**: CUDA color kernel threshold mismatch (`psi_sq_total > 1e-30f` → `total_sq > 1e-30f`) that caused FTZ underflow to 0/0=NaN
|
|
22
|
+
- **GPU boundary masking**: Added missing Psi boundary masking in color CUDA kernel
|
|
23
|
+
- **Color variance RuntimeWarning**: Safe denominator pattern to avoid division-by-zero warning on zero-field input
|
|
24
|
+
- **Schwarzschild chi RuntimeWarning**: Compute `np.where(r > r_s, 1.0 - r_s/r, 0.0)` before `np.sqrt` to avoid invalid-value warning
|
|
25
|
+
|
|
26
|
+
### Improved
|
|
27
|
+
- Test suite: 202 → **307 tests** (all passing)
|
|
28
|
+
- Coverage: 64% → **91%** (excluding viz/ and CUDA kernel strings)
|
|
29
|
+
- Docs version: aligned at 0.4.0 across pyproject.toml, lfm/__init__.py, docs/conf.py
|
|
30
|
+
|
|
31
|
+
## [0.3.0] - 2026-03-21
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- **Visualisation module** (`lfm.viz`): 10 plotting functions for rapid exploration
|
|
35
|
+
- `plot_slice`, `plot_three_slices`, `plot_chi_histogram` — 2D field slices
|
|
36
|
+
- `plot_evolution`, `plot_energy_components` — time-series dashboards
|
|
37
|
+
- `plot_radial_profile` — χ(r) with 1/r reference overlay
|
|
38
|
+
- `plot_isosurface` — 3D voxel rendering of χ wells/voids
|
|
39
|
+
- `plot_power_spectrum` — Fourier P(k) visualisation
|
|
40
|
+
- `plot_trajectories` — peak motion scatter plots
|
|
41
|
+
- `plot_sweep` — parameter sweep line plots
|
|
42
|
+
- **Power spectrum analyser** (`lfm.analysis.spectrum`): `power_spectrum()` — radially-averaged FFT P(k) for any 3D field
|
|
43
|
+
- **Particle tracker** (`lfm.analysis.tracker`): `track_peaks()` and `flatten_trajectories()` — follow energy-density maxima across timesteps
|
|
44
|
+
- **Parameter sweep runner** (`lfm.sweep`): `sweep()` — run a batch of simulations varying one parameter, collect metrics
|
|
45
|
+
- **Docs**: `docs/troubleshooting.md` — common errors (NaN, CFL, slow, imports) with fixes
|
|
46
|
+
- **Docs**: `docs/primer.md` — "LFM in Five Minutes" physics primer
|
|
47
|
+
|
|
7
48
|
## [0.2.1] - 2026-03-20
|
|
8
49
|
|
|
9
50
|
### Added
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as contributors and maintainers pledge to make participation in our
|
|
6
|
+
project a harassment-free experience for everyone.
|
|
7
|
+
|
|
8
|
+
## Our Standards
|
|
9
|
+
|
|
10
|
+
Examples of behavior that contributes to a positive environment:
|
|
11
|
+
|
|
12
|
+
* Using welcoming and inclusive language
|
|
13
|
+
* Being respectful of differing viewpoints
|
|
14
|
+
* Gracefully accepting constructive criticism
|
|
15
|
+
* Focusing on what is best for the community
|
|
16
|
+
|
|
17
|
+
Examples of unacceptable behavior:
|
|
18
|
+
|
|
19
|
+
* Trolling, insulting/derogatory comments, and personal attacks
|
|
20
|
+
* Public or private harassment
|
|
21
|
+
* Publishing others' private information without permission
|
|
22
|
+
|
|
23
|
+
## Enforcement
|
|
24
|
+
|
|
25
|
+
Instances of unacceptable behavior may be reported to the project maintainers.
|
|
26
|
+
All complaints will be reviewed and investigated promptly and fairly.
|
|
27
|
+
|
|
28
|
+
## Attribution
|
|
29
|
+
|
|
30
|
+
This Code of Conduct is adapted from the
|
|
31
|
+
[Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lfm-physics
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Lattice Field Medium physics simulation library
|
|
5
5
|
Project-URL: Homepage, https://github.com/gpartin/lfm-physics
|
|
6
6
|
Project-URL: Repository, https://github.com/gpartin/lfm-physics
|
|
@@ -214,6 +214,56 @@ fc = lfm.color_variance(psi_real_color, psi_imag_color)
|
|
|
214
214
|
|
|
215
215
|
# Confinement proxy — χ line integral between peaks
|
|
216
216
|
proxy = lfm.confinement_proxy(sim.chi, pos_a, pos_b)
|
|
217
|
+
|
|
218
|
+
# Fourier power spectrum P(k) of any 3D field
|
|
219
|
+
spec = lfm.power_spectrum(sim.chi, bins=50)
|
|
220
|
+
# spec['k'], spec['power']
|
|
221
|
+
|
|
222
|
+
# Track energy peaks across a run
|
|
223
|
+
trajectories = lfm.track_peaks(sim, steps=5000, interval=200, n_peaks=3)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Parameter Sweeps
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
# Sweep amplitude from 2 to 10 and record chi_min at each value
|
|
230
|
+
config = lfm.SimulationConfig(grid_size=32)
|
|
231
|
+
results = lfm.sweep(config, param="amplitude", values=[2, 4, 6, 8, 10],
|
|
232
|
+
steps=3000, metric_names=["chi_min", "well_fraction"])
|
|
233
|
+
for r in results:
|
|
234
|
+
print(f"amp={r['amplitude']:.0f} chi_min={r['chi_min']:.2f}")
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Visualisation *(New in 0.3.0)*
|
|
238
|
+
|
|
239
|
+
Install with: `pip install "lfm-physics[viz]"`
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
from lfm.viz import (
|
|
243
|
+
plot_slice, # 2D slice through a 3D field
|
|
244
|
+
plot_three_slices, # XY + XZ + YZ panels
|
|
245
|
+
plot_chi_histogram, # distribution of χ values
|
|
246
|
+
plot_evolution, # time-series of metrics
|
|
247
|
+
plot_energy_components, # stacked kinetic / gradient / potential
|
|
248
|
+
plot_radial_profile, # χ(r) with 1/r reference overlay
|
|
249
|
+
plot_isosurface, # 3D voxel rendering
|
|
250
|
+
plot_power_spectrum, # P(k) from Fourier analysis
|
|
251
|
+
plot_trajectories, # peak motion in x-y / x-z / y-z
|
|
252
|
+
plot_sweep, # sweep results line plot
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# Example: slice through the chi field at z = 32
|
|
256
|
+
fig, ax = plot_slice(sim.chi, axis=2, index=32, title="χ mid-plane")
|
|
257
|
+
fig.savefig("chi_slice.png")
|
|
258
|
+
|
|
259
|
+
# Three-panel overview
|
|
260
|
+
fig = plot_three_slices(sim.chi, title="χ field")
|
|
261
|
+
|
|
262
|
+
# Time evolution dashboard
|
|
263
|
+
fig = plot_evolution(sim.history)
|
|
264
|
+
|
|
265
|
+
# Radial profile with 1/r fit
|
|
266
|
+
fig, ax = plot_radial_profile(sim.chi, center=(32,32,32))
|
|
217
267
|
```
|
|
218
268
|
|
|
219
269
|
## Checkpoints & Units
|
|
@@ -172,6 +172,56 @@ fc = lfm.color_variance(psi_real_color, psi_imag_color)
|
|
|
172
172
|
|
|
173
173
|
# Confinement proxy — χ line integral between peaks
|
|
174
174
|
proxy = lfm.confinement_proxy(sim.chi, pos_a, pos_b)
|
|
175
|
+
|
|
176
|
+
# Fourier power spectrum P(k) of any 3D field
|
|
177
|
+
spec = lfm.power_spectrum(sim.chi, bins=50)
|
|
178
|
+
# spec['k'], spec['power']
|
|
179
|
+
|
|
180
|
+
# Track energy peaks across a run
|
|
181
|
+
trajectories = lfm.track_peaks(sim, steps=5000, interval=200, n_peaks=3)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Parameter Sweeps
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
# Sweep amplitude from 2 to 10 and record chi_min at each value
|
|
188
|
+
config = lfm.SimulationConfig(grid_size=32)
|
|
189
|
+
results = lfm.sweep(config, param="amplitude", values=[2, 4, 6, 8, 10],
|
|
190
|
+
steps=3000, metric_names=["chi_min", "well_fraction"])
|
|
191
|
+
for r in results:
|
|
192
|
+
print(f"amp={r['amplitude']:.0f} chi_min={r['chi_min']:.2f}")
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Visualisation *(New in 0.3.0)*
|
|
196
|
+
|
|
197
|
+
Install with: `pip install "lfm-physics[viz]"`
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from lfm.viz import (
|
|
201
|
+
plot_slice, # 2D slice through a 3D field
|
|
202
|
+
plot_three_slices, # XY + XZ + YZ panels
|
|
203
|
+
plot_chi_histogram, # distribution of χ values
|
|
204
|
+
plot_evolution, # time-series of metrics
|
|
205
|
+
plot_energy_components, # stacked kinetic / gradient / potential
|
|
206
|
+
plot_radial_profile, # χ(r) with 1/r reference overlay
|
|
207
|
+
plot_isosurface, # 3D voxel rendering
|
|
208
|
+
plot_power_spectrum, # P(k) from Fourier analysis
|
|
209
|
+
plot_trajectories, # peak motion in x-y / x-z / y-z
|
|
210
|
+
plot_sweep, # sweep results line plot
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Example: slice through the chi field at z = 32
|
|
214
|
+
fig, ax = plot_slice(sim.chi, axis=2, index=32, title="χ mid-plane")
|
|
215
|
+
fig.savefig("chi_slice.png")
|
|
216
|
+
|
|
217
|
+
# Three-panel overview
|
|
218
|
+
fig = plot_three_slices(sim.chi, title="χ field")
|
|
219
|
+
|
|
220
|
+
# Time evolution dashboard
|
|
221
|
+
fig = plot_evolution(sim.history)
|
|
222
|
+
|
|
223
|
+
# Radial profile with 1/r fit
|
|
224
|
+
fig, ax = plot_radial_profile(sim.chi, center=(32,32,32))
|
|
175
225
|
```
|
|
176
226
|
|
|
177
227
|
## Checkpoints & Units
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
| Version | Supported |
|
|
6
|
+
| ------- | ------------------ |
|
|
7
|
+
| 0.3.x | :white_check_mark: |
|
|
8
|
+
| < 0.3 | :x: |
|
|
9
|
+
|
|
10
|
+
## Reporting a Vulnerability
|
|
11
|
+
|
|
12
|
+
If you discover a security vulnerability, please report it responsibly:
|
|
13
|
+
|
|
14
|
+
1. **Do not** open a public issue.
|
|
15
|
+
2. Email the maintainer directly with details.
|
|
16
|
+
3. Allow reasonable time for a fix before public disclosure.
|
|
17
|
+
|
|
18
|
+
lfm-physics is a scientific simulation library with no network services,
|
|
19
|
+
authentication, or user data handling. Security concerns are limited to
|
|
20
|
+
arbitrary code execution via pickle/eval (we use only numpy `.npz` for
|
|
21
|
+
checkpoints, which is safe).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Minimal makefile for Sphinx documentation
|
|
2
|
+
SPHINXOPTS ?=
|
|
3
|
+
SPHINXBUILD ?= sphinx-build
|
|
4
|
+
SOURCEDIR = .
|
|
5
|
+
BUILDDIR = _build
|
|
6
|
+
|
|
7
|
+
.PHONY: help html clean livehtml
|
|
8
|
+
|
|
9
|
+
help:
|
|
10
|
+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
|
|
11
|
+
|
|
12
|
+
html:
|
|
13
|
+
@$(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
|
|
14
|
+
|
|
15
|
+
clean:
|
|
16
|
+
@rm -rf $(BUILDDIR)
|
|
17
|
+
|
|
18
|
+
livehtml:
|
|
19
|
+
sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)/html" $(SPHINXOPTS)
|
|
20
|
+
|
|
21
|
+
# Catch-all target
|
|
22
|
+
%:
|
|
23
|
+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
@ECHO OFF
|
|
2
|
+
pushd %~dp0
|
|
3
|
+
|
|
4
|
+
REM Minimal Windows batch file for Sphinx documentation
|
|
5
|
+
|
|
6
|
+
if "%SPHINXBUILD%" == "" (
|
|
7
|
+
set SPHINXBUILD=sphinx-build
|
|
8
|
+
)
|
|
9
|
+
set SOURCEDIR=.
|
|
10
|
+
set BUILDDIR=_build
|
|
11
|
+
|
|
12
|
+
if "%1" == "" goto help
|
|
13
|
+
if "%1" == "clean" goto clean
|
|
14
|
+
|
|
15
|
+
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
|
16
|
+
goto end
|
|
17
|
+
|
|
18
|
+
:clean
|
|
19
|
+
rmdir /s /q %BUILDDIR% 2>NUL
|
|
20
|
+
goto end
|
|
21
|
+
|
|
22
|
+
:help
|
|
23
|
+
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
|
24
|
+
|
|
25
|
+
:end
|
|
26
|
+
popd
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# LFM in Five Minutes
|
|
2
|
+
|
|
3
|
+
A minimal introduction to the physics behind the `lfm-physics` library.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## One Sentence
|
|
8
|
+
|
|
9
|
+
> The universe is a cubic lattice where every point stores two numbers —
|
|
10
|
+
> a wave amplitude **Ψ** and a local stiffness **χ** — and they evolve
|
|
11
|
+
> by two coupled wave equations.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## The Two Fields
|
|
16
|
+
|
|
17
|
+
| Symbol | Name | Physical meaning |
|
|
18
|
+
|--------|------|------------------|
|
|
19
|
+
| **Ψ** | Wave field | Energy / matter at each lattice point |
|
|
20
|
+
| **χ** | Chi field | Stiffness of the lattice at each point |
|
|
21
|
+
|
|
22
|
+
Empty space has χ = 19 everywhere. Where energy concentrates, χ drops
|
|
23
|
+
below 19, forming a potential well — what we call *gravity*.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## The Two Equations
|
|
28
|
+
|
|
29
|
+
**GOV-01 — Wave Equation** (how Ψ evolves):
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
Ψⁿ⁺¹ = 2Ψⁿ − Ψⁿ⁻¹ + Δt²[c²∇²Ψⁿ − (χⁿ)²Ψⁿ]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Energy propagates through the lattice. The `χ²Ψ` term means waves
|
|
36
|
+
oscillate faster where χ is high (empty space) and slower where χ is low
|
|
37
|
+
(near matter). This is how gravity bends light.
|
|
38
|
+
|
|
39
|
+
**GOV-02 — Chi Equation** (how χ evolves):
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
χⁿ⁺¹ = 2χⁿ − χⁿ⁻¹ + Δt²[c²∇²χⁿ − κ(|Ψⁿ|² − E₀²)]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Energy density |Ψ|² pushes χ down — matter curves spacetime. The
|
|
46
|
+
coupling κ = 1/63 is derived from the lattice geometry.
|
|
47
|
+
|
|
48
|
+
**That's it.** These two update rules, applied at every lattice point
|
|
49
|
+
every timestep, produce gravity, waves, dark matter, expansion, and more.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Why 19?
|
|
54
|
+
|
|
55
|
+
The number 19 comes from counting non-propagating modes on a 3D cubic
|
|
56
|
+
lattice:
|
|
57
|
+
|
|
58
|
+
| Mode type | Count | k-vectors |
|
|
59
|
+
|-----------|-------|-----------|
|
|
60
|
+
| Centre | 1 | (0,0,0) |
|
|
61
|
+
| Faces | 6 | (±1,0,0), (0,±1,0), (0,0,±1) |
|
|
62
|
+
| Edges | 12 | (±1,±1,0), etc. |
|
|
63
|
+
| **Total** | **19** | **= χ₀** |
|
|
64
|
+
|
|
65
|
+
The remaining 8 corner modes (±1,±1,±1) are propagating — identifying
|
|
66
|
+
them with gluons gives N_gluons = 8.
|
|
67
|
+
|
|
68
|
+
From χ₀ = 19 alone, LFM derives 40+ physical constants to high accuracy.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## What Emerges
|
|
73
|
+
|
|
74
|
+
| Phenomenon | How it arises |
|
|
75
|
+
|------------|---------------|
|
|
76
|
+
| **Gravity** | Energy (|Ψ|²) dips χ → potential well → attraction |
|
|
77
|
+
| **Dark matter** | χ wells persist after matter moves away (memory) |
|
|
78
|
+
| **Electromagnetism** | Phase of complex Ψ = charge; interference = Coulomb |
|
|
79
|
+
| **Expansion** | Voids evacuate → χ rises → photons slow down |
|
|
80
|
+
| **Particles** | Standing waves trapped in self-consistent χ wells |
|
|
81
|
+
| **Atoms** | Nuclear χ well + bound electron eigenmodes |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Quick Start
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
import lfm
|
|
89
|
+
|
|
90
|
+
# Create a 64-cell cubic universe
|
|
91
|
+
config = lfm.SimulationConfig(grid_size=64)
|
|
92
|
+
sim = lfm.Simulation(config)
|
|
93
|
+
|
|
94
|
+
# Drop a soliton — a localized energy concentration
|
|
95
|
+
sim.place_soliton((32, 32, 32), amplitude=6.0)
|
|
96
|
+
|
|
97
|
+
# Evolve for 1000 timesteps
|
|
98
|
+
sim.run(steps=1000)
|
|
99
|
+
|
|
100
|
+
# Look at what happened
|
|
101
|
+
print(f"χ_min = {sim.chi.min():.2f}") # Should be < 19 (gravity!)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
See the [examples/](../examples/) directory for 14 runnable demos covering
|
|
105
|
+
gravity, electromagnetism, atoms, orbits, cosmology, and more.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Going Deeper
|
|
110
|
+
|
|
111
|
+
| Topic | Resource |
|
|
112
|
+
|-------|----------|
|
|
113
|
+
| Full API reference | `help(lfm.Simulation)` |
|
|
114
|
+
| All 14 examples | [examples/](../examples/) |
|
|
115
|
+
| Visualization | `from lfm.viz import plot_slice` |
|
|
116
|
+
| Parameter sweeps | `from lfm import sweep` |
|
|
117
|
+
| Common errors | [troubleshooting.md](troubleshooting.md) |
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Common problems and how to fix them.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## My simulation gives NaN
|
|
8
|
+
|
|
9
|
+
**Cause:** The wave amplitude is too large for the grid, causing the
|
|
10
|
+
leapfrog integrator to diverge.
|
|
11
|
+
|
|
12
|
+
**Fix:**
|
|
13
|
+
```python
|
|
14
|
+
# Lower the amplitude
|
|
15
|
+
sim.place_soliton((32, 32, 32), amplitude=4.0) # instead of 12.0
|
|
16
|
+
|
|
17
|
+
# Or use a larger grid (more room to spread energy)
|
|
18
|
+
config = lfm.SimulationConfig(grid_size=128) # instead of 32
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Rule of thumb:** Keep amplitude below ~8 for `grid_size=32`, below ~12
|
|
22
|
+
for `grid_size=64`. When in doubt, start small and increase.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Energy diverges over time
|
|
27
|
+
|
|
28
|
+
**Cause:** The timestep `dt` exceeds the CFL stability limit.
|
|
29
|
+
|
|
30
|
+
**Fix:** Use the default `dt=0.02` — it satisfies the CFL condition for
|
|
31
|
+
all standard setups. If you've changed `dt` manually:
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
# Safe: dt = 0.02 (default, well inside CFL)
|
|
35
|
+
config = lfm.SimulationConfig(dt=0.02)
|
|
36
|
+
|
|
37
|
+
# The CFL limit for the 19-point stencil with χ₀=19:
|
|
38
|
+
# dt < 1/sqrt(16c²/(3·Δx²) + χ₀²) ≈ 0.104 (for Δx=c=1)
|
|
39
|
+
# Our default 0.02 gives ~5× safety margin.
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## χ goes negative
|
|
45
|
+
|
|
46
|
+
**This is not a bug.** In extreme-gravity scenarios (very high amplitude
|
|
47
|
+
or dense clusters), χ can dip below zero. This is the LFM equivalent of
|
|
48
|
+
a black hole interior.
|
|
49
|
+
|
|
50
|
+
**If you want to prevent it:** Enable the Mexican-hat self-interaction,
|
|
51
|
+
which creates a stable second vacuum at −χ₀:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
config = lfm.SimulationConfig(
|
|
55
|
+
lambda_self=lfm.LAMBDA_H, # 4/31 ≈ 0.129
|
|
56
|
+
)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**If you don't care about extreme gravity:** Use gravity-only mode
|
|
60
|
+
(default `lambda_self=0.0`) and lower the amplitude.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Everything collapses into one blob
|
|
65
|
+
|
|
66
|
+
**Cause:** With periodic boundaries and enough energy, gravity always
|
|
67
|
+
wins — everything falls toward the centre of mass. This is correct
|
|
68
|
+
physics for a closed universe.
|
|
69
|
+
|
|
70
|
+
**Fix:** Use frozen boundaries (the default) to simulate an open region
|
|
71
|
+
embedded in the vacuum:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
config = lfm.SimulationConfig(
|
|
75
|
+
boundary_type=lfm.BoundaryType.FROZEN, # default
|
|
76
|
+
)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Frozen boundaries hold χ = 19 at the edges, representing infinite empty
|
|
80
|
+
space beyond the simulation box.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Simulation is very slow
|
|
85
|
+
|
|
86
|
+
**Check 1 — Are you using GPU?**
|
|
87
|
+
```python
|
|
88
|
+
print(lfm.gpu_available()) # True if CuPy + CUDA detected
|
|
89
|
+
|
|
90
|
+
# Force GPU
|
|
91
|
+
sim = lfm.Simulation(config, backend="gpu")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Install GPU support:
|
|
95
|
+
```bash
|
|
96
|
+
pip install "lfm-physics[gpu]"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Check 2 — Is your grid too large for CPU?**
|
|
100
|
+
|
|
101
|
+
| Grid size | Cells | CPU time/step | GPU time/step |
|
|
102
|
+
|-----------|-----------|---------------|---------------|
|
|
103
|
+
| 32³ | 32 K | ~0.3 ms | ~0.02 ms |
|
|
104
|
+
| 64³ | 262 K | ~3 ms | ~0.05 ms |
|
|
105
|
+
| 128³ | 2.1 M | ~30 ms | ~0.3 ms |
|
|
106
|
+
| 256³ | 16.8 M | ~300 ms | ~7 ms |
|
|
107
|
+
|
|
108
|
+
For grid_size ≥ 128 on CPU, expect minutes for long runs. GPU gives
|
|
109
|
+
50–200× speedup.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## ImportError: matplotlib not found
|
|
114
|
+
|
|
115
|
+
The visualization module (`lfm.viz`) requires matplotlib:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
pip install "lfm-physics[viz]"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Or install everything:
|
|
122
|
+
```bash
|
|
123
|
+
pip install "lfm-physics[all]"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## How do I save and resume a run?
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
# Save
|
|
132
|
+
sim.save_checkpoint("my_run.npz")
|
|
133
|
+
|
|
134
|
+
# Resume later
|
|
135
|
+
sim2 = lfm.Simulation.load_checkpoint("my_run.npz")
|
|
136
|
+
sim2.run(steps=5000) # continues where it left off
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Checkpoints preserve the full simulation state: fields, config, step
|
|
140
|
+
count, and metric history.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Which field level should I use?
|
|
145
|
+
|
|
146
|
+
| I want to simulate... | Field level |
|
|
147
|
+
|-----------------------------------|-----------------------|
|
|
148
|
+
| Gravity, dark matter, cosmology | `FieldLevel.REAL` |
|
|
149
|
+
| Electromagnetism, charged particles | `FieldLevel.COMPLEX` |
|
|
150
|
+
| Strong force, color confinement | `FieldLevel.COLOR` |
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
config = lfm.SimulationConfig(
|
|
154
|
+
field_level=lfm.FieldLevel.COMPLEX, # for EM
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Start with REAL (simplest, fastest). Upgrade only when your physics
|
|
159
|
+
requires it.
|