openpkflow 2.3.0__tar.gz → 2.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openpkflow-2.5.0/.dockerignore +11 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/.github/workflows/ci.yml +11 -8
- {openpkflow-2.3.0 → openpkflow-2.5.0}/.github/workflows/docs.yml +2 -2
- {openpkflow-2.3.0 → openpkflow-2.5.0}/.github/workflows/publish.yml +5 -5
- openpkflow-2.5.0/.github/workflows/slow-validation.yml +26 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/.gitignore +5 -0
- openpkflow-2.3.0/CLAUDE.md → openpkflow-2.5.0/AGENTS.md +11 -3
- {openpkflow-2.3.0 → openpkflow-2.5.0}/CHANGELOG.md +43 -0
- openpkflow-2.5.0/CLAUDE.md +383 -0
- openpkflow-2.5.0/Dockerfile +25 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/FUTURE_PLANS.md +48 -3
- openpkflow-2.5.0/HANDOFF.md +264 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/PKG-INFO +54 -32
- {openpkflow-2.3.0 → openpkflow-2.5.0}/README.md +52 -31
- openpkflow-2.5.0/RELEASE.md +48 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/ROADMAP.md +34 -7
- {openpkflow-2.3.0 → openpkflow-2.5.0}/VALIDATION.md +26 -0
- openpkflow-2.5.0/api/README.md +41 -0
- openpkflow-2.5.0/api/app/__init__.py +1 -0
- openpkflow-2.5.0/api/app/config.py +23 -0
- openpkflow-2.5.0/api/app/deps.py +40 -0
- openpkflow-2.5.0/api/app/main.py +48 -0
- openpkflow-2.5.0/api/app/routers/__init__.py +1 -0
- openpkflow-2.5.0/api/app/routers/be.py +57 -0
- openpkflow-2.5.0/api/app/routers/dissolution.py +79 -0
- openpkflow-2.5.0/api/app/routers/ivivc.py +47 -0
- openpkflow-2.5.0/api/app/routers/nca.py +59 -0
- openpkflow-2.5.0/api/app/routers/sim.py +67 -0
- openpkflow-2.5.0/api/app/schemas/__init__.py +1 -0
- openpkflow-2.5.0/api/app/schemas/be.py +40 -0
- openpkflow-2.5.0/api/app/schemas/dissolution.py +30 -0
- openpkflow-2.5.0/api/app/schemas/ivivc.py +41 -0
- openpkflow-2.5.0/api/app/schemas/nca.py +40 -0
- openpkflow-2.5.0/api/app/schemas/sim.py +57 -0
- openpkflow-2.5.0/api/app/services/__init__.py +1 -0
- openpkflow-2.5.0/api/app/services/be_service.py +79 -0
- openpkflow-2.5.0/api/app/services/dissolution_service.py +70 -0
- openpkflow-2.5.0/api/app/services/ivivc_service.py +84 -0
- openpkflow-2.5.0/api/app/services/nca_service.py +99 -0
- openpkflow-2.5.0/api/app/services/sim_service.py +57 -0
- openpkflow-2.5.0/api/requirements.txt +6 -0
- openpkflow-2.5.0/api/tests/__init__.py +1 -0
- openpkflow-2.5.0/api/tests/conftest.py +26 -0
- openpkflow-2.5.0/api/tests/test_dissolution.py +95 -0
- openpkflow-2.5.0/api/tests/test_nca.py +83 -0
- openpkflow-2.5.0/api/tests/test_sim.py +79 -0
- openpkflow-2.5.0/docker-compose.yml +16 -0
- openpkflow-2.5.0/docs/changelog.md +205 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/index.md +29 -3
- openpkflow-2.5.0/docs/migration-cheatsheet.md +196 -0
- openpkflow-2.5.0/docs/openfit/CLAUDE.md +402 -0
- openpkflow-2.5.0/docs/openfit/OPENASSAYFLOW_CLAUDE.md +228 -0
- openpkflow-2.5.0/docs/openfit/ROADMAP.md +230 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/reference/be.md +53 -3
- openpkflow-2.5.0/docs/theory.md +482 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/tutorials/bayes.md +4 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/tutorials/be.md +39 -4
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/tutorials/dissolution.md +5 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/tutorials/ivivc.md +5 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/tutorials/nca.md +5 -0
- openpkflow-2.5.0/docs/tutorials/pop.md +225 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/tutorials/sim.md +5 -0
- openpkflow-2.5.0/docs/validation-matrix.md +46 -0
- openpkflow-2.5.0/examples/replicate_be_partial.csv +10 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/mkdocs.yml +8 -1
- openpkflow-2.5.0/progress_web_app.md +96 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/pyproject.toml +8 -2
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/conda-forge/meta.yaml +9 -5
- openpkflow-2.5.0/scripts/crossval_winnonlin.py +252 -0
- openpkflow-2.5.0/scripts/powertost_crossval.R +95 -0
- openpkflow-2.5.0/scripts/release_readiness.py +78 -0
- openpkflow-2.5.0/scripts/replicate_be_crossval.R +154 -0
- openpkflow-2.5.0/site/app/index.html +3685 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/__init__.py +1 -1
- openpkflow-2.5.0/src/openpkflow/be/__init__.py +28 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/be/methods.py +152 -2
- openpkflow-2.5.0/src/openpkflow/be/replicate.py +311 -0
- openpkflow-2.5.0/src/openpkflow/be/reporting.py +289 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/cli.py +232 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/models.py +20 -3
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/study.py +2 -2
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/nca/__init__.py +2 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/nca/methods.py +63 -0
- openpkflow-2.5.0/src/openpkflow/student/__init__.py +36 -0
- openpkflow-2.5.0/src/openpkflow/student/dissolution.py +506 -0
- openpkflow-2.5.0/src/openpkflow/student/nca.py +404 -0
- openpkflow-2.5.0/src/openpkflow/student/sim.py +492 -0
- openpkflow-2.5.0/tests/be/test_methods_hypothesis.py +112 -0
- openpkflow-2.5.0/tests/be/test_replicate.py +150 -0
- openpkflow-2.5.0/tests/dissolution/test_bootstrap_hypothesis.py +68 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/dissolution/test_models.py +1 -1
- openpkflow-2.5.0/tests/dissolution/test_similarity_hypothesis.py +107 -0
- openpkflow-2.5.0/tests/ivivc/test_methods_hypothesis.py +71 -0
- openpkflow-2.5.0/tests/nca/test_methods_hypothesis.py +621 -0
- openpkflow-2.5.0/tests/sim/test_dosing_hypothesis.py +153 -0
- openpkflow-2.5.0/tests/sim/test_methods_hypothesis.py +313 -0
- openpkflow-2.5.0/tests/sim/test_models_hypothesis.py +118 -0
- openpkflow-2.5.0/tests/sim/test_simulate_hypothesis.py +133 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/test_cli.py +72 -0
- openpkflow-2.5.0/tests/test_student.py +352 -0
- openpkflow-2.5.0/tests/validation/test_be_power_reference.py +199 -0
- openpkflow-2.5.0/tests/validation/test_be_replicate_reference.py +133 -0
- openpkflow-2.5.0/tests/validation/test_nca_winnonlin_reference.py +788 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/validation/test_pop_foce_reference.py +2 -0
- openpkflow-2.5.0/webapp/.gitignore +24 -0
- openpkflow-2.5.0/webapp/README.md +33 -0
- openpkflow-2.5.0/webapp/eslint.config.js +22 -0
- openpkflow-2.5.0/webapp/index.html +13 -0
- openpkflow-2.5.0/webapp/package-lock.json +3679 -0
- openpkflow-2.5.0/webapp/package.json +43 -0
- openpkflow-2.5.0/webapp/playwright.config.ts +23 -0
- openpkflow-2.5.0/webapp/public/favicon.svg +1 -0
- openpkflow-2.5.0/webapp/public/icons.svg +24 -0
- openpkflow-2.5.0/webapp/src/App.tsx +45 -0
- openpkflow-2.5.0/webapp/src/components/layout/AppShell.tsx +25 -0
- openpkflow-2.5.0/webapp/src/components/layout/ErrorBoundary.tsx +45 -0
- openpkflow-2.5.0/webapp/src/components/layout/PageLoader.tsx +12 -0
- openpkflow-2.5.0/webapp/src/components/layout/Sidebar.tsx +82 -0
- openpkflow-2.5.0/webapp/src/components/layout/ThemeProvider.tsx +19 -0
- openpkflow-2.5.0/webapp/src/components/layout/ThemeToggle.tsx +22 -0
- openpkflow-2.5.0/webapp/src/components/layout/TopBar.tsx +66 -0
- openpkflow-2.5.0/webapp/src/components/layout/theme-context.ts +16 -0
- openpkflow-2.5.0/webapp/src/components/shared/AnalysisShell.tsx +81 -0
- openpkflow-2.5.0/webapp/src/components/shared/ColumnMapper.tsx +42 -0
- openpkflow-2.5.0/webapp/src/components/shared/Disclaimer.tsx +10 -0
- openpkflow-2.5.0/webapp/src/components/shared/DownloadReportButton.tsx +175 -0
- openpkflow-2.5.0/webapp/src/components/shared/ErrorBanner.tsx +32 -0
- openpkflow-2.5.0/webapp/src/components/shared/FileDropzone.tsx +134 -0
- openpkflow-2.5.0/webapp/src/components/shared/MetricCard.tsx +39 -0
- openpkflow-2.5.0/webapp/src/components/shared/PKChart.tsx +218 -0
- openpkflow-2.5.0/webapp/src/components/shared/PasteDataGrid.tsx +297 -0
- openpkflow-2.5.0/webapp/src/components/ui/Badge.tsx +30 -0
- openpkflow-2.5.0/webapp/src/components/ui/Button.tsx +42 -0
- openpkflow-2.5.0/webapp/src/components/ui/Card.tsx +6 -0
- openpkflow-2.5.0/webapp/src/components/ui/Input.tsx +16 -0
- openpkflow-2.5.0/webapp/src/components/ui/SegmentedControl.tsx +44 -0
- openpkflow-2.5.0/webapp/src/components/ui/Select.tsx +21 -0
- openpkflow-2.5.0/webapp/src/components/ui/Skeleton.tsx +5 -0
- openpkflow-2.5.0/webapp/src/index.css +249 -0
- openpkflow-2.5.0/webapp/src/lib/api.ts +199 -0
- openpkflow-2.5.0/webapp/src/lib/gridCsv.ts +18 -0
- openpkflow-2.5.0/webapp/src/lib/types.ts +95 -0
- openpkflow-2.5.0/webapp/src/lib/utils.ts +6 -0
- openpkflow-2.5.0/webapp/src/main.tsx +10 -0
- openpkflow-2.5.0/webapp/src/pages/BePage.tsx +512 -0
- openpkflow-2.5.0/webapp/src/pages/DissolutionPage.tsx +348 -0
- openpkflow-2.5.0/webapp/src/pages/Home.tsx +156 -0
- openpkflow-2.5.0/webapp/src/pages/IvIvcPage.tsx +388 -0
- openpkflow-2.5.0/webapp/src/pages/NcaPage.tsx +486 -0
- openpkflow-2.5.0/webapp/src/pages/NotFound.tsx +20 -0
- openpkflow-2.5.0/webapp/src/pages/SimPage.tsx +503 -0
- openpkflow-2.5.0/webapp/tests/paste-run.spec.ts +144 -0
- openpkflow-2.5.0/webapp/tsconfig.app.json +28 -0
- openpkflow-2.5.0/webapp/tsconfig.json +7 -0
- openpkflow-2.5.0/webapp/tsconfig.node.json +24 -0
- openpkflow-2.5.0/webapp/vite.config.ts +17 -0
- openpkflow-2.5.0/wrangler.toml +6 -0
- openpkflow-2.3.0/HANDOFF.md +0 -135
- openpkflow-2.3.0/docs/tutorials/pop.md +0 -100
- openpkflow-2.3.0/src/openpkflow/be/__init__.py +0 -14
- openpkflow-2.3.0/src/openpkflow/be/reporting.py +0 -133
- {openpkflow-2.3.0 → openpkflow-2.5.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/.github/dependabot.yml +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/.pre-commit-config.yaml +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/CITATION.cff +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/CODE_OF_CONDUCT.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/CONTRIBUTING.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/LICENSE +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/SECURITY.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/V2_ARCHITECTURE_DECISION.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/codecov.yml +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/demo.ipynb +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/logo.png +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/reference/bayes.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/reference/dissolution.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/reference/ivivc.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/reference/ml.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/reference/nca.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/reference/pop.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/reference/sim.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/docs/reference/validation.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/examples/be_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/examples/dissolution_advanced.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/examples/dissolution_basic.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/examples/dissolution_comparison.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/examples/ivivc_report.md +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/examples/openpkflow_tour.ipynb +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/examples/report_dissolution.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/bootf2_dissolution_crossval.R +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/dissolution_models_crossval.R +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/ivivc_wn_lr_crossval.R +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/nlmixr2_popk_crossval.R +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/noncompart_theoph_crossval.R +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/pknca_ss_crossval.R +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/pknca_theoph_crossval.R +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/pknca_theoph_crossval_extended.R +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/probe_bootf2.R +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/probe_foce_i.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/probe_noncompart.R +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/scripts/urine_nca_crossval.R +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/bayes/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/bayes/bayes_be.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/bayes/bayes_pk.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/bayes/map_pk.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/bayes/priors.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/bayes/reporting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/bayes/results.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/be/results.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/be/study.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/datasets/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/datasets/example_dissolution.csv +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/datasets/example_not_similar.csv +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/datasets/example_similar.csv +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/datasets/ss_crossval.csv +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/datasets/theoph.csv +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/bootstrap.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/loader.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/multi_media.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/plotting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/reporting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/similarity.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/ivivc/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/ivivc/methods.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/ivivc/reporting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/ivivc/results.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/ivivc/study.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/ml/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/ml/surrogate.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/nca/loader.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/nca/reporting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/nca/results.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/nca/sparse.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/nca/study.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/dataset.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/diagnostics.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/foce_i.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/foce_inner.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/model.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/objective.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/omega.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/plotting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/reporting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/result.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/saem.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/saem_kernel.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/gof.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/plotting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/reporting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/pop/vpc.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/py.typed +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/docx.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/html.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/pdf.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/bayes_be_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/be_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/dissolution_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/fit_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/ivivc_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/map_pk_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/multi_media_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/nca_single_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/nca_summary_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/pop_gof_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/pop_vpc_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/sim_report.html +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/sim/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/sim/dosing.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/sim/methods.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/sim/models.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/sim/plotting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/sim/reporting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/sim/results.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/sim/simulate.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/src/openpkflow/validation/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/bayes/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/bayes/test_bayes_be.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/bayes/test_map_pk.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/be/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/be/test_methods.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/be/test_study.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/dissolution/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/dissolution/test_alternatives.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/dissolution/test_bootstrap.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/dissolution/test_excel_loader.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/dissolution/test_m13b.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/dissolution/test_model_comparison.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/dissolution/test_multi_media.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/dissolution/test_similarity.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/dissolution/test_study.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/ivivc/test_ivivc.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/ml/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/ml/test_surrogate.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/nca/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/nca/test_loader.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/nca/test_methods.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/nca/test_nca_pdf_docx.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/nca/test_nca_reporting.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/nca/test_nca_results.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/nca/test_sparse_nca.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/nca/test_steady_state_urine.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/nca/test_study.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/nca/test_theoph_reference.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/pop/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/pop/test_dataset.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/pop/test_estimation_diagnostics.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/pop/test_estimation_model.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/pop/test_estimation_objective.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/pop/test_foce_i.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/pop/test_gof.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/pop/test_pop_vpc.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/pop/test_saem.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/pop/test_vpc.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/report/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/report/test_docx.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/report/test_pdf.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/sim/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/sim/test_methods.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/sim/test_roundtrip_nca.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/sim/test_sim_models.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/sim/test_simulate.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/test_benchmark.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/validation/__init__.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/validation/test_dissolution_bootf2_reference.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/validation/test_dissolution_models_reference.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/validation/test_ivivc_wn_lr_reference.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/validation/test_nca_noncompart_reference.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/validation/test_nca_ss_reference.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/validation/test_nca_theoph_reference.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/validation/test_nca_urine_reference.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/validation/test_nca_validation.py +0 -0
- {openpkflow-2.3.0 → openpkflow-2.5.0}/tests/validation/test_sim_validation.py +0 -0
|
@@ -6,6 +6,9 @@ on:
|
|
|
6
6
|
pull_request:
|
|
7
7
|
branches: [main]
|
|
8
8
|
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
|
|
9
12
|
jobs:
|
|
10
13
|
test:
|
|
11
14
|
name: Python ${{ matrix.python-version }}
|
|
@@ -16,10 +19,10 @@ jobs:
|
|
|
16
19
|
python-version: ["3.10", "3.11", "3.12"]
|
|
17
20
|
|
|
18
21
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
22
|
+
- uses: actions/checkout@v6
|
|
20
23
|
|
|
21
24
|
- name: Set up Python ${{ matrix.python-version }}
|
|
22
|
-
uses: actions/setup-python@
|
|
25
|
+
uses: actions/setup-python@v6
|
|
23
26
|
with:
|
|
24
27
|
python-version: ${{ matrix.python-version }}
|
|
25
28
|
|
|
@@ -32,7 +35,7 @@ jobs:
|
|
|
32
35
|
run: pytest --tb=short -q --cov=openpkflow --cov-report=xml
|
|
33
36
|
|
|
34
37
|
- name: Upload coverage to Codecov
|
|
35
|
-
uses: codecov/codecov-action@
|
|
38
|
+
uses: codecov/codecov-action@v6
|
|
36
39
|
with:
|
|
37
40
|
files: coverage.xml
|
|
38
41
|
flags: ${{ matrix.python-version }}
|
|
@@ -46,9 +49,9 @@ jobs:
|
|
|
46
49
|
runs-on: ubuntu-latest
|
|
47
50
|
|
|
48
51
|
steps:
|
|
49
|
-
- uses: actions/checkout@
|
|
52
|
+
- uses: actions/checkout@v6
|
|
50
53
|
|
|
51
|
-
- uses: actions/setup-python@
|
|
54
|
+
- uses: actions/setup-python@v6
|
|
52
55
|
with:
|
|
53
56
|
python-version: "3.12"
|
|
54
57
|
|
|
@@ -61,9 +64,9 @@ jobs:
|
|
|
61
64
|
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.draft == false)
|
|
62
65
|
|
|
63
66
|
steps:
|
|
64
|
-
- uses: actions/checkout@
|
|
67
|
+
- uses: actions/checkout@v6
|
|
65
68
|
|
|
66
|
-
- uses: actions/setup-python@
|
|
69
|
+
- uses: actions/setup-python@v6
|
|
67
70
|
with:
|
|
68
71
|
python-version: "3.12"
|
|
69
72
|
|
|
@@ -81,7 +84,7 @@ jobs:
|
|
|
81
84
|
--benchmark-columns=min,mean,stddev,rounds,iterations
|
|
82
85
|
|
|
83
86
|
- name: Upload benchmark results
|
|
84
|
-
uses: actions/upload-artifact@
|
|
87
|
+
uses: actions/upload-artifact@v7
|
|
85
88
|
with:
|
|
86
89
|
name: benchmark-results-${{ github.sha }}
|
|
87
90
|
path: benchmark.json
|
|
@@ -14,10 +14,10 @@ jobs:
|
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
|
|
16
16
|
steps:
|
|
17
|
-
- uses: actions/checkout@
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
18
|
|
|
19
19
|
- name: Set up Python
|
|
20
|
-
uses: actions/setup-python@
|
|
20
|
+
uses: actions/setup-python@v6
|
|
21
21
|
with:
|
|
22
22
|
python-version: "3.12"
|
|
23
23
|
|
|
@@ -31,7 +31,7 @@ jobs:
|
|
|
31
31
|
run: python -m twine check dist/*
|
|
32
32
|
|
|
33
33
|
- name: Upload build artifacts
|
|
34
|
-
uses: actions/upload-artifact@
|
|
34
|
+
uses: actions/upload-artifact@v7
|
|
35
35
|
with:
|
|
36
36
|
name: dist
|
|
37
37
|
path: dist/
|
|
@@ -47,7 +47,7 @@ jobs:
|
|
|
47
47
|
|
|
48
48
|
steps:
|
|
49
49
|
- name: Download build artifacts
|
|
50
|
-
uses: actions/download-artifact@
|
|
50
|
+
uses: actions/download-artifact@v8
|
|
51
51
|
with:
|
|
52
52
|
name: dist
|
|
53
53
|
path: dist/
|
|
@@ -68,7 +68,7 @@ jobs:
|
|
|
68
68
|
|
|
69
69
|
steps:
|
|
70
70
|
- name: Download build artifacts
|
|
71
|
-
uses: actions/download-artifact@
|
|
71
|
+
uses: actions/download-artifact@v8
|
|
72
72
|
with:
|
|
73
73
|
name: dist
|
|
74
74
|
path: dist/
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Slow validation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
schedule:
|
|
6
|
+
- cron: "0 3 * * 0"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
slow-validation:
|
|
10
|
+
name: Slow validation (Python 3.12)
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v6
|
|
15
|
+
|
|
16
|
+
- uses: actions/setup-python@v6
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
|
|
20
|
+
- name: Install package and dev dependencies
|
|
21
|
+
run: |
|
|
22
|
+
python -m pip install --upgrade pip
|
|
23
|
+
pip install -e ".[dev,reports,ml]"
|
|
24
|
+
|
|
25
|
+
- name: Run slow validation tests
|
|
26
|
+
run: pytest -m slow tests/validation -q
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
This file provides guidance to
|
|
3
|
+
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
|
|
4
4
|
|
|
5
5
|
## Scope and boundary (read this first)
|
|
6
6
|
|
|
@@ -14,6 +14,14 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
14
14
|
- `report/` — HTML, PDF, DOCX, Markdown
|
|
15
15
|
- `validation/` — cross-checks against published references
|
|
16
16
|
|
|
17
|
+
**Web app layer (same as CLAUDE.md):**
|
|
18
|
+
- `api/` — FastAPI REST adapter. Current routers: nca, dissolution, sim, ivivc, be.
|
|
19
|
+
Adding a new endpoint requires a schema (schemas/), service (services/), router (routers/),
|
|
20
|
+
and registration in main.py. Follow the existing nca router pattern exactly.
|
|
21
|
+
- `webapp/` — React + Vite + Tailwind frontend. Current pages: Home, NCA, Dissolution, Sim,
|
|
22
|
+
IVIVC, BE. See `progress_web_app.md` for the full file map and next candidates.
|
|
23
|
+
- Do NOT add pharmacometric logic to api/ or webapp/. Add to src/openpkflow/ first.
|
|
24
|
+
|
|
17
25
|
**Out of scope — do not extend (existing code is frozen at v2.3.0):**
|
|
18
26
|
- `pop/estimation/` — FOCE-I and SAEM exist but must not be extended. Pharmpy and
|
|
19
27
|
nlmixr2 are validated NLME engines. Bug fixes only. No IOV, no 3-cmt, no covariate
|
|
@@ -28,7 +36,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
28
36
|
3. The former covariate API in `pop/estimation/` (`CovariateModel`, `apply_covariates`)
|
|
29
37
|
was a non-functional v2.2.0 skeleton and was removed in v2.3.0. Do not reintroduce
|
|
30
38
|
covariate estimation without a full external validation plan.
|
|
31
|
-
4. When ROADMAP.md and
|
|
39
|
+
4. When ROADMAP.md and AGENTS.md disagree, AGENTS.md wins. Flag the conflict to the user.
|
|
32
40
|
5. Never use `--no-verify` to bypass pre-commit hooks. Fix the underlying issue instead.
|
|
33
41
|
|
|
34
42
|
---
|
|
@@ -11,6 +11,49 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
## [2.5.0] - 2026-06-12
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Student-friendly interface (`openpkflow.student`) with three one-call
|
|
19
|
+
functions: `analyze_pk()` for NCA, `fit_dissolution()` for dissolution
|
|
20
|
+
model fitting + f1/f2 comparison, and `fit_pk_model()` for 1/2-compartment
|
|
21
|
+
PK curve fitting.
|
|
22
|
+
- `student/sim.py` compartmental equations delegate to validated
|
|
23
|
+
`sim/methods.py` functions (c_1cmt_oral, c_1cmt_iv_bolus, c_2cmt_oral) --
|
|
24
|
+
no duplicate math.
|
|
25
|
+
- Hixson-Crowell model added to dissolution `_REGISTRY` (now 6 default
|
|
26
|
+
models: zero_order, first_order, higuchi, korsmeyer_peppas, weibull,
|
|
27
|
+
hixson_crowell).
|
|
28
|
+
- External validation of NCA engine against WinNonlin(r) (Kim et al. 2018,
|
|
29
|
+
PMC6989226, Table 3): all 8 parameters within 0.02% for Theoph Subject 8
|
|
30
|
+
(Cmax, Tmax, lambda_z, t1/2, AUClast, AUCinf, CL/F, Vz/F).
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Mandated disclaimer text (CLAUDE.md rule 7) applied to all student module
|
|
35
|
+
report summaries.
|
|
36
|
+
- `test_all_default_models_fit` updated to expect 6 default models.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## [2.4.0] — 2026-05-30
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- Research-grade replicate bioequivalence screening via `replicate_be()`:
|
|
45
|
+
long-format full/partial replicate data parsing, GMR + conventional 90% CI,
|
|
46
|
+
CVwR estimation, EMA-style scaled-limit summaries, and FDA-style RSABE point
|
|
47
|
+
criterion screening. These outputs are explicitly documented as exploratory
|
|
48
|
+
and not a replacement for jurisdiction-specific validated SAS/R workflows.
|
|
49
|
+
- Replicate BE CLI/report workflow: `openpkflow be replicate`, HTML/Markdown
|
|
50
|
+
reports, JSON export, example partial-replicate CSV, and scalar reference
|
|
51
|
+
validation fixtures for the screening calculations.
|
|
52
|
+
- Release-readiness documentation and slow-validation workflow for heavyweight
|
|
53
|
+
reference checks, plus a read-only `scripts/release_readiness.py` checker.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
14
57
|
## [2.3.0] — 2026-05-24
|
|
15
58
|
|
|
16
59
|
### Breaking Changes
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Scope and boundary (read this first)
|
|
6
|
+
|
|
7
|
+
**In scope — build, extend, polish:**
|
|
8
|
+
- `dissolution/` — f1, f2, MSD, model fitting, multi-media (greenfield moat vs competitors)
|
|
9
|
+
- `nca/` — sparse, steady-state, urinary, CDISC PP (greenfield moat)
|
|
10
|
+
- `ivivc/` — Level A (greenfield moat)
|
|
11
|
+
- `sim/` — analytical compartment models
|
|
12
|
+
- `bayes/` — MAP individual PK (scipy, screening tool, not regulatory primary)
|
|
13
|
+
- `be/` — paired TOST convenience layer + BioEqPy export
|
|
14
|
+
- `report/` — HTML, PDF, DOCX, Markdown
|
|
15
|
+
- `validation/` — cross-checks against published references
|
|
16
|
+
|
|
17
|
+
**Web app layer (ratified 2026-05-31 — see PIVOT_PLAN.md Option A):**
|
|
18
|
+
- `api/` — FastAPI REST adapter. Wraps `openpkflow` public APIs. No pharmacometric math.
|
|
19
|
+
In scope: adding endpoints, fixing bugs in the adapter layer, improving error handling.
|
|
20
|
+
Current routers: nca, dissolution, sim, ivivc, be.
|
|
21
|
+
- `webapp/` — React + Vite + Tailwind frontend. In scope: UI improvements, new pages for
|
|
22
|
+
modules already covered by the backend, bug fixes.
|
|
23
|
+
Current pages: Home, NCA (/nca), Dissolution (/dissolution), Simulation (/sim),
|
|
24
|
+
IVIVC (/ivivc), Bioequivalence (/be).
|
|
25
|
+
- Both dirs are separate from `src/openpkflow/` and do NOT modify the frozen library.
|
|
26
|
+
- Do not add new pharmacometric logic to `api/` or `webapp/`. If a new analysis is needed,
|
|
27
|
+
first add it to the appropriate `src/openpkflow/` module, then expose it in `api/`.
|
|
28
|
+
- See `progress_web_app.md` for the full file map, completed features, and next candidates.
|
|
29
|
+
|
|
30
|
+
**Out of scope — do not extend (existing code is frozen at v2.3.0):**
|
|
31
|
+
- `pop/estimation/` — FOCE-I and SAEM exist but must not be extended. Pharmpy and
|
|
32
|
+
nlmixr2 are validated NLME engines. Bug fixes only. No IOV, no 3-cmt, no covariate
|
|
33
|
+
selection, no iv_infusion route for estimation.
|
|
34
|
+
- RSABE / replicate-design BE — belongs in companion BioEqPy package, not here.
|
|
35
|
+
- WeasyPrint, Streamlit/Gradio GUI (as embedded GUI in the library), CDISC Define.xml, eCTD table formatting.
|
|
36
|
+
Note: The `api/` + `webapp/` web application is a separate layer, not a Streamlit/Gradio embed.
|
|
37
|
+
|
|
38
|
+
**Rules for AI agents:**
|
|
39
|
+
1. Before adding any feature, verify it is on the in-scope list. If not, ask the user.
|
|
40
|
+
2. Validation work outranks new features. Do not add a new module when existing
|
|
41
|
+
modules lack NONMEM/PKNCA cross-validation.
|
|
42
|
+
3. The former covariate API in `pop/estimation/` (`CovariateModel`, `apply_covariates`)
|
|
43
|
+
was a non-functional v2.2.0 skeleton and was removed in v2.3.0. Do not reintroduce
|
|
44
|
+
covariate estimation without a full external validation plan.
|
|
45
|
+
4. When ROADMAP.md and CLAUDE.md disagree, CLAUDE.md wins. Flag the conflict to the user.
|
|
46
|
+
5. Never use `--no-verify` to bypass pre-commit hooks. Fix the underlying issue instead.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Identity
|
|
51
|
+
|
|
52
|
+
**Package:** `openpkflow`
|
|
53
|
+
**Author:** Priyam Thakar <priyamthakar1@gmail.com>
|
|
54
|
+
**GitHub:** https://github.com/priyamthakar/openpkflow
|
|
55
|
+
**PyPI target:** `pip install openpkflow`
|
|
56
|
+
**License:** MIT
|
|
57
|
+
**Philosophy:** Transparent, reproducible, open-source Python workflow for dissolution, NCA, PK/PD simulation, and pharmacometric reporting. Does not replace expert regulatory judgement or validated commercial platforms.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Commands
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Install in editable mode with dev tools
|
|
65
|
+
pip install -e ".[dev]"
|
|
66
|
+
|
|
67
|
+
# Run all tests (exclude slow MCMC tests)
|
|
68
|
+
pytest --ignore=tests/pop/test_saem.py --ignore=tests/bayes/test_bayes_be.py -k "not MCMC and not mcmc"
|
|
69
|
+
|
|
70
|
+
# Run NCA + validation tests (fast, complete coverage)
|
|
71
|
+
pytest tests/nca/ tests/validation/
|
|
72
|
+
|
|
73
|
+
# Run single module
|
|
74
|
+
pytest tests/nca/test_methods.py
|
|
75
|
+
|
|
76
|
+
# Run with coverage
|
|
77
|
+
pytest --cov=src/openpkflow --cov-report=term-missing
|
|
78
|
+
|
|
79
|
+
# Lint and auto-fix
|
|
80
|
+
ruff check src/ tests/ --fix
|
|
81
|
+
ruff format src/ tests/
|
|
82
|
+
|
|
83
|
+
# Type-check
|
|
84
|
+
mypy src/openpkflow
|
|
85
|
+
|
|
86
|
+
# Build wheel/sdist
|
|
87
|
+
python -m build
|
|
88
|
+
|
|
89
|
+
# PKNCA cross-validation (requires R + PKNCA)
|
|
90
|
+
"C:\Program Files\R\R-4.6.0\bin\Rscript.exe" -e ".libPaths('D:/R-library/4.6'); source('scripts/pknca_theoph_crossval.R')"
|
|
91
|
+
|
|
92
|
+
# CLI
|
|
93
|
+
openpkflow version
|
|
94
|
+
openpkflow similarity --reference "20,40,60,80" --test "21,39,61,79"
|
|
95
|
+
openpkflow dissolution compare data.csv --reference reference --test test --report out.html
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Architecture
|
|
101
|
+
|
|
102
|
+
- **Layout:** `src/` layout (PEP 517/518). Always import from `src/openpkflow/`, never from project root.
|
|
103
|
+
- **Build:** hatchling (`pyproject.toml`)
|
|
104
|
+
- **Python floor:** 3.10+
|
|
105
|
+
- **Core deps:** numpy, pandas, scipy, matplotlib, pydantic, typer, jinja2
|
|
106
|
+
- **Optional deps:** `[reports]` (openpyxl, reportlab, python-docx), `[bayes]` (pymc, arviz, cmdstanpy), `[ml]` (scikit-learn, torch), `[dev]` (pytest, ruff, mypy, build, twine)
|
|
107
|
+
- **Avoid WeasyPrint** — Windows/GTK dependencies are painful. Use ReportLab for PDF.
|
|
108
|
+
|
|
109
|
+
### Module map
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
dissolution/ -- f1, f2, bootstrap_f2, model fitting, loader, reporting <- DONE v0.1-v0.2
|
|
113
|
+
nca/ -- AUC, lambda_z, PK parameters, steady-state, urine, tlast <- DONE v0.4.0, v1.3.0
|
|
114
|
+
ivivc/ -- Wagner-Nelson, Loo-Riegelman, convolution, Levy, %PE <- DONE v1.2.0
|
|
115
|
+
sim/ -- analytical compartment models, dosing, superposition <- DONE v0.5.0
|
|
116
|
+
pop/ — GOF plots (4-panel), VPC (simulation-based), dataset ← DONE v0.6.0
|
|
117
|
+
bayes/ — ImportError guards; [bayes] extras wired; PyMC deferred ← v0.8.0 deferred
|
|
118
|
+
ml/ — PKSurrogate (torch MLP, EXPERIMENTAL) ← DONE v0.9.0
|
|
119
|
+
report/ — Markdown, HTML, PDF (ReportLab), Word (python-docx) ← DONE v0.3.0
|
|
120
|
+
datasets/ — example CSVs (dissolution + theoph NCA reference)
|
|
121
|
+
validation/ — reference comparison utilities
|
|
122
|
+
cli.py — Typer CLI entry point
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### NCA module layout
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
nca/
|
|
129
|
+
__init__.py — exports all public symbols
|
|
130
|
+
methods.py — pure math: auc_linear, auc_log, auc_linear_up_log_down,
|
|
131
|
+
cmax, tmax, lambda_z (BAR² auto + manual), auc_inf_obs,
|
|
132
|
+
auc_percent_extrapolated, clearance_volume_parameters
|
|
133
|
+
_validate_time_conc rejects NaN/Inf, negative conc
|
|
134
|
+
loader.py — load_nca_csv(): CSV load + BLQ handling
|
|
135
|
+
results.py — NCAResult (per-subject), NCASummaryResults dataclasses
|
|
136
|
+
study.py — NCAStudy: from_csv(), analyze() -> NCASummaryResults
|
|
137
|
+
tlast trimming: strips trailing conc <= 0 before AUClast
|
|
138
|
+
reporting.py — report_nca_single(), report_nca_summary() (HTML + Markdown)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### NCA data flow
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
CSV file
|
|
145
|
+
-> load_nca_csv() BLQ-handled DataFrame (subject, time, conc, dose, route)
|
|
146
|
+
-> NCAStudy(df, auc_method, blq_method)
|
|
147
|
+
-> study.analyze() per-subject loop:
|
|
148
|
+
1. tlast trimming: strip trailing conc <= 0 (FDA/EMA)
|
|
149
|
+
2. AUClast via chosen method (linear/log/linear_up_log_down)
|
|
150
|
+
3. Cmax, Tmax from full profile
|
|
151
|
+
4. lambda_z BAR² auto (post-Cmax positive points)
|
|
152
|
+
5. AUCinf = AUClast + Clast/lambda_z
|
|
153
|
+
6. CL_F/Vz_F (oral) or CL/Vz (IV)
|
|
154
|
+
-> NCASummaryResults list of NCAResult
|
|
155
|
+
-> summary.to_dataframe() pandas DataFrame
|
|
156
|
+
-> summary.report("out.html") -> report_nca_summary() -> nca_summary_report.html
|
|
157
|
+
-> result.report("sub.html") -> report_nca_single() -> nca_single_report.html
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Sim module layout
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
sim/
|
|
164
|
+
__init__.py — exports all public symbols
|
|
165
|
+
methods.py — pure math: c_1cmt_iv_bolus, c_1cmt_iv_infusion, c_1cmt_oral,
|
|
166
|
+
c_2cmt_iv_bolus, c_2cmt_oral, superpose
|
|
167
|
+
dosing.py — Dose, DoseRegimen dataclasses; DoseRegimen.from_repeated()
|
|
168
|
+
models.py — OneCompartmentModel, TwoCompartmentModel (CL/V parameterization)
|
|
169
|
+
simulate.py — simulate(model, regimen, times) -> SimulationResult
|
|
170
|
+
results.py — SimulationResult: times, concs, model, regimen, .summary(), .plot(), .report()
|
|
171
|
+
plotting.py — pk_profile_plot_b64() base64 PNG helper
|
|
172
|
+
reporting.py — report_simulation() dispatcher (HTML + Markdown + PDF + DOCX)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Sim data flow
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
OneCompartmentModel(route, CL, Vz) or TwoCompartmentModel(...)
|
|
179
|
+
+ DoseRegimen.from_repeated(amount, route, tau, n_doses)
|
|
180
|
+
+ times array
|
|
181
|
+
-> simulate() per-dose analytical superposition (linear systems only)
|
|
182
|
+
-> SimulationResult .times, .concs, .Cmax, .Tmax
|
|
183
|
+
-> result.report("sim.html") -> report_simulation() -> sim_report.html
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Dissolution data flow
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
CSV file
|
|
190
|
+
→ load_dissolution_csv() # pydantic-validated DataFrame
|
|
191
|
+
→ DissolutionStudy.from_csv() # groups by formulation label
|
|
192
|
+
→ study.compare(ref, test) # calls get_formulation_means(), then f1/f2
|
|
193
|
+
→ ComparisonResult # dataclass: f1_value, f2_value, means, time_points
|
|
194
|
+
→ result.summary() # text to stdout
|
|
195
|
+
→ result.report("out.html") # → report_dissolution() → render_html_report()
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Report rendering
|
|
199
|
+
|
|
200
|
+
- HTML template lives at `src/openpkflow/report/templates/dissolution_report.html`
|
|
201
|
+
- Jinja2 renderer is `src/openpkflow/report/html.py` — note: `zip` is manually injected into `env.globals` because Jinja2 does not expose Python builtins
|
|
202
|
+
- Markdown renderer is `src/openpkflow/dissolution/reporting.py`
|
|
203
|
+
- Format is inferred from file extension in `report_dissolution()`
|
|
204
|
+
|
|
205
|
+
### Windows console constraint
|
|
206
|
+
|
|
207
|
+
All CLI output and docstrings must use ASCII-only characters. Unicode punctuation (em dashes `—`, right arrows `→`, `>=`, `<=`) causes `UnicodeEncodeError` on Windows cp1252 consoles. Use plain ASCII equivalents (`>=`, `->`, `-`).
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Validation & Cross-Validation
|
|
212
|
+
|
|
213
|
+
### PKNCA NCA cross-validation
|
|
214
|
+
|
|
215
|
+
The NCA module is cross-validated against PKNCA 0.12.1 (Denney et al., 2015) on the
|
|
216
|
+
12-subject R nlme::Theoph theophylline dataset. AUClast matches within 2% relative
|
|
217
|
+
tolerance for every subject. Cmax matches exactly.
|
|
218
|
+
|
|
219
|
+
Run with:
|
|
220
|
+
```bash
|
|
221
|
+
"C:\Program Files\R\R-4.6.0\bin\Rscript.exe" -e ".libPaths('D:/R-library/4.6'); source('scripts/pknca_theoph_crossval.R')"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
The R script outputs a `_PKNCA_REFERENCE` dict that goes into
|
|
225
|
+
`tests/validation/test_nca_theoph_reference.py`.
|
|
226
|
+
|
|
227
|
+
### Validation test suite
|
|
228
|
+
|
|
229
|
+
- `tests/validation/test_nca_theoph_reference.py` — per-subject PKNCA cross-validation
|
|
230
|
+
- `tests/validation/test_nca_validation.py` — analytical truth recovery (IV bolus, oral)
|
|
231
|
+
- `tests/validation/test_sim_validation.py` — Gibaldi & Perrier analytical solutions
|
|
232
|
+
- `tests/nca/test_methods.py` — edge cases: all-zero, NaN/Inf, trailing zeros, mixed zeros
|
|
233
|
+
|
|
234
|
+
Each test cites a source: paper DOI, FDA guidance ID, or reference implementation.
|
|
235
|
+
|
|
236
|
+
### Known edge cases tested
|
|
237
|
+
|
|
238
|
+
- All-zero concentrations → AUClast = 0 (no crash)
|
|
239
|
+
- NaN/Inf concentrations → ValueError (not silently propagated)
|
|
240
|
+
- Trailing zero concentrations → trimmed by tlast logic in study.py
|
|
241
|
+
- Single-point profiles → ValueError (need >= 2 for AUC)
|
|
242
|
+
- Empty arrays → ValueError
|
|
243
|
+
- Negative concentrations → ValueError
|
|
244
|
+
- Non-increasing times → ValueError
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Current focus
|
|
249
|
+
|
|
250
|
+
v2.3.0 is current — Pop PK FOCE-I validated against nlme reference, covariate skeleton removed.
|
|
251
|
+
Next focus: conda-forge distribution + PowerTOST cross-validation (nice-to-have).
|
|
252
|
+
See `ROADMAP.md` for the full ladder.
|
|
253
|
+
|
|
254
|
+
**Before any new feature:** run `python -m build && python -m twine check dist/*` to confirm the wheel is clean.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Release Ladder
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
0.1.0 f1, f2, input validation, CSV loader, CLI, Markdown+HTML report stub, tests DONE
|
|
262
|
+
0.1.1 bootstrap_f2, profile plots in HTML reports, CI, example datasets, py.typed DONE
|
|
263
|
+
0.1.2 PyPI publish, Trusted Publishing workflow DONE
|
|
264
|
+
0.1.3 README polish, f2_method="regulatory" option, CV% warning in compare()
|
|
265
|
+
0.2.0 dissolution model fitting (Weibull, Korsmeyer-Peppas, Higuchi, first-order,
|
|
266
|
+
zero-order) — scipy curve_fit, AIC/BIC/R2, fit overlay in HTML report
|
|
267
|
+
0.3.0 full Markdown + HTML + ReportLab PDF report generator
|
|
268
|
+
0.4.0 NCA engine (AUC, Cmax, Tmax, lambda_z, t1/2, CL/F, Vz/F)
|
|
269
|
+
0.5.0 PK simulation (1-comp, 2-comp, oral, IV, infusion, repeated dosing) DONE
|
|
270
|
+
0.6.0 population PK diagnostics, GOF plots, VPC helpers DONE
|
|
271
|
+
0.7.0 Pharmpy bridge SKIPPED (reserved)
|
|
272
|
+
0.8.0 Bayesian PK (PyMC, CmdStanPy) DEFERRED (extras wired)
|
|
273
|
+
0.9.0 ML surrogate (torch MLP, EXPERIMENTAL) DONE
|
|
274
|
+
1.0.0 stable public release DONE
|
|
275
|
+
1.1.0 dissolution regulatory toolkit: MSD, model-dependent comparison, RSD check DONE
|
|
276
|
+
1.2.0 IVIVC Level A: Wagner-Nelson, Loo-Riegelman, convolution predict, %PE DONE
|
|
277
|
+
1.3.0 NCA expansion: steady-state, urinary excretion, CDISC PP output DONE
|
|
278
|
+
1.4.0 multi-media dissolution: pH 1.2/4.5/6.8 panel, alcohol dose-dumping DONE
|
|
279
|
+
1.5.0 Sparse-sampling NCA: model-informed 1-cmt oral from 3-5 data points DONE
|
|
280
|
+
2.0.0 Bayesian PK: MAP individual estimation + full posterior + Bayesian BE (PyMC) DONE
|
|
281
|
+
2.1.0 FOCE-I & SAEM population PK (1-cmt, diagonal Omega) DONE
|
|
282
|
+
2.2.0 2-cmt models, full Omega matrix, covariate skeleton DONE
|
|
283
|
+
2.3.0 Remove covariate skeleton, FOCE-I nlme cross-validation, conda-forge prep DONE
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
See `ROADMAP.md` for full milestone detail, scope rationale, and definition of done.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Code Conventions
|
|
291
|
+
|
|
292
|
+
- **Type hints required** on all public API functions and methods.
|
|
293
|
+
- **Docstrings required** on all public functions — use NumPy docstring style.
|
|
294
|
+
- **No comments** unless the WHY is non-obvious (hidden constraint, subtle invariant, workaround).
|
|
295
|
+
- **No multi-paragraph docstrings** — one short description line, then Parameters/Returns/Raises sections only.
|
|
296
|
+
- Line length: 100 characters (ruff).
|
|
297
|
+
- Formatting: ruff (`ruff format`), linting: ruff lint, type-checking: mypy strict.
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Pharmacometric Correctness Rules
|
|
302
|
+
|
|
303
|
+
These are load-bearing. Do not violate them.
|
|
304
|
+
|
|
305
|
+
1. **f1/f2 require matched time points.** Caller supplies aligned `reference` and `test` arrays. The functions do not silently reindex or interpolate. If arrays differ in length, raise `ValueError`.
|
|
306
|
+
|
|
307
|
+
2. **AUC method must be explicit.** Never silently default. Always require the caller to pass the method name (`"linear"`, `"log"`, `"linear_up_log_down"`).
|
|
308
|
+
|
|
309
|
+
3. **Apparent vs absolute parameters must be distinguished in output names.** Use `CL_F` for oral apparent clearance, `CL` for IV-derived clearance. Never mix them in the same output without labelling.
|
|
310
|
+
|
|
311
|
+
4. **BLQ handling must be explicit.** Never silently drop BLQ values. Require the caller to specify the method.
|
|
312
|
+
|
|
313
|
+
5. **AUClast stops at tlast.** Following FDA/EMA NCA guidance, AUClast integrates from time 0 to tlast — the last time point with a quantifiable (positive) concentration. Trailing zero or negative concentrations must be excluded from the trapezoidal sum. This is enforced in `study.py`.
|
|
314
|
+
|
|
315
|
+
6. **NaN/Inf must be rejected.** `_validate_time_conc()` in `methods.py` rejects non-finite concentrations and times with explicit `ValueError` messages. Do not allow NaN to propagate silently through AUC calculations.
|
|
316
|
+
|
|
317
|
+
7. **Disclaimer required in all generated reports:**
|
|
318
|
+
> This report was generated using OpenPKFlow (open-source). Final regulatory interpretation should be reviewed by qualified formulation, pharmacokinetic, and regulatory experts.
|
|
319
|
+
|
|
320
|
+
8. **Do not copy code from R packages.** You may study R package behavior, formulas, documentation, and reference outputs. Do not copy source code unless the license explicitly allows it.
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Validation Discipline (mandatory from day one)
|
|
325
|
+
|
|
326
|
+
Every formula function must have at minimum two test cases:
|
|
327
|
+
|
|
328
|
+
1. A **degenerate/sanity case** with a hand-checkable answer (e.g., identical input → f2 = 100).
|
|
329
|
+
2. A **published reference example** with the citation in the test's docstring (paper DOI, FDA guidance ID, or R-package vignette name).
|
|
330
|
+
|
|
331
|
+
Tests must cite the source of the expected value. "I calculated it manually" is not a citation.
|
|
332
|
+
|
|
333
|
+
Known reference values:
|
|
334
|
+
- f2 = 100 when reference == test (by definition)
|
|
335
|
+
- f2 ≈ 50 when profiles differ by ~10 percentage points at each timepoint (FDA 1997 guidance threshold)
|
|
336
|
+
- f1 = 0 when reference == test (by definition)
|
|
337
|
+
- AUClast matches PKNCA 0.12.1 within 2% on all 12 theophylline subjects
|
|
338
|
+
- Cmax matches PKNCA 0.12.1 exactly
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Report Format Priority
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
v0.1.x: console summary → Markdown report → HTML report with embedded profile plot
|
|
346
|
+
v0.2.x: dissolution model fitting results in reports
|
|
347
|
+
v0.3.0: ReportLab PDF export, python-docx Word export
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
OpenPKFlow is **report-first**: the product delivers clean, professional, regulatory-style reports. Calculation correctness is necessary but not sufficient — the output must be shareable with supervisors, clients, CROs, and regulatory teams.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Git Conventions
|
|
355
|
+
|
|
356
|
+
- Never force-push. Never `--no-verify`. Never amend published commits.
|
|
357
|
+
- Commit message format: `<type>(<scope>): <short description>` (e.g., `feat(dissolution): add f1 and f2 with validation`)
|
|
358
|
+
- Version bumps: update `pyproject.toml` version and `CHANGELOG.md` together in one commit.
|
|
359
|
+
- Tag releases: `git tag v0.1.1`
|
|
360
|
+
|
|
361
|
+
## PyPI Upload Order
|
|
362
|
+
|
|
363
|
+
1. tests passing locally
|
|
364
|
+
2. `pip install -e .` works
|
|
365
|
+
3. `python -m build` succeeds
|
|
366
|
+
4. `python -m twine check dist/*` clean
|
|
367
|
+
5. Upload to TestPyPI: `twine upload --repository testpypi dist/*`
|
|
368
|
+
6. Fresh venv install: `pip install -i https://test.pypi.org/simple/ openpkflow` — verify `openpkflow version` and `openpkflow similarity` work
|
|
369
|
+
7. Upload to real PyPI: `twine upload dist/*`
|
|
370
|
+
|
|
371
|
+
**Preferred: PyPI Trusted Publishing** — no stored token, scoped to the repo. Set up at pypi.org/manage/account/publishing/ then add a `publish.yml` GitHub Actions workflow that triggers on version tags. Only the repo owner can configure this — it requires a one-time manual step at pypi.org.
|
|
372
|
+
|
|
373
|
+
Do not upload broken or untested wheels.
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Positioning Reminder
|
|
378
|
+
|
|
379
|
+
Use:
|
|
380
|
+
> **A transparent, reproducible, open-source Python workflow for dissolution, NCA, PK/PD simulation, and pharmacometric reporting.**
|
|
381
|
+
|
|
382
|
+
Never say:
|
|
383
|
+
> "FDA-approved", "replaces Certara", "AI discovers the perfect formulation."
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Dockerfile for OpenPKFlow with Jupyter and all extras
|
|
2
|
+
# Build: docker build -t openpkflow .
|
|
3
|
+
# Run: docker run -p 8888:8888 -v $(pwd):/workspace openpkflow
|
|
4
|
+
|
|
5
|
+
FROM python:3.12-slim
|
|
6
|
+
|
|
7
|
+
LABEL org.opencontainers.image.title="OpenPKFlow"
|
|
8
|
+
LABEL org.opencontainers.image.description="Python-first pharmacy toolkit for dissolution, NCA, PK/PD simulation, and pharmacometric reporting."
|
|
9
|
+
LABEL org.opencontainers.image.url="https://github.com/priyamthakar/openpkflow"
|
|
10
|
+
LABEL org.opencontainers.image.documentation="https://priyamthakar.github.io/openpkflow/"
|
|
11
|
+
|
|
12
|
+
WORKDIR /workspace
|
|
13
|
+
|
|
14
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
15
|
+
gcc g++ make \
|
|
16
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
17
|
+
|
|
18
|
+
COPY pyproject.toml README.md ./
|
|
19
|
+
COPY src/ src/
|
|
20
|
+
|
|
21
|
+
RUN pip install --no-cache-dir ".[reports,bayes,ml]" jupyter
|
|
22
|
+
|
|
23
|
+
EXPOSE 8888
|
|
24
|
+
|
|
25
|
+
ENTRYPOINT ["jupyter", "lab", "--ip=0.0.0.0", "--port=8888", "--allow-root", "--no-browser"]
|