Catalog PyPI
PACKAGE EXPLORERView in registry

adopt-fpml

PyPI

Automatic discovery of optimal hybrid first-principles–machine-learning models

engineeringfirsthybridlearningmachinemodelingprinciplesprocesssystems
Versions collected1
Direct dependencies9From release 0.1.0
Last observed20 Oct, 19:46 UTC

README

Version 0.1.0 documentation

ADOPT-FPML

CI PyPI Python License

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:

ConfigurationPackage nameInformation flowML learns
ParallelparallelFP and ML operate in parallelFP-output residuals
Series Iseries_1FP → MLrequested system outputs, using at least one FP output as an ML input
Series IIseries_2ML → FProw-wise corrections to FP parameters
IntegratedintegratedML ↔ FPFP parameter corrections using measured/synthetic inputs

The default algorithm follows the manuscript:

  1. Run the standalone FP model and accept outputs satisfying their output-specific thresholds.
  2. Rank candidate inputs by mean absolute Pearson correlation with unresolved outputs.
  3. For each interaction configuration, add ranked inputs sequentially and retrain the ML block.
  4. Score candidates with corrected Akaike information criterion (AICc) and greedily prune a branch at its first non-improvement.
  5. Select the admissible candidate with the lowest local AICc within the stage.
  6. Retain it only if it resolves at least one new output and its relative global-AICc increase is below tau_AIC.
  7. Screen predicted synthetic variables for relevance, redundancy, and a cardinality cap; propagate retained variables to the next stage.
  8. 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

ComponentYou provideDefault/fallbackHow to replace it
FP modelpredict(inputs, parameters=None) and output namesNo universal physical modelImplement the protocol or wrap a function
Datanumeric, finite, row-aligned input/output DataFramesCase-study data are included only for examplesUse your own DataFrames
Accuracy rulesone rule for every outputfloat means absolute RMSEUse MetricThreshold for MAE, max error, or relative RMSE
ML class/solveroptional trainerone-hidden-layer tanh NumPy MLP with Adam and early stoppingImplement MLTrainer, or use SklearnTrainer
Input selectionoptional selectormean absolute Pearson correlationSpearman, mutual information, or a custom selector
Candidate objectiveoptional callableAICcInject another complexity-aware objective
Branch pruningsearch configurationgreedy first non-improvementpatience or moving-window policies
Stage terminationsearch configurationall outputs resolved, no candidate, AICc rule, or stage capChange 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

CaseRetained stage 1Retained stage 2Standalone FP output
E1, three CSTRsSeries I: fp_T_out, T_in, CA0, fp_CB, fp_CC; resolves CB, CCParallel: fp_T_out, stage-1 T_out, stage-1 CA, T_in; resolves CA, T_outNone
E2, cooler/flashSeries I: fp_x_A, fp_x_C; resolves seven outputsIntegrated: fp_F_liq, T_feed; corrects UA, K_A, K_B, K_C; resolves F_liq, y_Ax_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.

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.1.012 Aug 20269

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
mukherjeeangan26/adopt-fpml

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 19:46 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:d5694159e0f9629b61083d631c2209f5e52bc27552b3fdee33d1884a2bc8f8f6