openpkflow 2.2.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.2.0 → openpkflow-2.5.0}/.github/workflows/ci.yml +11 -8
- {openpkflow-2.2.0 → openpkflow-2.5.0}/.github/workflows/docs.yml +2 -2
- {openpkflow-2.2.0 → openpkflow-2.5.0}/.github/workflows/publish.yml +5 -5
- openpkflow-2.5.0/.github/workflows/slow-validation.yml +26 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/.gitignore +5 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/.pre-commit-config.yaml +1 -0
- openpkflow-2.2.0/CLAUDE.md → openpkflow-2.5.0/AGENTS.md +125 -34
- {openpkflow-2.2.0 → openpkflow-2.5.0}/CHANGELOG.md +69 -0
- openpkflow-2.5.0/CLAUDE.md +383 -0
- openpkflow-2.5.0/Dockerfile +25 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/FUTURE_PLANS.md +48 -3
- openpkflow-2.5.0/HANDOFF.md +264 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/PKG-INFO +62 -35
- {openpkflow-2.2.0 → openpkflow-2.5.0}/README.md +60 -34
- openpkflow-2.5.0/RELEASE.md +48 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/ROADMAP.md +55 -10
- {openpkflow-2.2.0 → openpkflow-2.5.0}/VALIDATION.md +84 -1
- 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.2.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.5.0/docs/reference/bayes.md +98 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/docs/reference/be.md +53 -3
- openpkflow-2.5.0/docs/reference/ivivc.md +66 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/docs/reference/nca.md +27 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/docs/reference/pop.md +9 -2
- openpkflow-2.5.0/docs/theory.md +482 -0
- openpkflow-2.5.0/docs/tutorials/bayes.md +262 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/docs/tutorials/be.md +39 -4
- {openpkflow-2.2.0 → openpkflow-2.5.0}/docs/tutorials/dissolution.md +5 -0
- openpkflow-2.5.0/docs/tutorials/ivivc.md +197 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/docs/tutorials/nca.md +18 -3
- openpkflow-2.5.0/docs/tutorials/pop.md +225 -0
- {openpkflow-2.2.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/be_report.html +761 -0
- openpkflow-2.5.0/examples/dissolution_comparison.html +362 -0
- openpkflow-2.5.0/examples/ivivc_report.md +63 -0
- openpkflow-2.5.0/examples/openpkflow_tour.ipynb +2352 -0
- openpkflow-2.5.0/examples/replicate_be_partial.csv +10 -0
- openpkflow-2.5.0/examples/report_dissolution.html +362 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/mkdocs.yml +8 -1
- openpkflow-2.5.0/progress_web_app.md +96 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/pyproject.toml +8 -2
- openpkflow-2.5.0/scripts/bootf2_dissolution_crossval.R +118 -0
- openpkflow-2.5.0/scripts/conda-forge/meta.yaml +64 -0
- openpkflow-2.5.0/scripts/crossval_winnonlin.py +252 -0
- openpkflow-2.5.0/scripts/dissolution_models_crossval.R +185 -0
- openpkflow-2.5.0/scripts/ivivc_wn_lr_crossval.R +171 -0
- openpkflow-2.5.0/scripts/nlmixr2_popk_crossval.R +194 -0
- openpkflow-2.5.0/scripts/noncompart_theoph_crossval.R +114 -0
- openpkflow-2.5.0/scripts/pknca_ss_crossval.R +149 -0
- openpkflow-2.5.0/scripts/pknca_theoph_crossval.R +178 -0
- openpkflow-2.5.0/scripts/pknca_theoph_crossval_extended.R +171 -0
- openpkflow-2.5.0/scripts/powertost_crossval.R +95 -0
- openpkflow-2.5.0/scripts/probe_bootf2.R +9 -0
- openpkflow-2.5.0/scripts/probe_foce_i.py +102 -0
- openpkflow-2.5.0/scripts/probe_noncompart.R +7 -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/scripts/urine_nca_crossval.R +220 -0
- openpkflow-2.5.0/site/app/index.html +3685 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/__init__.py +1 -1
- openpkflow-2.5.0/src/openpkflow/be/__init__.py +28 -0
- {openpkflow-2.2.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.2.0 → openpkflow-2.5.0}/src/openpkflow/cli.py +232 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/datasets/__init__.py +6 -0
- openpkflow-2.5.0/src/openpkflow/datasets/ss_crossval.csv +28 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/models.py +20 -3
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/study.py +2 -2
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/nca/__init__.py +2 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/nca/methods.py +80 -2
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/nca/results.py +5 -1
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/nca/study.py +10 -3
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/__init__.py +1 -1
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/foce_i.py +66 -18
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/foce_inner.py +10 -2
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/model.py +14 -53
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/objective.py +1 -3
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/plotting.py +1 -1
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/result.py +53 -49
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/saem.py +111 -30
- 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.2.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.2.0 → openpkflow-2.5.0}/tests/nca/test_methods.py +72 -0
- openpkflow-2.5.0/tests/nca/test_methods_hypothesis.py +621 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/nca/test_theoph_reference.py +2 -2
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/pop/test_estimation_model.py +4 -1
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/pop/test_foce_i.py +6 -2
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/pop/test_saem.py +6 -2
- 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.2.0 → openpkflow-2.5.0}/tests/test_cli.py +75 -1
- 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_dissolution_bootf2_reference.py +122 -0
- openpkflow-2.5.0/tests/validation/test_dissolution_models_reference.py +319 -0
- openpkflow-2.5.0/tests/validation/test_ivivc_wn_lr_reference.py +245 -0
- openpkflow-2.5.0/tests/validation/test_nca_noncompart_reference.py +314 -0
- openpkflow-2.5.0/tests/validation/test_nca_ss_reference.py +188 -0
- openpkflow-2.5.0/tests/validation/test_nca_theoph_reference.py +419 -0
- openpkflow-2.5.0/tests/validation/test_nca_urine_reference.py +252 -0
- openpkflow-2.5.0/tests/validation/test_nca_winnonlin_reference.py +788 -0
- openpkflow-2.5.0/tests/validation/test_pop_foce_reference.py +378 -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.2.0/HANDOFF.md +0 -204
- openpkflow-2.2.0/docs/tutorials/pop.md +0 -100
- openpkflow-2.2.0/src/openpkflow/be/__init__.py +0 -14
- openpkflow-2.2.0/src/openpkflow/be/reporting.py +0 -133
- openpkflow-2.2.0/src/openpkflow/pop/estimation/covariate.py +0 -225
- openpkflow-2.2.0/tests/validation/test_nca_theoph_reference.py +0 -278
- {openpkflow-2.2.0 → openpkflow-2.5.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/.github/dependabot.yml +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/CITATION.cff +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/CODE_OF_CONDUCT.md +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/CONTRIBUTING.md +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/LICENSE +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/SECURITY.md +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/V2_ARCHITECTURE_DECISION.md +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/codecov.yml +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/demo.ipynb +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/docs/logo.png +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/docs/reference/dissolution.md +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/docs/reference/ml.md +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/docs/reference/sim.md +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/docs/reference/validation.md +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/examples/dissolution_advanced.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/examples/dissolution_basic.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/bayes/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/bayes/bayes_be.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/bayes/bayes_pk.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/bayes/map_pk.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/bayes/priors.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/bayes/reporting.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/bayes/results.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/be/results.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/be/study.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/datasets/example_dissolution.csv +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/datasets/example_not_similar.csv +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/datasets/example_similar.csv +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/datasets/theoph.csv +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/bootstrap.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/loader.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/multi_media.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/plotting.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/reporting.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/dissolution/similarity.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/ivivc/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/ivivc/methods.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/ivivc/reporting.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/ivivc/results.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/ivivc/study.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/ml/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/ml/surrogate.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/nca/loader.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/nca/reporting.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/nca/sparse.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/dataset.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/diagnostics.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/omega.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/reporting.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/estimation/saem_kernel.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/gof.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/plotting.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/reporting.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/pop/vpc.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/py.typed +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/docx.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/html.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/pdf.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/bayes_be_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/be_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/dissolution_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/fit_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/ivivc_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/map_pk_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/multi_media_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/nca_single_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/nca_summary_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/pop_gof_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/pop_vpc_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/report/templates/sim_report.html +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/sim/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/sim/dosing.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/sim/methods.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/sim/models.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/sim/plotting.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/sim/reporting.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/sim/results.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/sim/simulate.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/src/openpkflow/validation/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/bayes/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/bayes/test_bayes_be.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/bayes/test_map_pk.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/be/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/be/test_methods.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/be/test_study.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/dissolution/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/dissolution/test_alternatives.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/dissolution/test_bootstrap.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/dissolution/test_excel_loader.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/dissolution/test_m13b.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/dissolution/test_model_comparison.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/dissolution/test_multi_media.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/dissolution/test_similarity.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/dissolution/test_study.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/ivivc/test_ivivc.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/ml/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/ml/test_surrogate.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/nca/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/nca/test_loader.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/nca/test_nca_pdf_docx.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/nca/test_nca_reporting.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/nca/test_nca_results.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/nca/test_sparse_nca.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/nca/test_steady_state_urine.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/nca/test_study.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/pop/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/pop/test_dataset.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/pop/test_estimation_diagnostics.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/pop/test_estimation_objective.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/pop/test_gof.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/pop/test_pop_vpc.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/pop/test_vpc.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/report/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/report/test_docx.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/report/test_pdf.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/sim/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/sim/test_methods.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/sim/test_roundtrip_nca.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/sim/test_sim_models.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/sim/test_simulate.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/test_benchmark.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/validation/__init__.py +0 -0
- {openpkflow-2.2.0 → openpkflow-2.5.0}/tests/validation/test_nca_validation.py +0 -0
- {openpkflow-2.2.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,45 @@
|
|
|
1
|
-
#
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Codex (Codex.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 (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
|
+
|
|
25
|
+
**Out of scope — do not extend (existing code is frozen at v2.3.0):**
|
|
26
|
+
- `pop/estimation/` — FOCE-I and SAEM exist but must not be extended. Pharmpy and
|
|
27
|
+
nlmixr2 are validated NLME engines. Bug fixes only. No IOV, no 3-cmt, no covariate
|
|
28
|
+
selection, no iv_infusion route for estimation.
|
|
29
|
+
- RSABE / replicate-design BE — belongs in companion BioEqPy package, not here.
|
|
30
|
+
- WeasyPrint, Streamlit/Gradio GUI, CDISC Define.xml, eCTD table formatting.
|
|
31
|
+
|
|
32
|
+
**Rules for AI agents:**
|
|
33
|
+
1. Before adding any feature, verify it is on the in-scope list. If not, ask the user.
|
|
34
|
+
2. Validation work outranks new features. Do not add a new module when existing
|
|
35
|
+
modules lack NONMEM/PKNCA cross-validation.
|
|
36
|
+
3. The former covariate API in `pop/estimation/` (`CovariateModel`, `apply_covariates`)
|
|
37
|
+
was a non-functional v2.2.0 skeleton and was removed in v2.3.0. Do not reintroduce
|
|
38
|
+
covariate estimation without a full external validation plan.
|
|
39
|
+
4. When ROADMAP.md and AGENTS.md disagree, AGENTS.md wins. Flag the conflict to the user.
|
|
40
|
+
5. Never use `--no-verify` to bypass pre-commit hooks. Fix the underlying issue instead.
|
|
2
41
|
|
|
3
|
-
|
|
42
|
+
---
|
|
4
43
|
|
|
5
44
|
## Identity
|
|
6
45
|
|
|
@@ -19,17 +58,17 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
19
58
|
# Install in editable mode with dev tools
|
|
20
59
|
pip install -e ".[dev]"
|
|
21
60
|
|
|
22
|
-
# Run all tests
|
|
23
|
-
pytest
|
|
61
|
+
# Run all tests (exclude slow MCMC tests)
|
|
62
|
+
pytest --ignore=tests/pop/test_saem.py --ignore=tests/bayes/test_bayes_be.py -k "not MCMC and not mcmc"
|
|
24
63
|
|
|
25
|
-
# Run tests
|
|
26
|
-
pytest
|
|
64
|
+
# Run NCA + validation tests (fast, complete coverage)
|
|
65
|
+
pytest tests/nca/ tests/validation/
|
|
27
66
|
|
|
28
|
-
# Run
|
|
29
|
-
pytest tests/
|
|
67
|
+
# Run single module
|
|
68
|
+
pytest tests/nca/test_methods.py
|
|
30
69
|
|
|
31
|
-
# Run
|
|
32
|
-
pytest
|
|
70
|
+
# Run with coverage
|
|
71
|
+
pytest --cov=src/openpkflow --cov-report=term-missing
|
|
33
72
|
|
|
34
73
|
# Lint and auto-fix
|
|
35
74
|
ruff check src/ tests/ --fix
|
|
@@ -41,8 +80,8 @@ mypy src/openpkflow
|
|
|
41
80
|
# Build wheel/sdist
|
|
42
81
|
python -m build
|
|
43
82
|
|
|
44
|
-
#
|
|
45
|
-
|
|
83
|
+
# PKNCA cross-validation (requires R + PKNCA)
|
|
84
|
+
"C:\Program Files\R\R-4.6.0\bin\Rscript.exe" -e ".libPaths('D:/R-library/4.6'); source('scripts/pknca_theoph_crossval.R')"
|
|
46
85
|
|
|
47
86
|
# CLI
|
|
48
87
|
openpkflow version
|
|
@@ -65,7 +104,7 @@ openpkflow dissolution compare data.csv --reference reference --test test --repo
|
|
|
65
104
|
|
|
66
105
|
```
|
|
67
106
|
dissolution/ -- f1, f2, bootstrap_f2, model fitting, loader, reporting <- DONE v0.1-v0.2
|
|
68
|
-
nca/ -- AUC, lambda_z, PK parameters, steady-state, urine
|
|
107
|
+
nca/ -- AUC, lambda_z, PK parameters, steady-state, urine, tlast <- DONE v0.4.0, v1.3.0
|
|
69
108
|
ivivc/ -- Wagner-Nelson, Loo-Riegelman, convolution, Levy, %PE <- DONE v1.2.0
|
|
70
109
|
sim/ -- analytical compartment models, dosing, superposition <- DONE v0.5.0
|
|
71
110
|
pop/ — GOF plots (4-panel), VPC (simulation-based), dataset ← DONE v0.6.0
|
|
@@ -85,12 +124,33 @@ nca/
|
|
|
85
124
|
methods.py — pure math: auc_linear, auc_log, auc_linear_up_log_down,
|
|
86
125
|
cmax, tmax, lambda_z (BAR² auto + manual), auc_inf_obs,
|
|
87
126
|
auc_percent_extrapolated, clearance_volume_parameters
|
|
127
|
+
_validate_time_conc rejects NaN/Inf, negative conc
|
|
88
128
|
loader.py — load_nca_csv(): CSV load + BLQ handling
|
|
89
129
|
results.py — NCAResult (per-subject), NCASummaryResults dataclasses
|
|
90
130
|
study.py — NCAStudy: from_csv(), analyze() -> NCASummaryResults
|
|
131
|
+
tlast trimming: strips trailing conc <= 0 before AUClast
|
|
91
132
|
reporting.py — report_nca_single(), report_nca_summary() (HTML + Markdown)
|
|
92
133
|
```
|
|
93
134
|
|
|
135
|
+
### NCA data flow
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
CSV file
|
|
139
|
+
-> load_nca_csv() BLQ-handled DataFrame (subject, time, conc, dose, route)
|
|
140
|
+
-> NCAStudy(df, auc_method, blq_method)
|
|
141
|
+
-> study.analyze() per-subject loop:
|
|
142
|
+
1. tlast trimming: strip trailing conc <= 0 (FDA/EMA)
|
|
143
|
+
2. AUClast via chosen method (linear/log/linear_up_log_down)
|
|
144
|
+
3. Cmax, Tmax from full profile
|
|
145
|
+
4. lambda_z BAR² auto (post-Cmax positive points)
|
|
146
|
+
5. AUCinf = AUClast + Clast/lambda_z
|
|
147
|
+
6. CL_F/Vz_F (oral) or CL/Vz (IV)
|
|
148
|
+
-> NCASummaryResults list of NCAResult
|
|
149
|
+
-> summary.to_dataframe() pandas DataFrame
|
|
150
|
+
-> summary.report("out.html") -> report_nca_summary() -> nca_summary_report.html
|
|
151
|
+
-> result.report("sub.html") -> report_nca_single() -> nca_single_report.html
|
|
152
|
+
```
|
|
153
|
+
|
|
94
154
|
### Sim module layout
|
|
95
155
|
|
|
96
156
|
```
|
|
@@ -117,20 +177,6 @@ OneCompartmentModel(route, CL, Vz) or TwoCompartmentModel(...)
|
|
|
117
177
|
-> result.report("sim.html") -> report_simulation() -> sim_report.html
|
|
118
178
|
```
|
|
119
179
|
|
|
120
|
-
### NCA data flow
|
|
121
|
-
|
|
122
|
-
```
|
|
123
|
-
CSV file
|
|
124
|
-
-> load_nca_csv() BLQ-handled DataFrame (subject, time, conc, dose, route)
|
|
125
|
-
-> NCAStudy(df, auc_method, blq_method)
|
|
126
|
-
-> study.analyze() per-subject loop: AUClast, Cmax, Tmax, lambda_z, AUCinf,
|
|
127
|
-
CL_F/Vz_F (oral) or CL/Vz (IV), warnings
|
|
128
|
-
-> NCASummaryResults list of NCAResult
|
|
129
|
-
-> summary.to_dataframe() pandas DataFrame
|
|
130
|
-
-> summary.report("out.html") -> report_nca_summary() -> nca_summary_report.html
|
|
131
|
-
-> result.report("sub.html") -> report_nca_single() -> nca_single_report.html
|
|
132
|
-
```
|
|
133
|
-
|
|
134
180
|
### Dissolution data flow
|
|
135
181
|
|
|
136
182
|
```
|
|
@@ -156,11 +202,48 @@ All CLI output and docstrings must use ASCII-only characters. Unicode punctuatio
|
|
|
156
202
|
|
|
157
203
|
---
|
|
158
204
|
|
|
205
|
+
## Validation & Cross-Validation
|
|
206
|
+
|
|
207
|
+
### PKNCA NCA cross-validation
|
|
208
|
+
|
|
209
|
+
The NCA module is cross-validated against PKNCA 0.12.1 (Denney et al., 2015) on the
|
|
210
|
+
12-subject R nlme::Theoph theophylline dataset. AUClast matches within 2% relative
|
|
211
|
+
tolerance for every subject. Cmax matches exactly.
|
|
212
|
+
|
|
213
|
+
Run with:
|
|
214
|
+
```bash
|
|
215
|
+
"C:\Program Files\R\R-4.6.0\bin\Rscript.exe" -e ".libPaths('D:/R-library/4.6'); source('scripts/pknca_theoph_crossval.R')"
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The R script outputs a `_PKNCA_REFERENCE` dict that goes into
|
|
219
|
+
`tests/validation/test_nca_theoph_reference.py`.
|
|
220
|
+
|
|
221
|
+
### Validation test suite
|
|
222
|
+
|
|
223
|
+
- `tests/validation/test_nca_theoph_reference.py` — per-subject PKNCA cross-validation
|
|
224
|
+
- `tests/validation/test_nca_validation.py` — analytical truth recovery (IV bolus, oral)
|
|
225
|
+
- `tests/validation/test_sim_validation.py` — Gibaldi & Perrier analytical solutions
|
|
226
|
+
- `tests/nca/test_methods.py` — edge cases: all-zero, NaN/Inf, trailing zeros, mixed zeros
|
|
227
|
+
|
|
228
|
+
Each test cites a source: paper DOI, FDA guidance ID, or reference implementation.
|
|
229
|
+
|
|
230
|
+
### Known edge cases tested
|
|
231
|
+
|
|
232
|
+
- All-zero concentrations → AUClast = 0 (no crash)
|
|
233
|
+
- NaN/Inf concentrations → ValueError (not silently propagated)
|
|
234
|
+
- Trailing zero concentrations → trimmed by tlast logic in study.py
|
|
235
|
+
- Single-point profiles → ValueError (need >= 2 for AUC)
|
|
236
|
+
- Empty arrays → ValueError
|
|
237
|
+
- Negative concentrations → ValueError
|
|
238
|
+
- Non-increasing times → ValueError
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
159
242
|
## Current focus
|
|
160
243
|
|
|
161
|
-
|
|
162
|
-
Next
|
|
163
|
-
See `ROADMAP.md` for the full
|
|
244
|
+
v2.3.0 is current — Pop PK FOCE-I validated against nlme reference, covariate skeleton removed.
|
|
245
|
+
Next focus: conda-forge distribution + PowerTOST cross-validation (nice-to-have).
|
|
246
|
+
See `ROADMAP.md` for the full ladder.
|
|
164
247
|
|
|
165
248
|
**Before any new feature:** run `python -m build && python -m twine check dist/*` to confirm the wheel is clean.
|
|
166
249
|
|
|
@@ -172,8 +255,7 @@ See `ROADMAP.md` for the full post-1.0.0 ladder.
|
|
|
172
255
|
0.1.0 f1, f2, input validation, CSV loader, CLI, Markdown+HTML report stub, tests DONE
|
|
173
256
|
0.1.1 bootstrap_f2, profile plots in HTML reports, CI, example datasets, py.typed DONE
|
|
174
257
|
0.1.2 PyPI publish, Trusted Publishing workflow DONE
|
|
175
|
-
0.1.3 README polish, f2_method="regulatory" option, CV% warning in compare()
|
|
176
|
-
validation claims softened
|
|
258
|
+
0.1.3 README polish, f2_method="regulatory" option, CV% warning in compare()
|
|
177
259
|
0.2.0 dissolution model fitting (Weibull, Korsmeyer-Peppas, Higuchi, first-order,
|
|
178
260
|
zero-order) — scipy curve_fit, AIC/BIC/R2, fit overlay in HTML report
|
|
179
261
|
0.3.0 full Markdown + HTML + ReportLab PDF report generator
|
|
@@ -190,6 +272,9 @@ See `ROADMAP.md` for the full post-1.0.0 ladder.
|
|
|
190
272
|
1.4.0 multi-media dissolution: pH 1.2/4.5/6.8 panel, alcohol dose-dumping DONE
|
|
191
273
|
1.5.0 Sparse-sampling NCA: model-informed 1-cmt oral from 3-5 data points DONE
|
|
192
274
|
2.0.0 Bayesian PK: MAP individual estimation + full posterior + Bayesian BE (PyMC) DONE
|
|
275
|
+
2.1.0 FOCE-I & SAEM population PK (1-cmt, diagonal Omega) DONE
|
|
276
|
+
2.2.0 2-cmt models, full Omega matrix, covariate skeleton DONE
|
|
277
|
+
2.3.0 Remove covariate skeleton, FOCE-I nlme cross-validation, conda-forge prep DONE
|
|
193
278
|
```
|
|
194
279
|
|
|
195
280
|
See `ROADMAP.md` for full milestone detail, scope rationale, and definition of done.
|
|
@@ -219,10 +304,14 @@ These are load-bearing. Do not violate them.
|
|
|
219
304
|
|
|
220
305
|
4. **BLQ handling must be explicit.** Never silently drop BLQ values. Require the caller to specify the method.
|
|
221
306
|
|
|
222
|
-
5. **
|
|
307
|
+
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`.
|
|
308
|
+
|
|
309
|
+
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.
|
|
310
|
+
|
|
311
|
+
7. **Disclaimer required in all generated reports:**
|
|
223
312
|
> This report was generated using OpenPKFlow (open-source). Final regulatory interpretation should be reviewed by qualified formulation, pharmacokinetic, and regulatory experts.
|
|
224
313
|
|
|
225
|
-
|
|
314
|
+
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.
|
|
226
315
|
|
|
227
316
|
---
|
|
228
317
|
|
|
@@ -239,6 +328,8 @@ Known reference values:
|
|
|
239
328
|
- f2 = 100 when reference == test (by definition)
|
|
240
329
|
- f2 ≈ 50 when profiles differ by ~10 percentage points at each timepoint (FDA 1997 guidance threshold)
|
|
241
330
|
- f1 = 0 when reference == test (by definition)
|
|
331
|
+
- AUClast matches PKNCA 0.12.1 within 2% on all 12 theophylline subjects
|
|
332
|
+
- Cmax matches PKNCA 0.12.1 exactly
|
|
242
333
|
|
|
243
334
|
---
|
|
244
335
|
|
|
@@ -11,6 +11,75 @@ 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
|
+
|
|
57
|
+
## [2.3.0] — 2026-05-24
|
|
58
|
+
|
|
59
|
+
### Breaking Changes
|
|
60
|
+
|
|
61
|
+
- **`pop/estimation/covariate.py` removed** — `CovariateModel`, `CovariateDef`, `apply_covariates`,
|
|
62
|
+
`pack_betas`, `unpack_betas` are deleted. These symbols were a non-functional skeleton in v2.2.0
|
|
63
|
+
that silently did nothing during `run_foce_i()` or `run_saem()` estimation. Users who imported
|
|
64
|
+
any of these symbols must remove those imports. No estimation results are affected.
|
|
65
|
+
- **`PopPKModel.covariate_model` field removed** — `PopPKModel` no longer accepts a
|
|
66
|
+
`covariate_model` keyword argument. Existing `PopPKModel` definitions should drop that argument.
|
|
67
|
+
- **`PopPKResult.covariate_betas` field removed** — `PopPKResult.to_dict()` no longer includes
|
|
68
|
+
the `covariate_betas` key.
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
|
|
72
|
+
- Pop PK cross-validation on the 12-subject Theophylline dataset:
|
|
73
|
+
`tests/validation/test_pop_foce_reference.py`. `run_foce_i()` typical values match
|
|
74
|
+
the `nlme` reference values from Pinheiro & Bates (2000), Table 8.1, within 20%
|
|
75
|
+
relative tolerance. A waiting nlmixr2 5.0.0 script is included at
|
|
76
|
+
`scripts/nlmixr2_popk_crossval.R` for rerun once Rtools/C compiler support is available.
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- `PopPKModel.n_betas` always returns 0 (property retained for API compatibility with existing
|
|
81
|
+
code that reads it; will be removed in v3.0.0).
|
|
82
|
+
|
|
14
83
|
## [2.2.0] — 2026-05-23
|
|
15
84
|
|
|
16
85
|
### Added
|