Parameter validation (custom models)¶
OpenPFC encourages fail-fast configuration: invalid or missing parameters should be caught at startup, not hours into a run. The machinery lives in the frontend UI layer and is optional—your Model can ignore it or adopt it fully.
Building blocks¶
Piece |
Header |
Role |
|---|---|---|
|
|
Describes one parameter: name, range, units, required, typical value. |
|
|
Aggregates metadata, |
|
Your translation unit |
Used by the default spectral |
Value-returning helpers (ParameterValidator::validate, ValidationResult::{is_valid,format_errors,format_summary}, ParameterMetadata::validate / format_info, and ParameterMetadata::Builder::build) are marked [[nodiscard]] so ignoring validation output is typically a compile-time error.
Validation is typically invoked from application main or a thin wrapper before the expensive App::main() path, or integrated inside your app’s settings loader if you have one.
Validation vs. App parsing order¶
ParameterValidator and the default spectral pipeline both read the model.params JSON object, but they are separate layers:
Layer |
When |
Responsibility |
|---|---|---|
Optional validation |
In your code, after loading the config and before |
Fail fast on missing keys, bad types, or out-of-range values using metadata you register on |
Library |
Inside |
Copies JSON fields into your model’s parameter struct via your |
Wiring |
After initialization |
|
The framework never calls ParameterValidator for you. If you validate in main and then call app.main(), validation runs first; the library still applies from_json so your model receives the parsed values. Keep validator metadata and from_json field names in sync to avoid rejecting configs that would parse, or accepting configs that from_json would mis-handle.
Pattern¶
Declare metadata for each scalar (or structured) parameter your model reads from
model.params.Call
validator.validate(config["model"]["params"])(or thejsonsubtree you store parameters in).If
!result.is_valid(), printresult.format_errors()and exit.Optionally print
result.format_summary()for reproducibility (see rootREADME.md— Configuration Validation).
Minimal sketch (matches the root README.md snippet; headers live under openpfc/frontend/ui/):
#include <cstdlib>
#include <iostream>
#include <openpfc/frontend/ui/parameter_metadata.hpp>
#include <openpfc/frontend/ui/parameter_validator.hpp>
void validate_my_params(const pfc::ui::json &root) {
pfc::ui::ParameterValidator validator;
validator.add_metadata(
pfc::ui::ParameterMetadata<double>::builder()
.name("temperature")
.description("Effective temperature")
.required(true)
.range(0.0, 10000.0)
.typical(3300.0)
.units("K")
.build());
const pfc::ui::json ¶ms = root["model"]["params"];
auto result = validator.validate(params);
if (!result.is_valid()) {
std::cerr << result.format_errors() << '\n';
std::exit(1);
}
if (/* rank 0 */) {
std::cout << result.format_summary() << '\n';
}
}
Call this from main after loading the config file and before App::main() if you want validation outside the library; many apps instead fold validation into the same code path that parses model.params.
Reference implementation¶
apps/tungsten/include/tungsten/common/tungsten_input.hpp (and related) registers many parameters with ranges and descriptions—use it as the full example.
Smaller programs may only validate 3–5 critical scalars; you can still use the same ParameterMetadata<double>::builder() pattern as in the root README.md snippet.
Documentation elsewhere¶
Root
README.md— user-facing description of validation output and benefits.app_pipeline.md— whenmodel.paramsis applied relative toApp::main().
See also¶
tutorials/custom_app_minimal.md— minimalApptutorialstyleguide.md— API and header conventions