Repository navigation
feat(input): validate integer choices from shared parameter metadata - #8192
Draft
Stardust0831 wants to merge 2 commits into
Draft
Stardust0831 wants to merge 2 commits into
Stardust0831 wants to merge 2 commits into
Conversation
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linked Issue
Related to #7719. That issue tracks software silently changing parameters explicitly supplied by the user. The intended policy is to reject invalid explicit input with actionable diagnostics and legal values, while allowing contextual defaults for omitted parameters. Valid explicit input must take precedence over defaults.
What's changed?
Introduce a general, reusable INPUT validation mechanism, starting with scalar integer choices. Each
Input_Itemdeclares its legal values and a typed, read-only field binding. The shared engine handles complete-token validation, checking effective values, and consistent diagnostics with legal choices and parameter-specific manual links. The same declaration also drivesabacus -h, YAML export and generated Allowed values documentation.Other scalar integer-choice parameters can reuse this mechanism by declaring their field binding and allowed choices. The validator has no parameter-name branches or per-parameter validation callbacks.
nspinandgga_gradare the first two registrations of this shared mechanism; more parameters can migrate incrementally, and additional rule types can extend the common operators.Migrate
nspin(1, 2, 4) andgga_grad(0, 1, 2) to this shared path. For example,nspin 2abcpreviously became2; it now fails with the supplied value, legal choices and a link to the relevant manual section. Extra tokens, overflow and missing values also produce errors. A final migrated keyword without a value is no longer overlooked. Unmigrated parameters retain their existing handling of empty strings, empty vectors and EOF; missing-value rules must come from the declared domain.One
prepare_inputcall validates explicit domains before readers/default hooks, runs existing input preparation, then validates effective domains including defaults. Independent domain errors are collected and broadcast before all MPI ranks stop. Normal startup and--check-inputshare this path. Legal explicit values, includinggga_grad 0, and existing contextual defaults are preserved for the migrated parameters.This is the first infrastructure slice, not a claim that all reset behavior in #7719 is fixed. Existing dependency checks remain, including the
nspin=4requirement withnoncolin/lspinorb. Replacing arbitrary reset callbacks with defaults that only fill omitted fields, conditional rules, ranges and other domain types are later migrations. A legacy reset from one legal value to another is not detected by this first domain-only implementation. The existinggamma_onlyconvenience behavior is unchanged.Validation flow
Previously, readers and reset hooks ran before each parameter's
check_valuecallback, where legal-value and dependency checks were mixed together. The two diagrams below form one execution sequence. Green = new shared domain checks; red = stop. Domain checks apply only to declared domains, currentlynspinandgga_grad.1. Check explicit input, then prepare parameter values
flowchart LR A["INPUT<br/>raw tokens"] --> B{"Explicit<br/>domain valid?"} B -- "No" --> E["Domain error<br/>stop"] B -- "Yes / omitted" --> C["Read values<br/>defaults / reset<br/>aliases"] C --> D["Effective<br/>parameters"] classDef added fill:#e6f4ea,stroke:#237a3b,stroke-width:2px,color:#111; classDef error fill:#fff0f0,stroke:#b42318,color:#111; class B added; class E error;For a supplied domain-backed parameter, require exactly one complete integer from
allowed_values. Omitted keywords skip this token check. The preparation box uses the existing readers, default/reset hooks and alias normalization.2. Check effective values, then dependencies
flowchart LR A{"Effective<br/>domain valid?"} -- "Yes" --> B["Resolve context<br/>broadcast"] A -- "No" --> E["Domain error<br/>stop"] B --> C{"Dependencies<br/>OK?"} C -- "Yes" --> D["Run / finish<br/>check-input"] C -- "No" --> F["Existing error<br/>stop"] classDef added fill:#e6f4ea,stroke:#237a3b,stroke-width:2px,color:#111; classDef error fill:#fff0f0,stroke:#b42318,color:#111; class A added; class E,F error;The effective-value check also covers defaults for omitted parameters. Both domain checks are coordinated by
prepare_input; domain failures collect independent errors, report supplied/resolved values, legal choices and manual links, then broadcast diagnostics so all MPI ranks stop. After STRU/system context is available, the existingcheck_valuecallbacks check dependencies, conflicts and remaining legacy constraints. Their errors retain the existing reporting path.Legal values and dependencies answer different questions:
nspin 31, 2, 4gga_grad -10, 1, 2gga_gradmanual linknspin 2abc,nspin 2.0, or an overflowing integernspin 2 4nspin, including at EOF without a newlinenspin +2ornspin 022nspin 2withnoncolin 1orlspinorb 12is a legal spin modenspin=4nspin 4withnoncolin 1orlspinorb 1nspinwithnoncolin 11passes its domainnspin=4selectiongga_grad 00nspin 1withgga_grad 2nspinandgga_grad, with spin flags off1and0passOmitted keywords do not participate in the explicit-token check; their effective defaults are checked later. The default/reset box deliberately denotes the existing implementation: full isolation of explicit values from all legacy reset hooks is still pending. The documentation's
availabilityexpressions are not automatically enforced as hard dependency errors in this PR.Diagnostic format and rule review
Actual output when the same INPUT contains
nspin 3andgga_grad -1:The format identifies the input file, parameter, supplied value, legal choices and the corresponding manual section. Independent domain errors are reported together. This standard format currently covers declared-domain failures; legacy dependency errors have not been migrated to it.
The two choice sets exactly match the pre-existing guards and the published manual. The new token rules require one complete scalar integer, as documented;
+2and02remain accepted integer spellings.gga_gradapplicability is not turned into a hard prohibition: for example,nspin 1withgga_grad 2remains accepted, with its existing computational behavior. The existing implicationnoncolin || lspinorb => nspin == 4remains unchanged.Compatibility risks and automatic values
Both new domain checks run during INPUT preparation, before calculation starts. Built-in initial values already exist when the parameter object is constructed. The sequence is: validate supplied raw tokens, read explicit values and run existing default/reset hooks, then validate the values produced by that preparation. Structure/system context and the legacy dependency checks follow. The second check is not a check on every solver iteration, and some derived values are only available later.
The main compatibility change is stricter parsing for migrated parameters: an input such as
nspin 2.0,nspin 2abcornspin 2 4, previously accepted through partial parsing, now fails. Existing scripts that emit these forms must emit a scalar integer. Optional empty values for unmigrated parameters remain valid. The shared preparation code is exercised by the serial writer/reader round trip, MPI parameter tests and the full CPU/GPU CI suites. No numerical kernels are changed; the added checks run at startup.This slice uses the same integer-choice set for raw and prepared values. That is suitable for
nspinandgga_grad, which have no automatic-value sentinel. Parameters using automatic/default sentinels must not be migrated mechanically to this operator. In particular:scf_thr_type=-1andscf_thr=-1are resolved by the current reader to contextual defaultsscf_ene_thr=-1disables the extra energy-convergence criterion;nbspline=-1disables B-spline interpolationnbands=0requests automatic band selection after the electron count is knownA later shared extension should represent omitted input, an explicit automatic request and an explicit concrete value separately, and distinguish input-domain rules from resolved-value rules. Resolve defaults for omissions or a declared automatic request; preserve valid explicit concrete values, including zero/false. A documented automatic token is an instruction to derive a value. Unknown negative values must not silently become automatic requests. Defaults that require later context need an appropriate shared validation stage. These capabilities are not implemented in this first PR.
The existing reset callbacks are still a migration limitation: checking membership alone cannot detect one legal explicit value being replaced by another legal value. Likewise, the applicability descriptions are not sufficient on their own to introduce new hard rejection rules.
Unit Tests and/or Case Tests for my changes
Local builds used GCC 13.4, CPU/OpenMP,
OMP_NUM_THREADS=1, and the existing Conda numerical libraries. Built both serial and MPI executables with LCAO/LIBXC/JSON disabled.Passed:
All five CTest targets (55 individual tests) and both documentation tests passed. Full GoogleTest completion was verified. A subsequent rule audit reran the 13 domain/reader unit tests and verified 41 CLI input cases, including all nine legal spin/gradient combinations, malformed and missing tokens, default/explicit values and spin dependencies. The published manual page returned HTTP 200, and its
nspin,gga-gradandsymmetryanchors were confirmed. Tests cover complete tokens, cardinality, overflow, enum membership, typed bindings, copied metadata, errors before reset hooks, contextual defaults, existing spin dependencies, valid empty optional values and reading writer-generated INPUT files. The check-input death test now enablescheck_modeonly in its child process, so later tests finish and failures remain visible to CTest.CLI verification used
/tmp/abacus-input-domain-build/abacus_pw_omp:--version:v3.11.0-beta11.-h nspin: displaysAllowed values: 1, 2, 4.--generate-parameters-yaml, followed bypython3 docs/generate_input_main.py /tmp/abacus-input-domain-cli/parameters.yaml --output /tmp/abacus-input-domain-cli/input-main.md: both domains verified in parsed YAML and generated Markdown.--check-inputfrom an isolated copy oftests/01_PW/004_PW_UPF201_Si: omitted defaults and explicitnspin 2/gga_grad 0exit 0. Out-of-domain, malformed and missing values exit 1 with the expected diagnostics; normal startup also rejects invalid input.scf_thr_type=-1,scf_thr=-1,scf_ene_thr=-1,nbspline=-1,search_radius=-1andnbands=0passed both--check-inputand normal SCF.INPUT.inforecords prepared values1,1e-9,-1,-1,-1,0; the running log records automaticNBANDS=14and completed SCF. This PW check confirms that the input reader accepts the legacy values; it does not exercise LCAO search-radius resolution.MPI verification:
The focused test passed on both ranks. The isolated Si case completed SCF and exited 0. A follow-up two-rank Si SCF also completed with empty
out_pchganddfpt_qfile. Combinednspin 3/gga_grad -1and barenspinat EOF exited 1 with diagnostics, within a 30-second timeout. The existing MPI--check-inputpath prints success but callsexit(0)without finalization, so OpenMPI reports improper termination; this pre-existing behavior was not changed.git diff --checkandpython3 tools/03_code_analysis/agent_governance_check.py --stagedpassed. The initial infrastructure commit had three header-include review warnings, explained below; the compatibility follow-up had no governance findings.Governance Notes
InputDomainneeds standard string/vector declarations and owns its vector;Input_Itemowns a domain by value and therefore needs the complete type.Input_parais forward-declared in the domain header.