discopt-doe
Design-of-experiments plugin for the discopt
modeling language. Installs as the discopt.doe namespace package — code written
against from discopt.doe import ... works unchanged.
Three complementary entry points:
- "What is the best operating condition?" — active-learning optimization: fit a surrogate to completed experiments, recommend the next batch via an acquisition function (EI, UCB, steepest ascent), track everything in an Excel workbook.
- "Does this factor matter?" — classical designs: 2-level full/fractional factorials, mixture designs, Latin/Graeco-Latin squares, main-effect estimates, ANOVA.
- "How precisely can I estimate the model parameters?" — model-based DoE: exact D/A/E-optimal design from the Fisher Information Matrix (JAX autodiff), identifiability/estimability diagnostics, profile likelihood, model discrimination, sequential estimate–design loops.
Parameter estimation (discopt.estimate) lives in the base package; both
share the same Experiment interface.
Try it without installing anything
jkitchin.github.io/discopt-doe/app/ runs the design workflow in your browser — pick a design, download the spreadsheet, fill in your measurements, upload it back for fitting and ANOVA. It is Pyodide running the real package, not a reimplementation, and the workbooks it produces are the same ones the CLI reads. Nothing leaves your machine. See docs/browser-app.md.
Install
Both discopt-doe and its discopt>=0.9 dependency are published on
PyPI, so a plain pip install resolves
everything:
pip install discopt-doe # core
pip install "discopt-doe[gui]" # + Streamlit workbook GUI
pip install "discopt-doe[ml]" # + scikit-learn surrogates
Or with uv:
uv pip install "discopt-doe[gui]"
From source, to work on the package itself:
git clone https://github.com/jkitchin/discopt-doe
cd discopt-doe
uv sync --all-extras # core + gui + ml + dev
Quick start
FIM-based optimal design:
from discopt.doe import compute_fim, optimal_experiment, DesignCriterion
fim = compute_fim(experiment, param_values={"k": 2.0}, design_values={"T": 350.0})
design = optimal_experiment(
experiment,
param_values={"k": 2.0},
design_bounds={"T": (300, 400)},
criterion=DesignCriterion.D_OPTIMAL,
)
print(design.summary())
Active-learning round against a workbook:
from discopt.doe import optimize_round, OptimizationCriterion
result = optimize_round(
workbook="opt.xlsx",
criterion=OptimizationCriterion.MAXIMIZE,
surrogate="gp",
acquisition="expected_improvement",
batch_size=4,
)
print(result.next_designs)
Identifiability diagnostics before you spend beam time:
from discopt.doe import diagnose_identifiability, estimability_rank
diag = diagnose_identifiability(experiment, param_values)
est = estimability_rank(experiment, param_values)
Command line
Installing this package adds the doe subcommand to the base discopt CLI
(via the "discopt.cli" entry-point group):
discopt doe templates # list workbook templates
discopt doe new linear -o run.xlsx --input T:300:400 --n 8
discopt doe status run.xlsx
discopt doe fit run.xlsx # fit parameters to completed rows
discopt doe anova run.xlsx # ANOVA F-table (latin/factorial designs)
discopt doe extend run.xlsx --n 4 # design the next batch
discopt doe optimize run.xlsx # one active-learning round (optimize template)
discopt doe gui run.xlsx # Streamlit GUI (needs [gui] extra)
Classical designs over a continuous factor box — space-filling, or built for a quadratic response surface — need no model up front:
discopt doe new latin-hypercube -o lhs.xlsx --input T:300:400 --input P:1:5 --n 12
discopt doe new central-composite -o ccd.xlsx --input T:300:400 --input P:1:5
discopt doe new box-behnken -o bbd.xlsx --input T:300:400 --input P:1:5 --input F:0.1:2
fit estimates the recorded basis (--basis linear|quadratic) by least
squares, so a Box-Behnken or central-composite campaign goes straight from
new to fit with no model definition. Central-composite keeps every run
inside the bounds you give by default; pass --outside-bounds for the textbook
scaling where the axial points sit beyond them.
For a model of your own — including one nonlinear in its parameters — write the response and its parameters directly:
discopt doe new symbolic -o arrhenius.xlsx \
--expr "k0 * exp(-Ea / (8.314 * T))" \
--param k0=2.0 --param Ea=5000 \
--input T:300:500 --n 6
discopt doe fit arrhenius.xlsx # nonlinear least squares, analytic Jacobian
discopt doe extend arrhenius.xlsx --n 4 # next batch, re-centred on the fit
The expression is differentiated with sympy, so ∂y/∂θ is exact rather than a
finite difference. A nonlinear model's information depends on its parameter
values, so --param gives the nominal point the design is built around; fit
then extend re-centres it on what the data say.
GUI
discopt doe gui [workbook.xlsx] launches a Streamlit app over a campaign
workbook (install the [gui] extra, which also pulls scikit-learn for the
active-learning round). It wraps the same do_* functions as the CLI:
- Create a new campaign from a template, browsing to an output folder.
- Edit responses in-app or in Excel, then Save; the Rename panel can rename factors/response — note this clears the fit artifacts, so re-run Fit.
- Fit / Extend / Optimize / ANOVA panels drive the corresponding verb, and a History panel shows the workbook's audit log.
Flags: --port N, --no-browser. The DISCOPT_DOE_WORKBOOK environment
variable pre-selects a workbook. Keep charts in a separate file — the CLI/GUI
rewrite the workbook and openpyxl does not preserve embedded charts (a .bak
is written before the first save).
Development
The project is uv-managed:
uv sync --all-extras # create .venv with everything
uv run pytest # fast test set (slow tests excluded by default)
uv run pytest -m '' # everything
To develop against a local discopt checkout instead of the PyPI release, add
a [tool.uv.sources] override pointing discopt at your editable clone:
[tool.uv.sources]
discopt = { path = "../discopt", editable = true }
Docs are a Jupyter Book:
uv run jupyter-book build docs/
Claude Code skill
The package bundles a /discopt-doe skill and four expert agents (DoE,
estimability, identifiability, model discrimination) for Claude Code:
discopt-doe-install-skill # install to ~/.claude
discopt-doe-install-skill --project # install to ./.claude (versioned)
Related work
discopt-doe is not the only open-source option, and for some jobs it is not the best one. What distinguishes it is the combination of classical designs, model-based design, and a workbook/CLI/app workflow in one package; where another tool is a better fit, use it.
Model-based design of experiments. These are the closest neighbours — they design experiments from a mechanistic model and its Fisher information.
- Pyomo.DoE
— MBDoE for models written in Pyomo, solving the design problem as a
(stochastic) nonlinear program with sensitivities from
k_aug. If your model is already an algebraic or DAE Pyomo model, or you need design variables subject to serious process constraints, this is more powerful than what is here. Wang & Dowling, AIChE J 68 (2022), e17813. The two packages are compared head to head, against exact references rather than against each other, inbenchmarks/pyomo_doe_comparison/REPORT.md; several correctness fixes in discopt-doe came out of it. - pydex — optimal continuous (approximate) designs: it optimises weights over a candidate set through scipy or cvxpy, which is the natural home for the equivalence theorem. discopt-doe builds exact designs of a fixed number of runs instead; the two answer different questions about the same problem.
- Pyomo.parmest — the estimation half of the same loop: parameter fitting with bootstrap and likelihood-ratio confidence regions. It pairs naturally with Pyomo.DoE.
- PyOED — model-constrained OED for inverse problems and data assimilation, aimed at PDE-scale problems.
Classical and algorithmic designs.
- pyDOE3 — the maintained descendant of pyDOE/pyDOE2: factorial, fractional factorial, Plackett–Burman, Box–Behnken, central composite and Latin hypercube generators. Small, dependency-light, and a fine choice if a design matrix is all you need.
- dexpy — classical DOE from Stat-Ease, with D-optimal construction and power analysis.
- OApackage — orthogonal arrays, conference designs and D-efficient designs, with the combinatorial search done properly in C++.
- pyoptex — optimal design with extensible criteria and design structures, including split-plot and other restricted randomizations.
Sequential optimization and surrogates. Chapters on Bayesian optimization here are deliberately introductory; for production campaigns these are stronger.
- BoTorch and Ax — Bayesian optimization on PyTorch, with multi-objective, batch and constrained variants.
- BayBE — Bayesian experimental design aimed squarely at chemistry and formulation, with good handling of categorical and mixture-like search spaces.
- SMT — surrogate modelling toolbox, including sampling plans and gradient-enhanced models.
Outside Python. R remains the deepest ecosystem for classical DOE:
DoE.base and FrF2 for factorial and fractional designs, AlgDesign for
D/A/I-optimal construction, rsm for response-surface work, and daewr for the
designs in Lawson's textbook. JMP, Design-Expert and Minitab are the
commercial standards; the capability map in the book is written against the
workflow those tools support, without naming them.
Literature
The methods implemented here are referenced throughout the docs; the full bibliography is in docs/references.bib (Atkinson & Donev optimal design, Franceschini & Macchietto MBDoE, Yao estimability, Raue profile likelihood, Hunter–Reiner/Buzzi-Ferraris discrimination, and more).
Metadata
Release files for discopt-doe 0.4.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 | Provenance | |
|---|---|---|---|---|
| discopt_doe-0.4.1.tar.gz | 1.4 MB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| discopt_doe-0.4.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 2.6 MB
Release files / discopt_doe-0.4.1.tar.gz
| Download URL | discopt_doe-0.4.1.tar.gz |
|---|---|
| Size | 1.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e2449e9ee3f36a79eb31c1dcb7e5cb064c12b836c8652b4b72ab9b00b5f6d148
|
|
BLAKE2b-256 checksum How to use checksums |
26d7b71c9faba6400c4b6519787b1e2cbcbf7c35caed5590866b58e37377d888
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Oct 21, 2026.
Transparency logRelease files / discopt_doe-0.4.1-py3-none-any.whl
| Download URL | discopt_doe-0.4.1-py3-none-any.whl |
|---|---|
| Size | 1.3 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f0130886984559c36c703586aec2ba08c018fda69eecf9ba9066a5bfaa2a3eb2
|
|
BLAKE2b-256 checksum How to use checksums |
3510dfd29012cff96ea2d4fe2ec50ae473dccd821875b4fc82ebf42b6c7e30f5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Oct 21, 2026.
Transparency logSecurity for discopt-doe 0.4.1
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 discopt_doe-0.4.1.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 Oct 21, 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.