ADOPT-FPML
Automatic Discovery of OPTimal hybrid First Principles–Machine Learning models.
ADOPT-FPML discovers a parsimonious information-flow architecture for a system that has a first-principles (FP) model and measured data. It decides which outputs already have adequate FP predictions, where ML blocks are needed, which of four FP–ML interactions to use, what the ML inputs and outputs should be, and when to stop adding complexity.
This repository contains the proposed discovery algorithm, an installable Python package, two complete synthetic case studies, data-generation code, portable pretrained model artifacts, tests, and documentation. It intentionally does not copy full baseline-training programs that are already available in the cited literature.
Publication: Mukherjee, A., Giridhar, N. V. and Bhattacharyya, D. On the Automatic Discovery of Optimal Hybrid First Principles – Machine Learning Models for Interconnected Systems (manuscript under review)
What ADOPT-FPML searches
At every stage, ADOPT-FPML evaluates four reduced-superstructure configurations:
| Configuration | Package name | Information flow | ML learns |
|---|---|---|---|
| Parallel | parallel |
FP and ML operate in parallel | FP-output residuals |
| Series I | series_1 |
FP → ML | requested system outputs, using at least one FP output as an ML input |
| Series II | series_2 |
ML → FP | row-wise corrections to FP parameters |
| Integrated | integrated |
ML ↔ FP | FP parameter corrections using measured/synthetic inputs |
The default algorithm follows the manuscript:
- Run the standalone FP model and accept outputs satisfying their output-specific thresholds.
- Rank candidate inputs by mean absolute Pearson correlation with unresolved outputs.
- For each interaction configuration, add ranked inputs sequentially and retrain the ML block.
- Score candidates with corrected Akaike information criterion (AICc) and greedily prune a branch at its first non-improvement.
- Select the admissible candidate with the lowest local AICc within the stage.
- Retain it only if it resolves at least one new output and its relative global-AICc increase is below
tau_AIC. - Screen predicted synthetic variables for relevance, redundancy, and a cardinality cap; propagate retained variables to the next stage.
- Stop when all outputs meet their thresholds, no admissible improvement remains, the global-AICc rule rejects a stage, or the stage limit is reached.
See Algorithm and terminology for the route variables and exact decision rules.
Installation
ADOPT-FPML requires Python 3.10 or newer.
python -m venv .venv
Activate it on macOS/Linux:
source .venv/bin/activate
Or Windows PowerShell:
.venv\Scripts\Activate.ps1
Install the released package:
python -m pip install --upgrade pip
python -m pip install adopt-fpml
adopt-fpml doctor
Install directly from a local clone for development:
git clone https://github.com/mukherjeeangan26/ADOPT-FPML.git
cd ADOPT-FPML
python -m pip install -e ".[dev]"
pytest
Use python -m pip install "adopt-fpml[sklearn]" for the optional scikit-learn estimator adapter and mutual-information selector. NumPy, pandas, and SciPy are the only required runtime dependencies.
Quick start on a new system
Prepare two row-aligned DataFrames:
inputs: measured/manipulated variables available to FP and ML models.measured_outputs: canonical target outputs, in the same row order.
Then wrap a Python function that returns FP predictions:
import pandas as pd
from adopt_fpml import ADOPTFPML, CallableFirstPrinciplesModel, SearchConfig
def my_fp_model(
inputs: pd.DataFrame,
parameters: pd.DataFrame | None = None,
) -> pd.DataFrame:
gain = 2.0 if parameters is None else parameters["gain"].to_numpy()
return pd.DataFrame(
{
"product": gain * inputs["feed"],
"temperature": inputs["inlet_temperature"] + 10.0,
},
index=inputs.index,
)
fp = CallableFirstPrinciplesModel(
my_fp_model,
output_names=["product", "temperature"],
)
result = ADOPTFPML(fp).fit(
inputs=inputs,
measured_outputs=measured_outputs,
thresholds={"product": 0.05, "temperature": 2.0}, # absolute RMSE defaults
config=SearchConfig(max_stages=3),
)
print(result.summary())
result.search_history.to_csv("search_history.csv", index=False)
Series II and integrated configurations need a ParameterTargetGenerator; without one, the optimizer records those routes as skipped and still searches parallel/Series I. The E1/E2 examples include bounded SciPy estimators, while a new system normally supplies its own parameter-estimation or inverse-model routine. See Defining your system.
Required choices and defaults
| Component | You provide | Default/fallback | How to replace it |
|---|---|---|---|
| FP model | predict(inputs, parameters=None) and output names |
No universal physical model | Implement the protocol or wrap a function |
| Data | numeric, finite, row-aligned input/output DataFrames | Case-study data are included only for examples | Use your own DataFrames |
| Accuracy rules | one rule for every output | float means absolute RMSE | Use MetricThreshold for MAE, max error, or relative RMSE |
| ML class/solver | optional trainer | one-hidden-layer tanh NumPy MLP with Adam and early stopping | Implement MLTrainer, or use SklearnTrainer |
| Input selection | optional selector | mean absolute Pearson correlation | Spearman, mutual information, or a custom selector |
| Candidate objective | optional callable | AICc | Inject another complexity-aware objective |
| Branch pruning | search configuration | greedy first non-improvement | patience or moving-window policies |
| Stage termination | search configuration | all outputs resolved, no candidate, AICc rule, or stage cap | Change SearchConfig |
The supplied MLP matches the paper’s model class. It is a reproducible research default, not a claim that one architecture is universally best. If a replacement model is used with AICc, its fitted wrapper must report a meaningful parameter_count.
Reproduce the case studies
Run the portable pretrained architectures without retraining:
adopt-fpml reproduce e1
adopt-fpml reproduce e1 --split test
adopt-fpml reproduce e2
adopt-fpml reproduce e2 --split test
Run the scripts from a clone:
python examples/e1/run_pretrained.py
python examples/e2/run_pretrained.py --split test
Generate E1 data from scratch:
adopt-fpml generate e1 --rows 500 --output e1_training.csv
Generate E2 from an E1 feed trajectory:
adopt-fpml generate e2 --feed e1_training.csv --output e2_training.csv
The longer discovery scripts demonstrate how to rerun structural search. ML optimization can produce small platform-level numerical variations; the portable pretrained runners are the reference path for matching reported predictions. Full details are in E1, E2, and Reproducibility.
Reported retained structures
| Case | Retained stage 1 | Retained stage 2 | Standalone FP output |
|---|---|---|---|
| E1, three CSTRs | Series I: fp_T_out, T_in, CA0, fp_CB, fp_CC; resolves CB, CC |
Parallel: fp_T_out, stage-1 T_out, stage-1 CA, T_in; resolves CA, T_out |
None |
| E2, cooler/flash | Series I: fp_x_A, fp_x_C; resolves seven outputs |
Integrated: fp_F_liq, T_feed; corrects UA, K_A, K_B, K_C; resolves F_liq, y_A |
x_C |
The manuscript’s third, industrial superheater case is described in the publication but its proprietary plant data and implementation were not supplied for public distribution and are not included here.
Repository map
.
├── src/adopt_fpml/ installable algorithm, interfaces, CLI, cases, data
├── examples/ E1, E2, and a minimal custom-system example
├── docs/ concepts, extension guides, reproducibility, release guide
├── tests/ unit, generator, optimizer, and reference-RMSE checks
├── .github/workflows/ CI and trusted PyPI publishing
├── pyproject.toml package metadata and dependencies
├── CITATION.cff citation metadata
└── LICENSE BSD 3-Clause license
See Source archive audit for what was retained, reconstructed, consolidated, or excluded from the original working archives.
Publication, citation, and attribution
Until the article is published, cite the software and provisional manuscript:
@software{mukherjee_adopt_fpml_2026,
author = {Mukherjee, Angan and Giridhar, Nishant V. and Bhattacharyya, Debangsu},
title = {ADOPT-FPML: Automatic Discovery of Optimal Hybrid First Principles--Machine Learning Models},
year = {2026},
version = {0.1.0},
url = {https://github.com/mukherjeeangan26/ADOPT-FPML}
}
Update CITATION.cff, this block, and pyproject.toml when the journal citation and DOI are assigned. GitHub displays CITATION.cff through its “Cite this repository” control.
Contributing and support
Bug reports, validation cases, new FP-model adapters, selectors, and carefully tested pruning extensions are welcome. Read CONTRIBUTING.md before opening a pull request. Use GitHub Issues for reproducible software problems; do not include proprietary plant data or credentials.
License and disclaimer
The code is provided under the BSD 3-Clause License. Confirm that this license and all author/affiliation details are acceptable before the first public release. The software is research code supplied without warranty; users are responsible for engineering validation, safety constraints, identifiability checks, and any deployment decision.
First-time maintainers can follow the complete GitHub and PyPI publishing guide.
Metadata
Release files for adopt-fpml 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| adopt_fpml-0.1.0.tar.gz | 490.9 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| adopt_fpml-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 967.5 kB
Release files / adopt_fpml-0.1.0.tar.gz
| Download URL | adopt_fpml-0.1.0.tar.gz |
|---|---|
| Size | 490.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2804ef672905ee70c1a75920d5ed5f3dd70ca2f9c9d4bb48046c1614892b1912
|
|
BLAKE2b-256 checksum How to use checksums |
f85df0477dd719ed39b14b161105175bee54fbc730477ef9fdae73282f99b30c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.
Transparency logRelease files / adopt_fpml-0.1.0-py3-none-any.whl
| Download URL | adopt_fpml-0.1.0-py3-none-any.whl |
|---|---|
| Size | 476.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
09e00972f1f0d633a5f2905636d8199bb294e08116066ce19bdd5254b895d1c8
|
|
BLAKE2b-256 checksum How to use checksums |
13ec5b89861ee26ba8e6cb70423eb28d7dec5fb4ca37f82c7d08f48aa5ead3e9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.
Transparency logSecurity for adopt-fpml 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for adopt_fpml-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.