Skip to content

feat: a second project, where the physics is real - #5

Merged
sotashimozono merged 1 commit into
mainfrom
feat/example-montecarlo
Sep 8, 2026
Merged

sotashimozono merged 1 commit into
mainfrom
feat/example-montecarlo

Conversation

@sotashimozono

Copy link
Copy Markdown
Member

ExampleMonteCarlo sweeps the Ising model on a square lattice over size and temperature —
ClassicalMonteCarlo over a Lattice2D lattice, through the LatticeCore interface.

It exists because the first project's kernel is a placeholder, and three of this template's claims
are only worth anything against a real work package.

The compute environment has no plotting backend, and that is not hygiene

Both physics packages carried Plots as a hard dependency until this week
(sotashimozono/DynamicalModels.jl#14, sotashimozono/Lattice2D.jl#88 moved it behind an extension).
run!(…; load=ExampleMonteCarlo) ships this module to every worker, so before those fixes this
project would have put a plotting stack on all of them.

report/ is where Plots lives. It reads the same vault off disk and calls the same reduction from
src/, so the table printed on the cluster and the figure drawn afterwards cannot disagree.

Every call is qualified, because two packages export run!

ClassicalMonteCarlo.run! advances a Markov chain. SweepRunner.run! dispatches the sweep. Every
module is imported as using X: X — the module, none of its exports — so neither can be reached
unqualified by accident.

The test asserts physics, not a threshold

Deep in the ordered phase the magnetisation is near saturation and the Binder cumulant near 2/3;
well above the transition both collapse. A chain that quietly stopped equilibrating fails from
both directions, which a tolerance picked to match today's output would not catch.

cold  kbT=1.2   |M|=0.9977   E/N=-1.9909   U4=0.6666
hot   kbT=4.0   |M|=0.1913   E/N=-0.5579   U4=0.0285

E/N → -2 and U4 → 2/3 are the textbook values, which is what makes the assertion meaningful
rather than a snapshot.

The temperature grids crowd kbT ≈ 2.269, the exact 2D Ising transition, because a sweep earns its
cost when the interesting thing happens between two of its points.

One correction worth recording

build_lattice takes the topology type, not an instance: Type{<:AbstractTopology{2}}.
ClassicalMonteCarlo's own script/random_runner.jl calls it as LType(), so copying that
working-looking example produced a MethodError. The signature came from methods(build_lattice)
instead. An example can be stale; the method table cannot.

Verified

test/runtests.jl                5 pass
compute.jl configs/smoke.toml   (done = 2, err = 0, total = 2)
collect.jl                      L=8 kbT=2.000  E/N=-1.71131  |M|=0.86310  U4=0.6309
                                L=8 kbT=2.500  E/N=-1.23214  |M|=0.63542  U4=0.5767
compute.jl again                (done = 0, skipped = 2)

CI picks this up without being told: discover finds every projects/*/Project.toml, so the matrix
now has two entries.

`ExampleMonteCarlo` sweeps the Ising model on a square lattice over size and temperature, using
ClassicalMonteCarlo over a Lattice2D lattice through the LatticeCore interface. It exists because
the first project's kernel is a placeholder, and three of this template's claims are only worth
anything against a real work package.

**The compute environment has no plotting backend, and that is not hygiene.** Both physics packages
carried `Plots` as a hard dependency until this week (DynamicalModels#14, Lattice2D#88 moved it
behind an extension). `run!(…; load=ExampleMonteCarlo)` ships this module to every worker, so before
those fixes this project would have put a plotting stack on all of them. `report/` is where Plots
lives, and it reads the same vault off disk.

**Every call is qualified, because two packages export `run!`.** ClassicalMonteCarlo's advances a
Markov chain; SweepRunner's dispatches the sweep. Every module is imported `using X: X`, so neither
can be reached unqualified by accident.

**The test asserts physics rather than a threshold.** Deep in the ordered phase the magnetisation is
near saturation and the Binder cumulant near 2/3; well above the transition both collapse. A chain
that quietly stopped equilibrating fails from both directions, which a tolerance picked to match
today's output would not catch. Measured: kbT=1.2 gives |M|=0.9977, E/N=-1.9909, U4=0.6666;
kbT=4.0 gives 0.1913, -0.5579, 0.0285.

The temperature grids crowd kbT ≈ 2.269, the exact 2D Ising transition, because a sweep earns its
cost when the interesting thing happens between two of its points.

One correction worth recording. `build_lattice` takes the topology TYPE, not an instance —
`Type{<:AbstractTopology{2}}`. ClassicalMonteCarlo's own `script/random_runner.jl` calls it as
`LType()`, so copying that working-looking example produced a MethodError; the signature came from
`methods(build_lattice)` instead. An example can be stale, and only the method table is not.

Verified end to end: 5 tests pass, smoke sweep done=2/err=0, `collect.jl` prints both points, and a
second run reports skipped=2.
@github-actions github-actions Bot added the enhancement New feature or request label Sep 8, 2026
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

📚 Docs preview: https://qatlashub.github.io/templateHPC.jl/previews/PR5/

(updates on each push to this PR)

@sotashimozono
sotashimozono merged commit 0ea7747 into main Sep 8, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant