Skip to content

Develop - #11

Merged
knc6 merged 11 commits into
mainfrom
develop
Aug 6, 2026
Merged

knc6 merged 11 commits into
mainfrom
develop

Conversation

@knc6

@knc6 knc6 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

No description provided.

knc6 added 11 commits June 5, 2026 05:58
Parameter sets:
- Add SLAKONET_MODELS registry mapping slakonet_v0/v1/v1a to their
  Figshare file IDs, replacing the hardcoded v0 download URL.
- default_model(model_name=...), --model_path <name> and the
  SLAKONET_MODEL env var now select a set; load_trained_model resolves
  a bare registry name through the download/cache path.

Forces / stress / energy (all validated against finite differences):
- Geometry stores lengths in Bohr, so dE/dR is eV/Bohr; convert to
  eV/Angstrom instead of applying the beta=0.1 fudge factor.
- Fix the stress: dE/dh^T @ h (not dE/dh @ h^T), correct virial sign,
  and convert eV/Bohr^3 -> eV/Angstrom^3. The ASE wrapper also
  reshaped the Voigt-6 vector to (2,3) and left it in GPa, which made
  get_stress() raise.
- alpha scaled the band energy but not the repulsive term, so the
  total energy was not E_band + E_rep. Default alpha and beta to 1.0;
  Si's equilibrium lattice constant improves from 5.72 to 5.51 A.
  Eigenvalues and bandgaps are unaffected.

Analysis:
- Add compute_site_projected_dos, layer_resolved_dos and
  gap_states_metric for per-atom-index projections, as needed for
  surface, defect and interface electronic structure.
slakonet/optim.py enabled torch.use_deterministic_algorithms(True),
set_detect_anomaly(True) and set_anomaly_enabled(True) at module import.
These are process-global, expensive, and were never opted into.

Consequences, measured on a 2-atom Si cell with a 4x4x4 mesh
(energy + forces, slakonet_v1a):

  anomaly + create_graph (before)   1.93 s
  create_graph=False                0.86 s
  anomaly off as well               0.32 s

Anomaly mode records a Python stack trace per autograd node; profiling
showed torch.fx.traceback.format_stack accounted for 84% of runtime.

Worse, the global determinism flag broke force evaluation: SlakoNet's
backward uses CuBLAS routines with no deterministic kernel, so
autograd raised and the bare `except RuntimeError` substituted
torch.zeros_like(). Any optimizer then reported instant convergence
with nothing moved. It also broke unrelated calculators sharing the
process - running alignn_ff and SlakoNet in one chipsff run made
SlakoNet return exactly zero forces, silently.

Changes:
- Move the flags into an opt-in set_debug_mode(); honour SLAKONET_DEBUG.
- Add create_graph (default False) to SimpleDftb. Only force-matching
  training needs a graph through the gradients.
- Wrap SimpleDftb.calculate in allow_nondeterministic() so SlakoNet
  still works if another library enables determinism, restoring the
  caller's setting afterwards.
- Never substitute zero forces on failure; raise with a diagnostic.

Forces and stress are unchanged (bit-identical) and still match finite
differences; 3C-SiC bandgap unchanged at 2.0995 eV.
A single fixed kpoints_array cannot serve cells that range from 2-atom
bulk to defect supercells to slabs. On ideal diamond Si, where symmetry
requires zero forces, the residual is:

  1x1x1  2.373 eV/Ang
  2x2x2  0.449
  4x4x4  0.042
  6x6x6  0.005

so a mesh chosen for a 64-atom supercell leaves spurious forces an order
of magnitude above a typical fmax=0.05 relaxation criterion.

kpoints_for() now derives the mesh from the reciprocal cell,
n_i = ceil(|b_i| / kspacing), with a single k-point along non-periodic
directions. kspacing=0.30 gives [7,7,7] for primitive Si, [2,2,2] for a
64-atom supercell and [4,4,1] for a slab, dropping Fmax to 0.0016.
kpoints_array is still honoured when kspacing is None.
DEFAULT_MODEL_NAME kept slakonet_v1 from the upstream rebase; v1a is the
current parameter set. SLAKONET_MODEL still overrides it.
SlakoNetCalculator (main.py) had only get_bandgap/get_fermi_energy;
SlaKoNetCalculator (ase_calc.py) had band_structure/dos but no HS
accessor. Both now expose the same three methods, with
get_bandstructure/get_dos on ase_calc as aliases of the existing
band_structure/dos.

get_HS returns (H, S) reshaped to (n_kpoints, n_orbitals, n_orbitals);
SimpleDftb stores them as (batch, n_orb, n_orb, n_k), which is awkward
to index per k-point. H is in Hartree, not eV, and the basis is
non-orthogonal, so the docstrings spell out the generalized eigenproblem
needed to recover band energies. Verified: eigh(H[k], S[k]) * 27.211
minus E_F reproduces the calculator's eigenvalues exactly, and H and S
are Hermitian at every k.

Also hoist the FilteredModel wrapper out of _run_calc_with_filtered_skfs
to module scope so the new methods can reuse it.
The test suite had no calculator coverage at all. test_ase_calculators
adds 11 tests over both calculator classes, checking forces and stress
against finite differences of the model's own energy rather than only
that the calls return something -- that is the check that catches the
unit and sign errors fixed earlier. Also covers get_dos,
get_bandstructure, get_HS (shape, hermiticity, and that
eigh(H,S)*27.211 - E_F reproduces the eigenvalues), kspacing mesh
selection, agreement between the two calculator classes, and SKF
re-filtering when the elements change.

README: the 'Using Pretrained Models in Python' example raised
KeyError: 'band_gap_eV' -- the keys are 'bandgap' and 'fermi_energy',
and both are tensors. generate_shell_dict_upto_Z65 also needs model=.
Document get_HS, including that H is in Hartree and needs the
generalized eigenproblem. All four README python blocks now execute.
README: condense the abstract to the key claims, drop the Applications
section and the Output Properties duplication, and add the dense-vs-
sparse scaling table. Key Features said 'up to 2000 atoms', which the
table contradicts; now says >10,000 with the sparse solver. Installation
instructions kept as they were.

Formatting: black -l 79 over the files touched in this branch. flake8
with the CI selection (E9,F63,F7,F82) reports 0; no line over 79 chars
was introduced.
Replace the plain 'Open in Colab' text link with the standard
colab-badge.svg image wrapped in the same link, so the badge itself
opens the notebook.
@knc6
knc6 merged commit 6455957 into main Aug 6, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant