engin-core
Open toolkit for fermentation scale-up: a mechanistic fed-batch simulator, a Gaussian-process titer model with conformally calibrated uncertainty, an active-learning next-batch recommender, and reproducible benchmarks. Built on mature libraries — scipy (integration), scikit-learn (GP), MAPIE (conformal) — with only the domain models hand-written.
Part of the engin-suite strain-to-scale monorepo.
Why
Most bioprocess optimizers give point predictions or intervals that quietly lie. The trap is easy to fall into: form a 90% interval from the model's uncertainty alone and assume normality, and it covers only ~55% of held-out runs — badly overconfident. engin-core forecasts titer with honest coverage and recommends the runs worth doing next.
Calibrated uncertainty is the whole point of the wedge: a scale-up decision needs
P(hit $/kg target), not a number with no error bar.
Install
Not published to PyPI yet — pip install engin-core will not find anything.
Install from a checkout of the monorepo:
git clone https://github.com/enginbio/engin-suite
cd engin-suite
pip install -e "packages/engin-core[dev]"
Quickstart
import numpy as np
from engin_core import (
simulate_unit, fit_gp, split_conformal_multiplier,
recommend_batch, ard_importance, unit_to_physical,
)
rng = np.random.default_rng(0)
U = rng.random((120, 5)) # unit-cube DoE (5 design knobs)
y = simulate_unit(U) # titer (g/L) from the simulator
tr, ca, te = slice(0, 70), slice(70, 100), slice(100, 120)
gp = fit_gp(U[tr], y[tr]) # fit the GP titer model
# Calibrate a 90% interval on a held-out set (split conformal):
mc, sdc = gp.predict(U[ca])
q90 = split_conformal_multiplier(y[ca], mc, sdc, level=0.90)
mean, sd = gp.predict(U[te]) # forecast: mean ± q90*sd is a 90% PI
X_next, m_next, sd_next, ei = recommend_batch(gp, float(y[tr].max()), k=8)
print("recommended next runs (physical units):\n", unit_to_physical(X_next))
print("titer drivers (ARD):", np.round(ard_importance(gp), 2))
Running this in a loop? recommend_batch draws a fresh candidate pool on each
call, because seed defaults to None (ADR 0011). Pass seed=<int> when you want
a bit-reproducible recommendation — but pass a different one each round, not a
fixed one, or every round searches the same fixed set of candidate points and the
campaign converges to the best point in that set rather than the best design.
Full end-to-end demo (writes plots, a DoE CSV, and a DoE round-reduction memo):
python examples/run_demo.py
What's in the box
| Module | What it does |
|---|---|
engin_core.simulator |
Fed-batch Monod/Luedeking-Piret bioreactor with product inhibition — a non-monotonic titer landscape with a real interior optimum. Bespoke equations, integrated by scipy solve_ivp (piecewise across the feed/induction switches). 5 knobs: feed_rate, feed_start, Sf, induction_time, S0. |
engin_core.gp |
scikit-learn ARD-RBF Gaussian Process + split-conformal (heteroscedastic, sd-scaled) and MAPIE-backed interval calibration + prob_at_least. |
engin_core.recommend |
Expected-Improvement next-batch recommender with a diversity filter. |
engin_core.sensitivity |
ARD inverse-lengthscale sensitivity — which knobs actually move titer. |
The calibration story (why conformal)
A raw GP interval is overconfident here because a space-filling DoE is "easier"
than the future query points the model is asked about (covariate shift), and the
epistemic sd ignores observation noise entirely. Split-conformal calibrates the
interval multiplier on a same-distribution held-out set using the finite-sample
conformal quantile — distribution-free, no normality assumption. The score is the classical
normalized nonconformity measure of Papadopoulos, Gammerman and Vovk —
|y − ŷ| / σ, with σ taken from the model's own predictive sd — and the
multiplier form keeps intervals riding the GP's per-point sd.
This is related to, but not the same as, MAPIE's ResidualNormalisedScore, which
estimates σ with a separate learned model fitted to log-residuals. Normalizing
by the GP's own sd needs no second model, which matters at the sample sizes this
targets.
Reproduce (python benchmarks/benchmark.py, mean over 20 seeds):
| 90% interval built from… | Coverage (target 0.90) |
|---|---|
| epistemic-only, Gaussian ×1.645 | 0.59 — naive, overconfident (seed-dependent; read as ~0.55–0.62) |
| total (model + noise), Gaussian ×1.645 | 0.86 — assumes normality, drifts per seed |
| total, split-conformal ×q90 | 0.96 — honest |
Benchmarks
python benchmarks/benchmark.py (mean over 20 seeds, held-out):
- Forecast: RMSE ≈ 3.8 g/L, R² ≈ 0.96.
- Calibration: see table above.
- Active-learning lift (best true titer of an 8-run batch vs the best true titer in the initial DoE): EI ≈ +18% vs random ≈ −23% — one recommended batch moves the frontier; a random batch does not.
The single-seed examples/run_demo.py slice: R² 0.97, RMSE ~4 g/L, feed_rate
the dominant driver, and one active-learning round lifting best titer +28%
(86→110 g/L).
Development
pip install -e ".[dev]"
pytest # tests
ruff check . # lint
License
Apache-2.0. Patent grant included, matching the BayBE/BioSTEAM ecosystem.
Metadata
Release files for engin-core 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| engin_core-0.1.1.tar.gz | 126.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| engin_core-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 215.3 kB
Release files / engin_core-0.1.1.tar.gz
| Download URL | engin_core-0.1.1.tar.gz |
|---|---|
| Size | 126.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
354734760ee056759a397a7afc3f5ee09740c9f88213ffe2767b64b6e3c132b0
|
|
BLAKE2b-256 checksum How to use checksums |
5a1d8856963963d2df8fe7a726e3c0f866ba63bd80d28dbb0794c2e1ffa21c8e
|
| 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 22, 2026.
Transparency logRelease files / engin_core-0.1.1-py3-none-any.whl
| Download URL | engin_core-0.1.1-py3-none-any.whl |
|---|---|
| Size | 88.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
eaaef8bc90976105daa62c2132338c71854cbaa0f8e67ff42d075bb28a2c6930
|
|
BLAKE2b-256 checksum How to use checksums |
377ff818f04e3fa489c9d9178d535002618f475f120cb551e2fd482424bd443d
|
| 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 22, 2026.
Transparency log