Fix BEC NaN handling for structures without target data in read_structures
Problem
read_structures is supposed to replace zeros with NaN for Born effective charge (BEC) data when a structure has no BEC targets — GPUMD writes zeros in bec_*.out as a placeholder in that
case. The detection code was broken in three ways:
- Wrong dict: the condition checked
s.info['bec_target'], but BEC is now per-atom data stored viastructure.new_array(...)ins.arrays['bec_target'](!220 (merged)). The condition never fired, so placeholder zeros were silently passed through as real data. - Fragile heuristic: even if the dict were correct,
np.allclose(..., 0)would misidentify a structure whose BEC values happen to be all zero. The reliable signal is'bec' not in s.arrays— the presence of abecarray in the source xyz file is what indicates that target BEC data was actually provided. - Incomplete replacement: only
bec_targetwas beingNaN-ed;bec_predicted(also zeros for untargeted structures) was left as-is.
The same three issues affected the tests: the setup used structure.info to carry the BEC signal, and the assertions looked in s_read.info rather than s_read.arrays.
Changes
calorine/nep/io.py — replace the NaN-replacement block with a corrected version that checks s.arrays, uses 'bec' not in s.arrays for detection, and NaN-s both bec_target and
bec_predicted.
tests/test_nep_io.py — two fixes in set_up_output_for_testing and test_read_structures_potential:
- Set
structure.arrays['bec'] = becs(instead of onlydata['bec_target'] = becs) for structures that have BEC target data, so the detection signal is present in the written xyz. - Update the assertion loop to skip
bec_target/bec_predictedin thes.infopass and check them separately vias_read.arrays, branching on'bec' not in s_ref.arraysto verify NaN vs. real values.