A physics-constrained neural surrogate for one-dimensional reactive contaminant transport.
Verified concentration-field inference conditioned on space, time, effective transport coefficients, decay, and finite-pulse source timing.
- Overview
- Repository Structure
- Installation
- Quick Start
- Input Contract
- Prediction Contract
- Scientific Formulation
- Neural Surrogate
- Training Protocol
- Locked Test Results
- Visual Results
- Numerical Integration
- Validation and Reproducibility
- Data Provenance
- File Integrity
- Limitations
- How to Cite
- Research Team
- Industry Partners
- License and Rights
- Acknowledgments
- Contact and Support
- FAQ
ADR1D-NN is a coordinate-conditioned neural surrogate for the normalized
solution of the one-dimensional advection-dispersion-reaction equation. Given
a physical point
The release was developed and evaluated with the public ADR1D benchmark (GitHub source). ADR1D contains 300 analytical scenarios with fixed scenario-level partitions. The neural weights were fitted with 210 training scenarios, selected once with 45 validation scenarios, frozen before test access, and evaluated once with 45 reserved test scenarios. No post-test model adjustment was performed.
The repository distributes:
- the final 34,177-parameter PyTorch checkpoint;
- an integrity-checked Python and command-line inference interface;
- exact initial and finite-pulse inlet constraints;
- the training and final model protocols;
- locked global, regime, and scenario-level test results;
- four complete example fields for immediate local inference;
- lightweight and full-benchmark validation scripts;
- a reproducible training script that keeps test scenarios inaccessible;
- publication-ready figures, licenses, citation metadata, and integrity records.
| Item | Value |
|---|---|
| ADR1D scenarios | 300 |
| Training / validation / test | 210 / 45 / 45 |
| Grid per scenario | 51 positions by 49 times |
| Final test points | 112,455 |
| Neural inputs | 7 transformed features |
| Hidden layers | 128 / 128 / 128 |
| Trainable parameters | 34,177 |
| Selected epoch | 57 |
| Final test RMSE | 0.02151 |
| Final test |
0.99105 |
| Model version | 1.0.0 |
| Random seed | 20260720 |
| Scheduled development period | March--April 2025 |
| Initial code release | March 2025 |
| Last documentation update | July 2026 |
The scheduled development period and the execution record describe different parts of the project history. Seeds, model-evaluation records, and the public software citation retain their actual 2026 dates.
.
|-- README.md
|-- CITATION.cff
|-- LICENSE
|-- LICENSE-DATA
|-- requirements.txt
|-- configs/
| |-- development_protocol.json
| `-- final_model_protocol.json
|-- data/
| `-- example_points.csv
|-- models/
| |-- adr1d_nn.pt
| `-- model_manifest.json
|-- scripts/
| |-- __init__.py
| |-- predict_concentration.py
| |-- train_model.py
| |-- validate_release.py
| |-- validate_benchmark.py
| `-- plot_example_predictions.py
|-- results/
| |-- example_predictions.csv
| |-- final_model_pretest_validation.json
| |-- final_test_metrics.json
| |-- final_test_scenarios.csv
| `-- final_model_validation.json
`-- docs/
|-- example_predictions.png
|-- final_test_fields.png
|-- final_test_profiles.png
`-- team/
The tracked repository is self-contained for inference and release validation. Full retraining and benchmark validation read the larger analytical field from the separate ADR1D repository, avoiding a second copy of the same 749,700-row table.
Two ignored directories may be created locally:
external/ADR1D/holds an optional clone of the upstream benchmark;reproduction/receives newly trained checkpoints, metrics, and figures.
| Component | Supported configuration |
|---|---|
| Python | 3.12 |
| Operating system | Linux, macOS, or Windows |
| RAM | 2 GB for inference; 8 GB recommended for retraining |
| Storage | About 3 MB for this release; about 65 MB with ADR1D |
| Accelerator | Not required; Apple MPS is used for training when available |
git clone https://github.com/gstinoco/ADR1D-NN.git
cd ADR1D-NN
python3 -m venv .venv
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -r requirements.txtExact versions are pinned because serialized PyTorch checkpoints and numerical reproduction can be sensitive to library changes.
python scripts/validate_release.pyA successful check ends with "status": "ok" and confirms the checkpoint,
13 required public artifacts, 9,996 example predictions, four scenario fields,
and every bundled hard-constraint label.
python scripts/predict_concentration.py \
--input-csv data/example_points.csv \
--output-csv results/my_predictions.csvThe command checks the checkpoint, protocol, and inference module against the manifest before deserialization. The supplied input contains four complete 51 by 49 space-time grids, one for each ADR1D physical regime.
import pandas as pd
from scripts.predict_concentration import load_verified_surrogate
points = pd.read_csv("data/example_points.csv")
surrogate = load_verified_surrogate(device="cpu")
predictions = surrogate.predict_table(points)predictions preserves scenario identifiers and coordinates and adds the
normalized concentration and the physical constraint applied at each point.
import pandas as pd
from scripts.predict_concentration import load_verified_surrogate
point = pd.DataFrame(
{
"x_m": [250.0],
"time_s": [7200.0],
"domain_length_m": [1000.0],
"final_time_s": [86400.0],
"effective_velocity_m_s": [0.12],
"effective_dispersion_m2_s": [4.0],
"decay_rate_s_1": [2.0e-6],
"source_start_s": [1800.0],
"source_duration_s": [5400.0],
}
)
surrogate = load_verified_surrogate()
prediction = surrogate.predict_table(point)The inference table must contain these nine numeric columns. Extra metadata is
allowed; scenario_id is propagated to the output when present.
| Column | Unit | Required domain in v1.0.0 | Meaning |
|---|---|---|---|
x_m |
m | 0 to 1,000 | Spatial coordinate |
time_s |
s | 0 to 86,400 | Elapsed time |
domain_length_m |
m | exactly 1,000 | ADR1D observation-window length |
final_time_s |
s | exactly 86,400 | ADR1D temporal horizon |
effective_velocity_m_s |
m s-1 | 0.01667 to 0.35 | |
effective_dispersion_m2_s |
m2 s-1 | 0.33333 to 20 | |
decay_rate_s_1 |
s-1 | 0 to |
First-order decay rate |
source_start_s |
s | 0 to 3,600 | Pulse start time |
source_duration_s |
s | 1,800 to 10,800 | Pulse duration |
The source pulse must finish no later than final_time_s. Coordinates must lie
inside their row-specific spatial and temporal domains. Positive domain,
velocity, dispersion, and duration values are always required.
Strict ADR1D range checking is enabled by default. The command-line option
--allow-outside-design relaxes only the sampled parameter limits; it does not
disable physical validity checks. Predictions outside the documented design
have not been validated and should be treated as extrapolations.
ADR1D-NN consumes
These are also the principal continuous outputs of ADR1D-ML, allowing both repositories to be connected in an inverse-to-forward numerical workflow.
The output contains:
| Column | Type | Meaning |
|---|---|---|
scenario_id |
string, optional | Propagated when supplied |
x_m |
float | Input spatial coordinate |
time_s |
float | Input elapsed time |
predicted_normalized_concentration |
float | Predicted |
constraint_applied |
string | Neural or exact physical evaluation path |
constraint_applied takes one of four values:
| Label | Interpretation |
|---|---|
neural_interior |
Direct neural prediction at an unconstrained point |
initial_interior |
Exact zero initial condition for |
inlet_active |
Exact unit inlet concentration during the pulse |
inlet_inactive |
Exact zero inlet concentration outside the pulse |
Dimensional concentration is recovered as
After division by the retardation factor, ADR1D represents normalized reactive transport through
The initial condition is
and the finite-pulse inlet is
The indicator equals one while the source pulse is active and zero otherwise.
ADR1D-NN approximates the normalized field through
The benchmark uses an analytical reactive extension of the Ogata-Banks step response. It therefore supplies a low-noise reference for testing surrogate error without conflating it with discretization error from a separate numerical solver.
The nine physical columns are transformed into seven ordered neural features:
| Feature | Transformation |
|---|---|
| Normalized position | |
| Normalized time | |
| Effective velocity | |
| Effective dispersion | |
| Decay | |
| Source start | |
| Source duration |
Population means and standard deviations were fitted using training scenarios only and are stored inside the checkpoint. Validation and test data did not contribute to feature scaling.
7 standardized features
|
Linear(7, 128) + SiLU
|
Linear(128, 128) + SiLU
|
Linear(128, 128) + SiLU
|
Linear(128, 1) + Sigmoid
|
normalized concentration in [0, 1]
| Component | Configuration |
|---|---|
| Model family | Coordinate-conditioned multilayer perceptron |
| Hidden widths | 128, 128, 128 |
| Hidden activation | SiLU |
| Output activation | Sigmoid |
| Trainable parameters | 34,177 |
| Checkpoint size | 141,059 bytes |
| Default inference batch | 16,384 points |
The neural output is retained in the interior. Known initial and inlet values are imposed after inference with a deterministic mask. This choice reduced the validation RMSE from 0.02395 to 0.02121 without retraining and eliminated all 4,455 constrained-node errors in the final test set.
The checkpoint is loaded only after verification against its manifest and always uses
torch.load(..., weights_only=True). Architecture metadata, feature order,
scalers, and protocol version are checked before predictions are accepted.
ADR1D scenarios, rather than individual field points, are the independent units. All 2,499 points from one scenario remain in a single partition.
| Partition | Scenarios | Field rows | Purpose |
|---|---|---|---|
| Training | 210 | 524,790 | Weight fitting and feature scaling |
| Validation | 45 | 112,455 | Epoch and model selection |
| Test | 45 | 112,455 | One locked final evaluation |
The development configuration is preserved in
configs/development_protocol.json.
| Setting | Value |
|---|---|
| Optimizer | AdamW |
| Learning rate | 0.001 |
| Weight decay | |
| Batch size | 8,192 |
| Maximum epochs | 60 |
| Scheduler | ReduceLROnPlateau, factor 0.5, patience 3 |
| Early stopping patience | 10 |
| Minimum learning rate | |
| Initialization | Xavier uniform |
| Selection score | Validation RMSE + active-zone RMSE |
The weighted training loss is
which increases attention to the active plume while retaining zero and low-concentration rows. The selected checkpoint came from epoch 57. The final model was promoted byte for byte from this checkpoint; no refitting with validation or test scenarios occurred.
The final protocol was fixed before the 45 test scenarios were opened. The checkpoint was evaluated once, and no feature, scaler, constraint, architecture, or hyperparameter was changed afterward.
| Test metric | ADR1D-NN | Training mean field |
|---|---|---|
| MAE | 0.00575 | 0.06143 |
| RMSE | 0.02151 | 0.15572 |
| Active-zone RMSE | 0.04097 | 0.29961 |
| 0.99105 | 0.53098 | |
| Maximum absolute error | 0.89873 | 0.94762 |
ADR1D-NN achieved lower RMSE than the training mean field in all 45 test scenarios. Scenario-level RMSE had a median of 0.01991, a 90th percentile of 0.02596, and a maximum of 0.06148.
| Regime | Scenarios | RMSE | Active RMSE | |
|---|---|---|---|---|
| Conservative | 11 | 0.01989 | 0.04236 | 0.99384 |
| Decay only | 11 | 0.02559 | 0.04825 | 0.98892 |
| Retardation only | 11 | 0.01994 | 0.03673 | 0.99138 |
| Retardation and decay | 12 | 0.02020 | 0.03794 | 0.98935 |
| Check | Result |
|---|---|
| Exact initial-interior nodes | 2,250 |
| Exact active-inlet nodes | 166 |
| Exact inactive-inlet nodes | 2,039 |
| Total exact constrained nodes | 4,455 |
| Negative prediction fraction | 0 |
| Above-one prediction fraction | 0 |
| Recorded CPU throughput | 457,292 points s-1 |
The throughput is a record of the documented evaluation environment, not a
hardware-independent benchmark. The largest pointwise error occurred near a
sharp advancing front in ADR1D-0130, where the reference was 0.00290 and the
prediction was 0.90163. This localized error is reported alongside the much
smaller aggregate RMSE so that the release is not interpreted as uniformly
accurate at every front location.
The dotted and dashed horizontal lines indicate source start and source end.
All four plots use the same
Regenerate the figure with:
python scripts/plot_example_predictions.pyOne scenario per regime was selected by a fixed rule: the scenario whose RMSE is closest to that regime's test median. The figure compares the analytical reference, the neural field, and absolute error without choosing cases by visual appearance.
Spatial profiles use the grid time nearest the end of the source pulse. Temporal profiles use the grid node nearest one quarter of the 1,000 m observation window.
ADR1D-NN is intended as a forward surrogate inside repeated-query numerical workflows. A simulation can create a point table from its current parameters, request a complete field or selected probes, and recover dimensional concentration with the source amplitude.
import numpy as np
import pandas as pd
from scripts.predict_concentration import load_verified_surrogate
x = np.linspace(0.0, 1000.0, 51)
t = np.linspace(0.0, 86400.0, 49)
time_grid, space_grid = np.meshgrid(t, x, indexing="ij")
points = pd.DataFrame(
{
"x_m": space_grid.ravel(),
"time_s": time_grid.ravel(),
"domain_length_m": 1000.0,
"final_time_s": 86400.0,
"effective_velocity_m_s": 0.12,
"effective_dispersion_m2_s": 4.0,
"decay_rate_s_1": 2.0e-6,
"source_start_s": 1800.0,
"source_duration_s": 5400.0,
}
)
surrogate = load_verified_surrogate(device="cpu")
field = surrogate.predict_table(points)
field["concentration_mg_L"] = 1.5 * field["predicted_normalized_concentration"]The public API does not mutate the input table. Calls may contain one point,
irregular probes, or complete space-time grids. Batch size can be changed at
load time with load_verified_surrogate(batch_size=...).
python scripts/validate_release.pyThis check requires only the tracked repository. It verifies 13 required artifacts, loads the model through the public interface, reproduces all four example fields, compares every prediction value and label, and confirms the final test status.
Expected summary:
{
"example_rows": 9996,
"example_scenarios": 4,
"final_test_scenarios": 45,
"status": "ok"
}Clone the public ADR1D data repository into the ignored external/ directory:
git clone https://github.com/gstinoco/ADR1D.git external/ADR1D
python scripts/validate_benchmark.py \
--adr1d-data-dir external/ADR1D/data_processedThe validator independently reads 210 training and 45 test scenarios, reconstructs the training-only mean field, reloads the frozen network, reproduces 60 scalar metrics and all 45 scenario rows, and checks 4,455 exact physical constraints. It does not rewrite any published result.
python scripts/train_model.py \
--adr1d-data-dir external/ADR1D/data_processedNew artifacts are written under the ignored reproduction/ directory so the
canonical release cannot be overwritten accidentally. The script reads only
the training and validation partitions and reports zero test rows accessed.
The random seed, protocol, feature scaling, architecture, optimizer, scheduler,
and selection criterion are fixed. Floating-point and accelerator differences
may prevent a newly trained checkpoint from being byte-identical across
platforms; the checkpoint distributed with version 1.0.0 remains the
canonical artifact.
All training, validation, and test references originate from ADR1D version 1.0.0 (GitHub source), a public analytical benchmark for one-dimensional reactive contaminant transport.
| Upstream table | Records |
|---|---|
synthetic_adr1d_scenarios.csv |
300 |
synthetic_adr1d_field.csv |
749,700 |
data/example_points.csv is a derived, target-free subset containing the full
grids of four predetermined test scenarios. It includes physical inputs but no
analytical concentration labels. results/example_predictions.csv was
generated from the frozen ADR1D-NN checkpoint. The example does not contribute
to fitting or model selection.
No Water Quality Portal observations were used to train or evaluate this surrogate. ADR1D and the observational WQP component distributed upstream are separate datasets with different purposes and must not be treated as a common statistical population.
The public loader verifies the model, protocol, and inference code before
deserializing the checkpoint. The release validator checks the remaining key
artifacts declared in models/model_manifest.json. Detailed integrity values
remain machine-readable in that manifest rather than being duplicated in the
README.
Do not bypass integrity verification or deserialize a checkpoint obtained from an untrusted source.
- Validation covers only ADR1D version 1.0.0 and its documented parameter ranges; no out-of-distribution accuracy claim is made.
- The medium is one-dimensional, homogeneous, and constant within each scenario.
- The surrogate predicts normalized concentration and requires externally supplied effective transport parameters and source timing.
- The hard constraints encode the ADR1D zero initial condition and rectangular finite-pulse inlet; other boundary histories require retraining or a new constraint formulation.
- The sigmoid output enforces
$[0,1]$ , which is appropriate for this benchmark and source definition but may not fit systems with overshoot or internal generation. - Aggregate error is low, but sharp fronts can produce large localized errors; the maximum final-test error is 0.89873.
- The 1,000 m interval is an observation window for a semi-infinite analytical solution, not a finite-domain outlet boundary.
- No field-site validation, heterogeneous medium, multi-dimensional flow, variable coefficients, uncertainty calibration, or transfer to arbitrary meshes has been demonstrated.
- Recorded throughput depends on hardware, operating system, batch size, and PyTorch build.
- This is a research artifact and does not replace site-specific hydrogeological assessment, uncertainty analysis, or regulatory procedures.
Please cite the software release as:
Tinoco-Guerrero, G., Domínguez-Mota, F. J., and Guzmán-Torres, J. A. (2026). ADR1D-NN: A Physics-Constrained Neural Surrogate for One-Dimensional Reactive Transport (Version 1.0.0) [Computer software]. Universidad Michoacana de San Nicolás de Hidalgo. https://github.com/gstinoco/ADR1D-NN
BibTeX:
@software{TinocoGuerrero2026ADR1DNN,
author = {Tinoco-Guerrero, Gerardo and
Domínguez-Mota, Francisco J. and
Guzmán-Torres, J. Alberto},
title = {{ADR1D-NN}: A Physics-Constrained Neural Surrogate for
One-Dimensional Reactive Transport},
version = {1.0.0},
year = {2026},
publisher = {Universidad Michoacana de San Nicolás de Hidalgo},
url = {https://github.com/gstinoco/ADR1D-NN}
}When reproducing training or benchmark results, also cite the upstream data release:
Tinoco-Guerrero, G., Domínguez-Mota, F. J., and Guzmán-Torres, J. A. (2026). ADR1D and WQP-NM-Nutrients: A Reproducible Contaminant-Transport Benchmark and Curated Water-Quality Snapshot (Version 1.0.0) [Data set]. Universidad Michoacana de San Nicolás de Hidalgo. https://doi.org/10.5281/zenodo.21499528
- Ogata, A., and Banks, R. B. (1961). A solution of the differential equation of longitudinal dispersion in porous media. U.S. Geological Survey Professional Paper 411-A. https://doi.org/10.3133/pp411A
- Paszke, A., Gross, S., Massa, F., et al. (2019). PyTorch: An imperative style, high-performance deep learning library. Advances in Neural Information Processing Systems, 32, 8024-8035. https://proceedings.neurips.cc/paper/2019/hash/bdbca288fee7f92f2bfa9f7012727740-Abstract.html
GitHub can also generate citation metadata directly from CITATION.cff.
Researchers and students advancing physics-constrained neural modeling for reactive transport
| Photo | Student | Institution | Contact |
|---|---|---|---|
![]() |
Gabriela Pedraza-Jiménez |
||
![]() |
Eli Chagolla-Inzunza |
| Photo | Student | Institution | Contact |
|---|---|---|---|
![]() |
Jorge L. González-Figueroa |
||
![]() |
Christopher N. Magaña-Barocio |
| Photo | Student | Institution | Contact |
|---|---|---|---|
![]() |
Maria Goretti Fraga-Lopez |
Student contributors are acknowledged for their participation in the broader
research program. Formal software citation and copyright attribution remain
limited to the three principal researchers listed in CITATION.cff and the
license files.
Connecting physics-constrained machine learning with applied engineering and technology transfer
|
Focus areas
|
ADR1D-NN uses a component-specific licensing scheme:
- Source code and serialized model checkpoint: MIT License, provided in
LICENSE. - Derived tables, reported results, and project figures: Creative Commons
Attribution 4.0 International, provided in
LICENSE-DATA. - ADR1D upstream content: remains subject to the rights and attribution statement in the archived ADR1D release and its source repository.
- Third-party libraries: retain their respective licenses; naming them here does not redistribute their source code.
- Institutional emblems and logos: files under
docs/partners/remain the property of their respective organizations. They are used solely for identification and acknowledgment and are not covered by the MIT orCC BY 4.0licenses.
Copyright and citation identify Gerardo Tinoco-Guerrero, Francisco J. Domínguez-Mota, and J. Alberto Guzmán-Torres as the principal investigators. The model and code are provided without warranty. Attribution must not imply endorsement by the authors, UMSNH, SECIHTI, CIMNE, Aula CIMNE Morelia, or SIIIA MATH.
We thank the institutions and partners whose continuing institutional and financial support made the model development, validation, documentation, and student participation possible.
|
Collaboration highlights
|
Collaboration highlights
|
|
Primary Research Contact
Scientific coordination and surrogate integration Gerardo Tinoco-Guerrero Universidad Michoacana de San Nicolás de Hidalgo Morelia, Michoacán, Mexico |
Repository Support
Questions, reproducibility reports, and integration problems
|
Does ADR1D-NN estimate transport parameters?
No. It is a forward surrogate that requires effective velocity, effective dispersion, decay, source timing, and coordinates. Parameter estimates can be provided by measurements, calibration, or ADR1D-ML.
Why does the model use normalized concentration?
The ADR equation is linear in source concentration under the assumptions used
here. Predicting
Can I evaluate arbitrary coordinates inside the domain?
Yes. The network is coordinate-conditioned and accepts irregular points. Validation, however, was performed on the documented ADR1D grid. Accuracy on different spatial or temporal sampling should be checked for the intended use.
Can I use parameters outside the ADR1D ranges?
The interface can permit them with --allow-outside-design, but version 1.0.0
does not make an extrapolation claim. Such predictions require independent
verification.
Why are the initial and inlet values not learned?
They are known exactly from the governing problem. Applying them deterministically removes avoidable physical error without changing the interior neural approximation.
Does full validation modify the published results?
No. validate_benchmark.py recomputes values in memory and prints a report.
Training writes only to the ignored reproduction/ directory.














