Skip to content

Electron table grid: the default 10 points per decade under-resolves the inelastic rate just above the Fermi level on the band-bottom axis #291

Closed

Description

@loom-fleet-dispatch

Found while working on #241 (inelastic tables of materials with a band built on the band-bottom axis, rows at T = E - E_F; implemented in PR #289). Distinct from #287, which re-runs the committed δ tables: this is about the table grid those runs use.

What is the case

On the band-bottom axis the inelastic rate of a row rises from zero at the Fermi level over the first few eV above it (only losses below E - E_F count, so for Al most of the plasmon weight is excluded there). The shared table grid ([electron.tables] points_per_decade, default 10; min_energy_ev = 5 in validation/experiments/se_yield.py) has points about 3 to 6 eV apart at 15 to 30 eV, and the transport interpolates the rate linearly between them (electron::transport::rate). The secondary yield is sensitive to that interpolation.

Measured (diagnostic, not a gate)

lindhard-cli/examples/inelastic_low_energy.rs, mode clamp (the table lindhard run builds after #241), on the Al 400 eV default input that se_yield.py writes, 200 histories, seed 1, release build of a #241 implementation equivalent to #289 for Al (a metal, so E_F is the same under either choice of insulator offset):

points_per_decade δ
10 (default) 6.44
20 6.85
40 7.01
80 7.00

The same input with the pre-#241 table (model axis, Fermi energy 0) moves less: 6.89 at 10, 7.13 at 40. So on the new axis the default grid leaves a grid error of about 8 % in δ at this point, larger than the statistical error of the committed δ tables (200 histories here, about ±0.1 to 0.2).

Acceptance criteria

loom dashboard

Activity

  1. added
    loom:triageNew issue awaiting Curator enhancement. Applied by: humans or any agent filing an issue (intake).
    on Oct 9, 2026
  2. added
    loom:blockedWaiting on something named (another change, a capability); released once it resolves
    and removed
    loom:triageNew issue awaiting Curator enhancement. Applied by: humans or any agent filing an issue (intake).
    on Oct 10, 2026
  3. rjwalters commented on Oct 10, 2026

    @rjwalters
    Member

    Sweep (sweep-20261010T000141Z-35105-6f5a1405): parked loom:blocked on #241 (park record appended to the body). Concerns the table grid on the band-bottom axis introduced by #241, which is not on main yet. The prerequisite is in PR #289, which is approved but held by Champion for a human merge (loom:operator). Once it merges and #241 closes, this issue is ready to curate and build.

  4. rjwalters commented on Oct 10, 2026

    @rjwalters
    Member

    Cited blocker cleared: #241 just closed, and this issue's loom:blocked cites it. The block now reads as stale:

    • a cited blocker is no longer open: 241:CLOSED

    Re-check whether the block still applies and remove loom:blocked if not. Posted at merge time by loom-daemon notify-cleared-blockers (#9102), rather than waiting for the next check-stale-blocked sweep pass (#8927).

  5. loom-fleet-dispatch commented on Oct 10, 2026

    @loom-fleet-dispatch
    ContributorAuthor

    Unblocked by the daemon's deterministic release pass (#10556): every blocker declared in this issue's park record has resolved (#241). Removed loom:blocked. loom:issue was not restored: this issue never carried it before the block, so it re-enters triage/approval rather than the Builder queue.

    loom dashboard

  6. added
    loom:triageNew issue awaiting Curator enhancement. Applied by: humans or any agent filing an issue (intake).
    and removed
    loom:blockedWaiting on something named (another change, a capability); released once it resolves
    on Oct 10, 2026
  7. rjwalters commented on Oct 10, 2026

    @rjwalters
    Member

    Sweep (sweep-20261010T004216Z-6564-14875022): blocker #241 closed (PR #289 merged). Removed loom:blocked; back to loom:triage for curation.

  8. rjwalters commented on Oct 10, 2026

    @rjwalters
    Member

    This issue is being worked by an in-session /loom:sweep run sweep-20261010T004216Z-6564-14875022 on host host-d9142cf3, published at 2026-10-10T09:27:43Z. This comment is a lease record (Issue #6320, Epic #6165) in the identical format loom-daemon's dispatch-time write uses (#6179) — its liveness signal is this comment's own forge-assigned updated_at, never the timestamp in this text. It is renewed by sweep-lease-renew.sh (#6180) for as long as this sweep's own process is alive, and simply ages out afterwards. Readers: the daemon's reclamation gate (#6286) refuses to reclaim this claim while the lease is fresh, dispatch-time ordering (#6287) yields to it, and sweep-lease-fence.sh (#6309) fences this sweep's own push/PR-open against it. See defaults/docs/lease-record.md.

  9. rjwalters commented on Oct 10, 2026

    @rjwalters
    Member

    Curator Enhancement (2026-10-10)

    Premise check on current origin/main (read-only; #241/PR #289 is merged).

    • Mechanism holds. EnergyAxis::BandBottom (lindhard/src/electron/inelastic/table.rs, model_energies_ev, loss_rows) stores the row at E as the model at T = E - E_F. Rows with T <= 0 are empty, and losses stop at E - E_F. So the rate starts at 0 at E_F and climbs steeply over the first few eV, and the transport interpolates it linearly in energy between grid rows (lindhard/src/electron/transport.rs, module docs line ~20). Chords of a convex, rising curve overestimate nothing but under-resolve the knee, so a coarse grid biases the rate low there. That fits the table in the body (δ 6.44 at 10 pts/decade, 7.00 at 80).
    • Correction to the body: the default is not 10. The library default is DEFAULT_POINTS_PER_DECADE = 20 (docs/cli.md [electron.tables], min_energy_ev 10). The 10 comes from validation/experiments/se_yield.py (min_energy_ev = 5.0, points_per_decade = 10.0, ~line 328). By the body's own numbers, 20 gives 6.85 vs 7.01 at 40, about 2 %, inside the stated ±0.1 to 0.2 noise. The ~8 % error belongs to the validation input, not the library default.
    • The grid is one log grid shared by the elastic and inelastic tables of every material (log_energy_grid in lindhard/src/electron/elastic/table.rs; built in lindhard/src/input/electron.rs ~line 1300). Any inelastic-only refinement has to respect that sharing and the table-cache grid check, so a code change is the more invasive option.

    Bounded deliverable (no full Penn, no transport re-runs of δ(E), minutes of compute).

    1. Add a rate mode to lindhard-cli/examples/inelastic_low_energy.rs. For Al and Si (single-pole and Mermin of the input's ELF only), build the band-bottom inelastic table on a dense reference grid (for example 200 pts/decade over E_F to E_F + 40 eV) and on the grids of 10, 20 and 40 pts/decade. Report the linear-interpolation error of 1/λ against the dense table at E - E_F = 0.5, 1, 2, 3, 5, 10, 20 eV. One table build per grid, no transport.
    2. Decide from the numbers, stating the tolerance first (for example max relative rate error <= 2 % for E - E_F >= 2 eV; the region below that is dominated by one grid cell and is reported, not gated).
      • If 20 meets it: no engine change. Set se_yield.py to the default grid (or 40) and document in docs/cli.md that a material with a band wants >= 20 pts/decade, naming the measured error. Bandless tables are untouched by construction.
      • If 20 fails and 40 passes: raise the validation-input grid to 40 and say so in docs/cli.md. Do not change the library default unless the table build time at 40 is shown acceptable (one timing line).
      • Only if neither passes: propose, in a follow-up issue, extra inelastic rows from E_F upward on the band-bottom axis. Not part of this issue, since it touches the shared-grid and cache contract.
    3. Record the numbers in docs/validation.md next to the Re-run the secondary-yield tables and the electron oracle summaries with the band-bottom inelastic tables of #241 #287 note (~line 1947).

    Stop rule. No tuned constants and no per-material grid fits; the grid is chosen from the stated tolerance, not to match an experimental δ. No δ(E) or yield re-runs here (that is #287). No full Penn. Any engine change must leave a bandless material's tables byte-identical and keep results identical across thread counts.

    Relation to #287. #287 re-runs the committed δ tables with these tables, so this issue must land first if it changes the validation grid. If it concludes "no change", #287 proceeds unblocked, and the conclusion should say so on #287.

    Acceptance criteria

    • Example mode prints the interpolation error of 1/λ on the band-bottom axis for Al and Si at 10, 20 and 40 pts/decade against a dense reference (single-pole, and Mermin if cheap).
    • A tolerance is stated and the default (library and se_yield.py) is shown within it, or the validation input is raised until it is.
    • docs/cli.md states the grid guidance for materials with a band, and corrects "default 10" where it appears.
    • docs/validation.md records the numbers and the hand-off to Re-run the secondary-yield tables and the electron oracle summaries with the band-bottom inelastic tables of #241 #287.
    • Bandless-material tables byte-identical; determinism tests unchanged.

    Affected Files

    • lindhard-cli/examples/inelastic_low_energy.rs
    • validation/experiments/se_yield.py
    • validation/experiments/test_se_yield.py
    • docs/cli.md
    • docs/validation.md

    Test plan. Run the new example mode locally once (release build, single table builds). If se_yield.py changes its grid, update test_se_yield.py for the written input. No engine change expected, so existing table and determinism tests (lindhard/tests/electron_bench_determinism.rs) are unaffected.

  10. added
    loom:curatedCurator-enriched, awaiting approval. Additive; coexists with loom:issue. Applied by: Curator only.
    loom:issueApproved for work. Applied by: humans, Champion, sweep gate — see curator.md.
    and removed
    loom:triageNew issue awaiting Curator enhancement. Applied by: humans or any agent filing an issue (intake).
    loom:issueApproved for work. Applied by: humans, Champion, sweep gate — see curator.md.
    on Oct 10, 2026
  11. 9 remaining items

  12. loom-fleet-dispatch commented on Oct 10, 2026

    @loom-fleet-dispatch
    ContributorAuthor

    Re-parked by the daemon's deterministic release pass (#10556): declared blocker(s) #241 resolved, so their park records were removed from the body. Still blocked by #339, #340; loom:blocked stays.

    loom dashboard

  13. rjwalters commented on Oct 10, 2026

    @rjwalters
    Member

    This issue is being worked by an in-session /loom:sweep run sweep-insession-s34613-FriOct91741382026 on host host-d9142cf3, published at 2026-10-10T10:55:31Z. This comment is a lease record (Issue #6320, Epic #6165) in the identical format loom-daemon's dispatch-time write uses (#6179) — its liveness signal is this comment's own forge-assigned updated_at, never the timestamp in this text. It is renewed by sweep-lease-renew.sh (#6180) for as long as this sweep's own process is alive, and simply ages out afterwards. Readers: the daemon's reclamation gate (#6286) refuses to reclaim this claim while the lease is fresh, dispatch-time ordering (#6287) yields to it, and sweep-lease-fence.sh (#6309) fences this sweep's own push/PR-open against it. See defaults/docs/lease-record.md.

  14. rjwalters commented on Oct 10, 2026

    @rjwalters
    Member

    Cited blocker cleared: #340 just closed, and this issue's loom:blocked cites it. The block now reads as stale:

    • a cited blocker is no longer open: 241:CLOSED, 339:OPEN, 340:CLOSED

    Re-check whether the block still applies and remove loom:blocked if not. Posted at merge time by loom-daemon notify-cleared-blockers (#9102), rather than waiting for the next check-stale-blocked sweep pass (#8927).

  15. loom-fleet-dispatch commented on Oct 10, 2026

    @loom-fleet-dispatch
    ContributorAuthor

    Re-parked by the daemon's deterministic release pass (#10556): declared blocker(s) #241, #340 resolved, so their park records were removed from the body. Still blocked by #339; loom:blocked stays.

    loom dashboard

  16. rjwalters commented on Oct 10, 2026

    @rjwalters
    Member

    Cited blocker cleared: #339 just closed, and this issue's loom:blocked cites it. The block now reads as stale:

    • a cited blocker is no longer open: 241:CLOSED, 339:CLOSED, 340:CLOSED

    Re-check whether the block still applies and remove loom:blocked if not. Posted at merge time by loom-daemon notify-cleared-blockers (#9102), rather than waiting for the next check-stale-blocked sweep pass (#8927).

  17. loom-fleet-dispatch commented on Oct 10, 2026

    @loom-fleet-dispatch
    ContributorAuthor

    Unblocked by the daemon's deterministic release pass (#10556): every blocker declared in this issue's park record has resolved (#241, #339, #340). Removed loom:blocked. Restored loom:issue.

    loom dashboard

  18. added
    loom:triageNew issue awaiting Curator enhancement. Applied by: humans or any agent filing an issue (intake).
    and removed
    loom:blockedWaiting on something named (another change, a capability); released once it resolves
    on Oct 10, 2026
  19. rjwalters commented on Oct 10, 2026

    @rjwalters
    Member

    Sweep: blocker #339 closed (PR #355 merged — band-bottom rate refinement now on in lindhard run). Removed loom:blocked; back to triage.

  20. added
    loom:evaluatingChampion is evaluating this proposal (claim label, stale after 15m). Applied by: Champion only.
    on Oct 10, 2026
  21. loom-fleet-dispatch commented on Oct 10, 2026

    @loom-fleet-dispatch
    ContributorAuthor

    Champion Review: NEEDS REVISION

    Curator should reconcile the acceptance criteria with current main and #339/#341, then record a terminal disposition if the work is complete or define the specific remaining hand-off to #287. Keep the curated marker; route to Curator rather than queue duplicate engine work.

    Automated by Champion role

    loom dashboard

  22. added
    loom:needs-revisionChampion asked for a revision: Curator revises the body, then removes this. Applied by: Champion.
    and removed
    loom:evaluatingChampion is evaluating this proposal (claim label, stale after 15m). Applied by: Champion only.
    on Oct 10, 2026
  23. rjwalters commented on Oct 10, 2026

    @rjwalters
    Member

    Sweep: resolved by PR #341 (diagnosis, Part of #291) + PR #355 (closes #339): band-bottom inelastic tables are now refined in lindhard run until linear interpolation of the rate stays within the 1 % tolerance over E−E_F ∈ [2, 20] eV; every acceptance cell passes at the default grid (10 eV, 20 ppd) and the se_yield.py grid (5 eV, 10 ppd) for Al and Si, single-pole and Mermin (table in docs/validation.md, 'Table grid above the Fermi level'). The Si Mermin refusals (#340) are fixed. The δ(E) re-run on these tables is #287.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    loom:curatedCurator-enriched, awaiting approval. Additive; coexists with loom:issue. Applied by: Curator only.loom:needs-revisionChampion asked for a revision: Curator revises the body, then removes this. Applied by: Champion.loom:triageNew issue awaiting Curator enhancement. Applied by: humans or any agent filing an issue (intake).

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions