Repository navigation
Ladder fit silently keeps the initial potential's rcut and ignores bonds::rcut from input.yaml #105
Description
When initial_potential is combined with a potential specification whose bonds::rcut differs from the initial potential's, the initial value silently wins. The fitted potential then has a cutoff the user never asked for, and nothing warns or raises.
This was found by reading the code — the test suite was not run — so please sanity-check the reproduction before acting on it.
Mechanism
extend_basis_block() in src/pyace/multispecies_basisextension.py:934 starts from the initial block:
extended_block = init_block.copy()Every block that exists in the initial potential therefore keeps all of the initial block's radial parameters — rcutij, dcutij, radbase, radparameters, r_in, delta_in — and only receives the target's function specifications grafted on. The target's radial parameters are never applied. The only assertion in that function (line 909) compares block_name; nothing compares the radial basis.
ACEBBasisSet then builds map_bond_specifications exclusively from blocks with number_of_species <= 2 (lib/ace/src/ace/ace_b_basis.cpp:975) and sets
radial_functions->cut(ele_i, ele_j) = bondSpecification.rcut; // ace_b_basis.cpp:1023so the pair block's value — inherited from the initial potential — is what the evaluator actually uses.
Why nothing catches it
- Mixed
rcutwithin one configuration. Blocks present in the initial potential keep its value (:934); blocks that exist only in the target are created fresh atmultispecies_basisextension.py:1122fromf_block.copy()and keep the target's. So an extended configuration can holdAl Alat 7 Å andAl Al Alat 5 Å. The higher-rank block'srcutijis skipped for bond specifications by thecontinueatace_b_basis.cpp:975, but still counts towardcutoffmaxat:890, which is unfiltered. Input::check_radial_basis_consistency— the one function that compares these fields — is called from a single place,lib/ace/src/ace/ace_yaml_input.cpp:331, during YAML file parsing, and only between a pair block and its reversed dual (Al NivsNi Al). It never runs on configurations assembled in memory by the ladder.BBasisConfiguration::validate(ace_b_basis.cpp:1312) only tries to construct anACEBBasisSet; that constructor's consistency check (:1009-1017) compares(i,j)against(j,i), both inherited from the same block, so it always passes.
The same override happens outside ladder fitting through the overwrite_blocks_from_initial_bbasis branch at multispecies_basisextension.py:352-358, which replaces generated blocks with the initial ones wholesale.
Reproduction
- Fit any potential with
bonds: {ALL: {rcut: 7, ...}}and keepoutput_potential.yaml. - Write a new
input.yamlwithbonds: {ALL: {rcut: 5, ...}},potential::initial_potential: output_potential.yamland afit::ladder_step. - Run
pacemaker. The resulting potential hasrcutij: 7, not 5.
A third symptom is worth noting: generalfit.py:256 writes target_potential.yaml carrying rcut: 5, while the fit and the final output potential use 7. The two files on disk disagree and neither says so.
Suggested fix
docs/pacemaker/faq.md:165 already states the rule:
If you change cutoff, i.e. from
rcut: 7torcut: 6.5, then potential should be refitted from the scratch.
That is the right behaviour — an initial potential's coefficients are meaningless at a different cutoff, so this is not recoverable by picking one of the two values. The documentation states the rule; the code just does not enforce it. A check next to the existing block_name assertion at multispecies_basisextension.py:909, comparing init_block against final_block and raising with the block name and both values, would cover it.
One trap for whoever implements it: do not reuse check_radial_basis_consistency's full field list. It also compares lmaxi, nradmaxi, nradbaseij and radcoefficients, and those are supposed to grow from initial to target — that is the point of the ladder (validate_radial_shape_from_funcs at :944 recomputes them, merge_crad_matrix at :949 merges the coefficients). Only the shape-independent parameters must match: rcutij, dcutij, radbase, radparameters, r_in, delta_in, inner_cutoff_type.
Found while investigating the top-level cutoff parameter (see #104), but independent of it.
Activity