Skip to content

Feat: database improvements#301

Merged
martin-schlipf merged 12 commits into
masterfrom
feature/database-improvements
Jul 10, 2026
Merged

Feat: database improvements#301
martin-schlipf merged 12 commits into
masterfrom
feature/database-improvements

Conversation

@martin-schlipf

Copy link
Copy Markdown
Collaborator

Summary

Rework the database payload produced by Calculation._to_database(): reorganize it
into a nested structure, fold sub-quantities into their parents, and fill in several
per-quantity summaries that were previously empty or missing.

Motivation

The database payload is consumed by the external writer (vaspdb). Previously every
quantity — including sub-components that only make sense as part of a larger quantity
(stoichiometry, dispersion) — was a sibling top-level key, and several quantities
emitted no content at all. This PR gives the payload one entry per user-facing quantity,
richer content, and a more consistent shape.

What changed

Payload shape (breaking for consumers of properties)

  • properties is now a dict of dicts: {quantity: {selection: model}}. The outer
    key is the quantity name (leading underscores stripped; group members as
    group_quantity, e.g. phonon_mode); the inner dict is keyed by selection with the
    default source keyed default.

Sub-quantities folded into parents

  • stoichiometry is folded into Structure_DB; dispersion into Band_DB and a new
    PhononBand_DB. stoichiometry/dispersion no longer appear as standalone top-level
    entries. (cell was already folded into Structure_DB.)

Structure: separate initial/final geometries

  • The structure entry is split into per-geometry models: a final geometry (always) and
    an initial geometry (only when it differs from final), plus any other source that
    differs from both. Geometries are compared by lattice vectors and positions.
  • Structure_DB geometry fields lost their initial_/final_ prefixes — each model now
    describes a single geometry (cell_volume, lattice_vector_1, angle_alpha, …).

New / richer per-quantity content

  • Pair correlation: first_peak_position and first_peak_height of the total g(r)
    (first local maximum above the ideal-gas baseline, so sub-threshold shoulders are
    ignored).
  • Current density: CurrentDensity_DB with the grid shape and min/max/mean of the
    current-density magnitude (was an empty stub).
  • Phonon band: PhononBand_DB with the phonon frequency range (was an empty stub).
  • Stoichiometry: ion counts (num_ion_types and the primitive reduction) are kept
    even when element names are absent (formula/compound stay None).

Robustness

  • write._write_dataset now skips a field whose schema source defines no path for it,
    instead of crashing when the raw data supplies a value (fixes writing the ionic()
    dielectric demo through the ion source).

Notes for vaspdb

  • properties consumers must handle the nested {quantity: {selection: model}} shape,
    the removal of standalone stoichiometry/dispersion keys, and the Structure_DB
    field rename (no initial_/final_ prefixes; separate initial/final models).

Change Calculation._to_database properties from a flat dict keyed by
`quantity`/`quantity_selection` to a nested `{quantity: {selection: model}}`
mapping. The outer key is the quantity name (with leading underscores
stripped); the inner dict is keyed by selection with the default source
keyed `default`.

merge_to_database now returns the nested shape and _collect_to_database
merges per quantity. Updates the dispatcher/handler tests and the
_DatabaseData docstring accordingly.
Stoichiometry data is now folded field-wise into Structure_DB, and
dispersion (eigenvalue range) into Band_DB. A new PhononBand_DB holds the
phonon dispersion frequency range for phonon_band (previously empty).

The Dispersion and Stoichiometry dispatchers no longer expose a
`_to_database`, so they are no longer collected as standalone top-level
properties; their handler `to_database` remains and is called by the parent
handlers. This mirrors how cell data is already folded into Structure_DB.
Replace the generic merge for the structure database entry with a custom
merge that stores the final structure always, the initial structure (first
ionic step of the default trajectory) only when it differs from the final
one, and any other source only when it differs from both. Geometries are
compared by lattice vectors and positions, so fixed-cell relaxations are
still detected as distinct.

StructureHandler.to_database now accepts a steps argument so a single
geometry can be described; each emitted model is built from one step.
Add first_peak_position and first_peak_height to PairCorrelation_DB. The
handler scans the existing sample points of the total g(r) for the first
strict local maximum above an absolute threshold (the ideal-gas baseline of
1.0), so small bumps before the first shell are ignored. Both fields are None
when no such peak exists.
Adapt tests/regression/test_manual.py to the new _to_database contract. It
resolves each legacy reference key to the nested (quantity, selection) lookup,
compares only the fields the reference actually set (so fields added by the
port are not flagged as changed), and treats the intended changes as
documented exceptions:

  - stoichiometry and dispersion are folded into parents -> asserted absent
    from the top level;
  - the structure entry is split, so only the final geometry is compared
    (initial_* is now a separate model covered by the unit tests);
  - kpoint stays top-level (phonon exposes it under the phonon selection).

Reference pickles are located via PY4VASP_REGRESSION_DIR (default work/examples)
and the cases skip when they are absent. Result on the port: 70 passed.
…elds

Structure_DB now describes a single geometry with unprefixed fields
(cell_volume, lattice_vector_*, angle_*, ...). The initial/final distinction
is expressed solely by the two models in the structure entry
({"final": ..., "initial": ...}) rather than by prefixed fields packed into
one object. StructureHandler.to_database builds one geometry for the selected
step (default: the final step).

Updates the structure unit test to the unprefixed single-geometry model and
the regression comparison to match legacy final_*/initial_* fields against the
corresponding split models.
Reformat the files touched by this branch with black (slice-colon spacing and
line wrapping). No behavioral changes; isort reports no import changes.
CurrentDensityHandler.to_database() previously returned an empty {}. It now
returns a CurrentDensity_DB carrying the grid shape and the min/max/mean of the
current-density magnitude |j| aggregated over all grid points and perturbations.
get_formula_and_compound previously returned all None whenever the element
names were missing, discarding the ion counts that were still available. It now
keeps num_ion_types (and the primitive reduction) in that case; only the
name-derived formula, compound, and unique-type list stay None. A structure
without ion-type names therefore still records its ion counts (folded into
Structure_DB).
write._write_dataset now skips any field whose schema target is unset
(check.is_none) even when the raw data supplies a value: a source that defines
no path for a field simply does not store it. Previously the unset
VaspData(None) target was passed to h5py as a key, crashing with "A name
should be string or bytes, not VaspData" when writing the ionic() dielectric
demo through the "ion" source (which has no q_point path).

Re-enables the dielectric_function/ionic/ion regression case.
Comment thread src/py4vasp/_calculation/structure.py Dismissed
Comment thread src/py4vasp/_calculation/structure.py Dismissed
@martin-schlipf martin-schlipf enabled auto-merge (squash) July 10, 2026 09:19
@martin-schlipf martin-schlipf merged commit 6ed538f into master Jul 10, 2026
29 checks passed
@martin-schlipf martin-schlipf deleted the feature/database-improvements branch July 10, 2026 09:25
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