diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index a76a841..787561b 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -6,7 +6,7 @@ Before contributing, ensure you have the following installed: -- **.NET SDK**: 9.0.0 or later +- **.NET SDK**: 10.0.0 or later - **Node.js**: 18.x, 22.x, or 23.x (LTS versions recommended) - **npm**: 10.x or later @@ -72,6 +72,13 @@ GenPRES/ │ └── scenarios/ # Clinical scenarios ├── scripts/ # Utility scripts └── src/ # Source code + ├── Informedica.Agents.Lib/ # Agent-based concurrency library + ├── Informedica.DataPlatform.Lib/ # Data Platform integration + ├── Informedica.FHIR.Lib/ # FHIR resource conversion + ├── Informedica.FTK.Lib/ # Adult formulary parsing library + ├── Informedica.GenCORE.Lib/ # Core domain library + ├── Informedica.GenFORM.Lib/ # Formulary management library + ├── Informedica.GenORDER.Lib/ # Order processing library ├── Informedica.GenPRES.Client/ # Frontend application │ ├── Components/ # UI components │ ├── Pages/ # Page components @@ -82,19 +89,16 @@ GenPRES/ │ ├── Properties/ # Server properties │ ├── Scripts/ # Server scripts │ └── data/ # Server data directory - ├── Informedica.Agents.Lib/ # Agent-based concurrency library - ├── Informedica.GenCORE.Lib/ # Core domain library - ├── Informedica.GenFORM.Lib/ # Formulary management library - ├── Informedica.GenORDER.Lib/ # Order processing library + ├── Informedica.GenPRES.Shared/ # Shared types and API protocol ├── Informedica.GenSOLVER.Lib/ # Constraint solver library ├── Informedica.GenUNITS.Lib/ # Units of measurement library - ├── Informedica.NKF.Lib/ # Pediatric formulary parsing library - ├── Informedica.FTK.Lib/ # Adult formulary parsing library + ├── Informedica.HIXConnect.Lib/ # HIX Connect integration ├── Informedica.Logging.Lib/ # Logging utilities - ├── Informedica.NLP.Lib/ # OpenAI/LLM integration for NLP + ├── Informedica.MCP.Lib/ # Model Context Protocol for LLM integration + ├── Informedica.MetaVision.Lib/ # MetaVision integration + ├── Informedica.NKF.Lib/ # Pediatric formulary parsing library + ├── Informedica.NLP.Lib/ # Natural Language Processing for rule extraction ├── Informedica.OTS.Lib/ # Ontology Terminology Server integration - ├── Informedica.DataPlatform.Lib/ # Data Platform integration - ├── Informedica.HIXConnect.Lib/ # HIX Connect integration ├── Informedica.Utils.Lib/ # Utility functions ├── Informedica.ZForm.Lib/ # Z-Index form library └── Informedica.ZIndex.Lib/ # Z-Index database library @@ -111,27 +115,31 @@ GenPRES/ ### Documentation Files - `README.md` - Project overview -- `ARCHITECTURE.md` - Architecture documentation - `CHANGELOG.md` - Version history - `CONTRIBUTING.md` - Contribution guidelines - `CODE_OF_CONDUCT.md` - Code of conduct -- `DEVELOPMENT.md` - Development guide +- `DEVELOPMENT.md` - Development guide (this file) - `GOVERNANCE.md` - Project governance - `MAINTAINERS.md` - Maintainer information - `ROADMAP.md` - Project roadmap - `SECURITY.md` - Security policy - `SUPPORT.md` - Support information -- `WARP.md` - Warp-specific documentation +- `WARP.md` - Warp AI agent documentation +- `docs/mdr/design-history/architecture.md` - Technical architecture +- `docs/domain/` - Domain model specifications ## Directory Descriptions ### Core Directories -- **`.github/`** - Contains GitHub-specific configurations including issue templates, PR templates, workflow definitions, and development instructions -- **`benchmark/`** - Performance benchmarking suite for measuring solver and equation performance -- **`data/`** - Application data including cached drug information, configuration files, clinical data (age/weight tables, vital signs), and Z-Index drug database files -- **`docs/`** - Comprehensive documentation including MDR compliance, design history, requirements, risk analysis, usability testing, and clinical scenarios -- **`src/`** - Source code organized into client (Fable/React frontend), server (Saturn backend), and multiple F# libraries +- **`.github/`** - GitHub configurations (issue/PR templates, workflows, development instructions) +- **`benchmark/`** - Performance benchmarking suite +- **`data/`** - Application data (drug cache, configuration, clinical data, Z-Index database) +- **`docs/`** - Comprehensive documentation: + - `docs/domain/` - Domain model specifications (Core Domain, GenFORM, GenORDER, GenSOLVER) + - `docs/mdr/` - MDR compliance (design history, requirements, risk analysis, validation) + - `docs/scenarios/` - Clinical scenarios +- **`src/`** - Source code (client, server, and F# libraries) ### Library Modules @@ -145,6 +153,14 @@ Each `Informedica.*.Lib` directory contains: ## Project Architecture +For complete architectural documentation, see: + +- **[Architecture Overview](docs/mdr/design-history/architecture.md)**: Technical stack, server/client structure, Docker hosting, and build configuration +- **[Core Domain Model](docs/domain/core-domain.md)**: Transformation pipeline, constraint-based architecture, and domain concepts +- **[GenFORM](docs/domain/genform-free-text-to-operational-rules.md)**: Free text to Operational Knowledge Rules (OKRs) +- **[GenORDER](docs/domain/genorder-operational-rules-to-orders.md)**: OKRs to Order Scenarios +- **[GenSOLVER](docs/domain/gensolver-from-orders-to-quantitative-solutions.md)**: Constraint solving engine + ### Technology Stack This project is built on the [SAFE Stack](https://safe-stack.github.io/): @@ -152,32 +168,36 @@ This project is built on the [SAFE Stack](https://safe-stack.github.io/): - **Informedica.GenPRES.Server**: F# with [Saturn](https://saturnframework.org/) - **Informedica.GenPRES.Client**: F# with [Fable](https://fable.io/docs/) and [Elmish](https://elmish.github.io/elmish/) - **Testing**: Expecto with FsCheck for property-based testing -- **Build**: .NET 9.0 +- **Build**: .NET 10.0 ### Core Libraries -In dependency order: +For complete library specifications including capabilities and dependencies, see [GenFORM Appendix B.3](docs/domain/genform-free-text-to-operational-rules.md#addendum-b3-genform-libraries). + +Key libraries in dependency order: - **Informedica.Utils.Lib**: Shared utilities, common functions -- **Informedica.Agents.Lib**: Implementations of agent-based execution (MailboxProcessor) -- **Informedica.Logging.Lib**: Logging library enabling concurrent logging -- **Informedica.NLP.Lib**: Natural Language Processing utilities to parse free text inputs to structured operational knowledge rules -- **Informedica.OTS.Lib**: Data access layer for Google Sheets and CSV files and Ontology Terminlogy Server (OTS) -- **Informedica.GenUNITS.Lib**: Units of measure and unit-safe calculations -- **Informedica.GenSOLVER.Lib**: Quantitative constraint solving, equations, and variables -- **Informedica.GenCORE.Lib**: Core Domain model (patients, context, and order abstractions) -- **Informedica.ZIndex.Lib**: Medication and product database (source domain) -- **Informedica.ZForm.Lib**: Z-Index structured dosing reference data (source domain) -- **Informedica.NKF.Lib**: "Nederlands Kinderformularium" dose rule extraction and processing -- **Informedica.FTK.Lib**: "Farmacotherapeutisch Kompas" dose rule extraction and processing -- **Informedica.GenFORM.Lib**: Domain library for all Operational Knowledge Rules (order constraints) -- **Informedica.GenORDER.Lib**: Generic clinical order scenarios and execution (including prescriptions, nutrition, and fluids) -- **Informedica.MCP.Lib**: Enabling MCP implementation of core libraries for use with LLMs and chatbots -- **Informedica.FHIR.Lib**: Converting GenPRES domain models to/from FHIR resources -- **Informedica.DataPlatorm.Lib**: Sending and retrieving patient and order data to/from Data Platform -- **Informedica.HIXConnect.Lib**: Sending and retrieving patient and order data to/from HIX Connect -- **Informedica.GenPRES.Server**: The server library and agent-based orchestration and API layer -- **Informedica.GenPRES.Client**: The webbased clinical order client UI +- **Informedica.Agents.Lib**: Agent-based execution (MailboxProcessor) +- **Informedica.Logging.Lib**: Concurrent logging +- **Informedica.NLP.Lib**: Natural Language Processing for structured rule extraction +- **Informedica.OTS.Lib**: Google Sheets/CSV and Ontology Terminology Server integration +- **Informedica.GenUNITS.Lib**: Unit-safe calculations +- **Informedica.GenSOLVER.Lib**: Quantitative constraint solving +- **Informedica.GenCORE.Lib**: Core domain model +- **Informedica.ZIndex.Lib**: Medication and product database +- **Informedica.ZForm.Lib**: Z-Index dosing reference data +- **Informedica.NKF.Lib**: Kinderformularium dose rule extraction +- **Informedica.FTK.Lib**: Farmacotherapeutisch Kompas dose rule extraction +- **Informedica.GenFORM.Lib**: Operational Knowledge Rules (OKRs) +- **Informedica.GenORDER.Lib**: Clinical order scenarios and execution +- **Informedica.MCP.Lib**: Model Context Protocol for LLM integration +- **Informedica.FHIR.Lib**: FHIR resource conversion +- **Informedica.DataPlatform.Lib**: Data Platform integration +- **Informedica.HIXConnect.Lib**: HIX Connect integration +- **Informedica.MetaVision.Lib**: MetaVision integration +- **Informedica.GenPRES.Shared**: Shared types and API protocol +- **Informedica.GenPRES.Server**: Server API and orchestration +- **Informedica.GenPRES.Client**: Web-based clinical UI ## Code Contribution Guidelines diff --git a/docs/mdr/design-history/architecture.md b/docs/mdr/design-history/architecture.md index 67bd735..94fd221 100644 --- a/docs/mdr/design-history/architecture.md +++ b/docs/mdr/design-history/architecture.md @@ -19,25 +19,25 @@ GenPres is a **client-server web application**: ### 2.1. Technologies -- **F#** (.NET 9.0) +- **F#** (.NET 10.0) - **Giraffe** for web server - **Saturn** for application composition - **Fable.Remoting** for type-safe API communication with the client ### 2.2. Structure -- **Entry Point**: `src/Server/Server.fs` -- **API Implementation**: `src/Server/ServerApi.fs` - - Implements protocol in `Shared.Api.IServerApi` +- **Entry Point**: `src/Informedica.GenPRES.Server/Server.fs` +- **API Implementation**: `src/Informedica.GenPRES.Server/ServerApi.fs` + - Implements protocol in `Informedica.GenPRES.Shared.Api.IServerApi` - Processes commands from the client, performs calculations/validations, and returns results -- **Agents & Domain Logic**: e.g., `src/Server/Scripts/OrderAgent.fsx` - - Uses F# MailboxProcessor (actor model) for concurrent/isolated processing (e.g., medication order calculations) +- **Domain Logic**: e.g., `src/Informedica.GenORDER.Lib` + - Uses F# MailboxProcessor (actor model) for concurrent/isolated processing (e.g., medication order calculations). NOT IMPLEMETENTED YET. ### 2.3. Docker Hosting - **Dockerfile** builds the server, bundles the client, and sets up the environment. - Environment variables (e.g., `GENPRES_URL_ID`, `GENPRES_PROD`) configure which Google Spreadsheet is used for configuration. -- Entry point: runs `dotnet Server.dll` and exposes port 8085. +- Entry point: runs `dotnet Informedica.GenPRES.Server.dll` and exposes port 8085. **Example Docker Usage:** @@ -55,12 +55,12 @@ docker run -it -p 8080:8085 halcwb/genpres - **F# (Fable)**: Compiles to JavaScript - **Elmish**: Model-View-Update architecture - **React**: UI rendering -- **Vite**: Dev/bundle tooling (see `src/Client/vite.config.js`) +- **Vite**: Dev/bundle tooling (see `src/Informedica.GenPRES.Client/vite.config.js`) ### 3.2. Structure -- **Entry Point**: `src/Client/App.fs` and `src/Client/index.html` -- Communicates with the server using Fable.Remoting proxies (`Api.IServerApi`) +- **Entry Point**: `src/Informedica.GenPRES.Client/App.fs` and `src/Informedica.GenPRES.Client/index.html` +- Communicates with the server using Fable.Remoting proxies (`Informedica.GenPRES.Shared.Api.IServerApi`) - Handles application state, dispatches commands, and updates UI reactively --- @@ -80,98 +80,54 @@ docker run -it -p 8080:8085 halcwb/genpres - **Data Cache**: Proprietary cache files (not distributed publicly) containing medication product information. - Used for fast lookup/calculation and offline use. - Demo cache files are included for development. - - Path: `src/Server/data/cache/README.md` explains the folder usage. + - Path: `src/Informedica.GenPRES.Server/data/cache/README.md` explains the folder usage. - **Drug Data Types and Logic**: - - Main types are defined in `src/Informedica.KinderFormularium.Lib/Drug.fs` and `src/Informedica.GenOrder.Lib/Types.fs` + - Main types are defined in `src/Informedica.KinderFormularium.Lib/Drug.fs` and `src/Informedica.GenORDER.Lib/Types.fs` - Includes types for Drug, Dose, Route, Schedule, and DrugOrder. - Drug data can be loaded from local cache or generated from Google Sheets. --- -## 5.1. Order Modeling and Calculation: Informedica.GenOrder.Lib +## 5.1. Domain Architecture and Transformation Pipeline -The [`Informedica.GenOrder.Lib`](Informedica.GenOrder.Lib.md) library is central to the modeling and calculation of medical orders in GenPres2. It provides a domain model and mapping from a clinical `Order` to a set of mathematical `Equations` that can be solved by the `Informedica.GenSolver.Lib`, using `Informedica.Units.Lib` for unit conversions. +GenPres implements a comprehensive domain architecture described in detail in the `docs/domain` folder. For complete architectural specifications, see: -### Medication Cycle +- **[Core Domain Model](../../domain/core-domain.md)**: Defines the transformation pipeline from expert knowledge to executable orders +- **[GenFORM](../../domain/genform-free-text-to-operational-rules.md)**: Transforms free text to Operational Knowledge Rules (OKRs) +- **[GenORDER](../../domain/genorder-operational-rules-to-orders.md)**: Transforms OKRs to Order Scenarios and defines the Order Model (Orderable, Component, Item) +- **[GenSOLVER](../../domain/gensolver-from-orders-to-quantitative-solutions.md)**: Quantitative constraint solving engine -A medical order in GenPres2 supports the full medication cycle: +### Key Domain Concepts -1. **Lookup**: Identify available medication products, dosing, and preparation instructions. -2. **Calculation**: Compute doses and preparation steps, which can be complex and depend on patient-specific factors. -3. **Adjustment**: Support for cyclic updates as administered prescriptions may require additions or changes. - -![Medication Cycle](https://docs.google.com/drawings/d/e/2PACX-1vSf_4pUCnI38jM1ad9Bq8Ody8UK5Xrc09jec246ST8JwpSsEROGAXHuVbiInydvBtjseY88lRCSSC1P/pub?w=744&h=520) - -### Order Model - -The order model is hierarchical and supports a wide range of clinical scenarios: - -- **Order**: Identified by an `Id`, represents a specific prescription. -- **Prescription**: Details how the order is prescribed (one per order). -- **Orderable**: The entity being ordered (e.g., a medication or nutrition product). -- **Component**: An orderable can have multiple components. -- **Item**: Each component can contain multiple items, each with possible unit group variations. -- **Dose**: Each orderable, component, and item can have one or more doses, supporting adjustments (e.g., per kg, per BSA). - -![Order model](https://docs.google.com/drawings/d/e/2PACX-1vTgBB0m625rx2mrDYibTaQ2moIUVPkJNKTRm8yvvWu5JaOZE-HcyoDIFtfLjYQluqKkl23_p4qRJWQG/pub?w=1222&h=638) - -This model allows for flexible expression of doses (e.g., per kg bodyweight, per BSA) and supports multiple unit systems (mass, molar, etc.). - -### Calculation Variables and Equations - -The library defines a comprehensive set of variables representing all relevant quantities in an order (e.g., dose quantity, concentration, rate, total, adjustments). These are mapped to equations that describe the relationships between them, enabling automated calculation and validation. - -**Example variable types:** - -- `ItemDoseQuantity` -- `ComponentDoseTotal` -- `OrderableDoseRate` -- `PrescriptionFrequency` -- `OrderAdjust` - -**Example equation:** +The system implements a transformation pipeline: ```text -ItemDoseQuantity = ItemComponentConcentration × ComponentDoseQuantity +Free Text → [GenFORM] → OKRs → [GenORDER] → Order Scenarios → [GenSOLVER] → Quantitative Solutions ``` -A full list of variables and equations is maintained in [`Informedica.GenOrder.Lib.md`](Informedica.GenOrder.Lib.md). +**Operational Knowledge Rules (OKRs)** define: +- Selection Constraints (Generic, Indication, Route, Patient Category, Dose Type, etc.) +- Calculation Constraints (Dose Limits, Schedule, Duration, Volumes, Concentrations) -### Integration +**Order Model** (hierarchical structure): +- Order → Prescription → Orderable → Component → Item → Dose -- The server domain logic uses this model to process medication orders, perform calculations, and validate prescriptions. -- The model supports not only medication but also feeding, parenteral nutrition, and maintenance fluids. -- All calculations are unit-safe and leverage the `Informedica.Units.Lib` for conversions. +For details on: +- Rule types (Dose Rule, Dilution Rule, Reconstitution Rule, Renal Rule), see [GenFORM Section 3](../../domain/genform-free-text-to-operational-rules.md#3-sources-and-types-of-dose-rules) +- Order model structure, see [GenORDER Section 6](../../domain/genorder-operational-rules-to-orders.md#6.-order-model-(executable-structure)) +- Dose semantics (Quantity, Per Time, Rate, Total, Adjusted), see [GenORDER Section 7](../../domain/genorder-operational-rules-to-orders.md#7.-quantitative-dose-semantics) +- Equation system (65 equations), see [GenORDER Appendix D.1](../../domain/genorder-operational-rules-to-orders.md#appendix-d.1.-equations-table) +- Constraint solving algorithm, see [GenSOLVER Section 3](../../domain/gensolver-from-orders-to-quantitative-solutions.md#3.-formal-constraint-solving-model) ---- +### Core Capabilities -## 5.2. Tackling Core Calculation and Usability Challenges - -The GenPres project has addressed several key challenges to enable robust, flexible, and safe medication prescribing: - -1. **Order-Independent Calculations:** - The system is designed so that calculations can be performed regardless of the order in which quantitative data is entered. For example, if a total dose, frequency, or individual dose is provided, the system can solve for the remaining variables. This is achieved by modeling the relationships as a set of equations, allowing any variable to be solved from any combination of knowns. - -2. **Automatic Unit Handling:** - All calculations are performed in base units, with automatic conversion between units. Users do not need to specify units explicitly; the system infers and converts as needed, ensuring consistency and reducing the risk of unit-related errors. - -3. **Absolute Precision:** - Calculations use absolute precision quantities (e.g., BigRationals) to avoid rounding errors. This ensures that all computed values are as precise as possible, which is critical for medication safety. - -4. **Range and Restriction Modeling:** - The system supports calculations involving ranges and restrictions. For example, a dose can be specified as a range (e.g., 60–80 mg), frequency as a set (e.g., 2, 3, or 4 times per day), and increments or specific allowed values can be enforced. This enables the system to present all valid scenarios to the prescriber. - -5. **Performance Considerations:** - While supporting flexible calculations and ranges, the system is being optimized for performance, especially for scenarios with large sets of possible values. Mathematical modeling and collaboration with academic partners are ongoing to further improve efficiency. - -6. **Comprehensive Data Integration:** - The system integrates two major sources of information: product data (which products are available) and dosing/preparation rules. This allows GenPres to calculate all possible valid scenarios for a given clinical context. - -7. **Web-Based, Device-Agnostic Interface:** - To ensure usability across clinical environments, GenPres is implemented as a web application, supporting use on desktops, tablets, and mobile devices. - -These solutions collectively enable GenPres to provide a "one-click" prescription experience, where the system computes all valid options and the clinician simply selects the most appropriate one. +1. **Order-Independent Calculations**: The constraint-based equation system allows calculations regardless of data entry order +2. **Automatic Unit Handling**: All calculations use base units with automatic conversion +3. **Absolute Precision**: Uses BigRationals to avoid rounding errors +4. **Range and Restriction Modeling**: Supports dose ranges, frequency sets, and value constraints +5. **Safety by Construction**: Invalid options are mathematically impossible to construct +6. **Completeness Guarantee**: All valid options are preserved by the constraint solver --- @@ -202,11 +158,18 @@ These solutions collectively enable GenPres to provide a "one-click" prescriptio ## 8. References +### Technical Stack - [SAFE Stack Documentation](https://safe-stack.github.io/docs/) - [Saturn](https://saturnframework.org/) - [Fable](https://fable.io/docs/) - [Elmish](https://elmish.github.io/elmish/) -- More background: [GenPres2 README](https://github.com/halcwb/GenPres2/blob/master/README.md) +- [.NET 10.0](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10/overview) + +### Domain Architecture +- [Core Domain Model](../../domain/core-domain.md) +- [GenFORM: Free Text to Operational Rules](../../domain/genform-free-text-to-operational-rules.md) +- [GenORDER: Operational Rules to Orders](../../domain/genorder-operational-rules-to-orders.md) +- [GenSOLVER: Order Scenarios to Quantitative Solutions](../../domain/gensolver-from-orders-to-quantitative-solutions.md) --- @@ -218,14 +181,21 @@ These solutions collectively enable GenPres to provide a "one-click" prescriptio --- -## 10. File References +## 10. Key Files and Libraries -- **See also**: - - [README.md](https://github.com/halcwb/GenPres2/blob/master/README.md) - - [Dockerfile](https://github.com/halcwb/GenPres2/blob/master/Dockerfile) - - [src/Server/ServerApi.fs](https://github.com/halcwb/GenPres2/blob/master/src/Server/ServerApi.fs) - - [src/Informedica.KinderFormularium.Lib/Drug.fs](https://github.com/halcwb/GenPres2/blob/master/src/Informedica.KinderFormularium.Lib/Drug.fs) +### Core Server Files +- `src/Informedica.GenPRES.Server/Server.fs`: Application entry point +- `src/Informedica.GenPRES.Server/ServerApi.fs`: API implementation +- `src/Informedica.GenPRES.Client/App.fs`: Client application entry +- `Dockerfile`: Container configuration for deployment ---- +### Domain Libraries +- **Informedica.GenFORM.Lib**: Operational Knowledge Rules implementation +- **Informedica.GenORDER.Lib**: Order scenario generation and management +- **Informedica.GenSOLVER.Lib**: Constraint solving engine +- **Informedica.GenUNITS.Lib**: Unit-aware computation +- **Informedica.ZForm.Lib**: Rule extraction from G-Standaard +- **Informedica.NKF.Lib**: Kinderformularium dosing rules +- **Informedica.FTK.Lib**: Farmacotherapeutisch Kompas rules -> **This is a summary based on code and documentation found in the repository. For more in-depth details, see the full [codebase on GitHub](https://github.com/halcwb/GenPres2) and linked files above. Results are based on a search limited to the top 10 results per query.** +For complete library specifications, see [GenFORM Appendix B.3](../../domain/genform-free-text-to-operational-rules.md#addendum-b3-genform-libraries). diff --git a/docs/mdr/design-history/genpres-state-management-proposal.md b/docs/mdr/design-history/genpres-state-management-proposal.md deleted file mode 100644 index 6a0ca8a..0000000 --- a/docs/mdr/design-history/genpres-state-management-proposal.md +++ /dev/null @@ -1,497 +0,0 @@ -# GenPRES State Management Design - -## Executive Summary - -GenPRES will be developed as a stateless persistence service for EHR integration. The service maintains zero permanent patient data, operates through temporary sessions where patient context is provided by the EHR, and returns all modifications upon session completion. Clinical calculation capabilities are preserved while eliminating persistent data storage. - -## Core Design Principle: Stateless Persistence - -### Definition -Stateless Persistence implementation: -- No permanent patient storage: Patient data, orders, or clinical decisions persist only during active sessions -- Temporary working sessions: Clinical context maintained during prescription workflows -- Complete state transfer: All session modifications returned to EHR system -- Resource-only caching: Institutional rules, formularies, and product data cached for performance - -### Service Boundary -``` -Session Lifecycle: -EHR → [Start Session + Patient Data + Orders] → GenPRES Session - ↓ -Active Session: GenPRES ←→ Clinician Interface (CRUD Operations) - ↓ -EHR ← [Modified Orders + Clinical Decisions] ← Session End → [State Discarded] -``` - -GenPRES operates as a computational clinical service with temporary working memory. - -## Architectural Design - -### 1. EHR-Controlled Session Management - -#### Session Initiation -```fsharp -type EhrSessionRequest = { - SessionId: Guid - EhrSystemId: string // Identifying which EHR system - EhrUserId: string // EHR user reference (not stored) - EhrPatientId: string // EHR patient reference (not stored) - PatientSnapshot: PatientData // Complete patient context for calculations - ExistingOrders: EhrOrder[] // Current patient orders from EHR - AuthorizationContext: { // EHR-provided user permissions and restrictions - UserRole: ClinicalRole - Permissions: Permission[] - Restrictions: Restriction[] - DepartmentAccess: string[] - PatientAccessLevel: AccessLevel - } - ClinicalContext: { - Department: string - Institution: string - ClinicalFlags: ClinicalFlag[] - Urgency: UrgencyLevel - } - ResourceVersions: { // Which cached resources to use - FormularyVersion: string - ProductDataVersion: string - InstitutionalRulesVersion: string - } - SessionConfiguration: { - TimeoutMinutes: int - AutoSyncEnabled: bool - MaxOrdersPerSession: int - } -} - -type GenPresSession = { - SessionId: Guid - EhrReference: EhrSystemId * EhrUserId * EhrPatientId // References only - AuthorizationContext: AuthorizationContext // User permissions from EHR - PatientContext: PatientData // Temporary clinical context - WorkingOrders: Map // Active order workspace - EhrOrderMapping: Map // Order reference mapping - ClinicalDecisions: ClinicalDecision[] // Treatment decisions made during session - CreatedAt: DateTime - LastActivity: DateTime - ExpiresAt: DateTime - AutoSync: bool -} -``` - -#### Session Operations -```fsharp -type SessionOperation = - | CreateOrder of OrderRequest - | ModifyOrder of OrderId * OrderModification - | DeleteOrder of OrderId - | SelectScenario of OrderId * ScenarioId - | ValidateOrderSet - | CalculateTreatmentPlan - | SyncToEhr // Manual sync during session - | FinalizeSession // Complete and transfer all changes - -type SessionResponse = { - SessionId: Guid - UpdatedOrders: Map - CalculatedScenarios: Map - ValidationResults: ValidationResult[] - ClinicalAlerts: ClinicalAlert[] - TreatmentPlanUpdate: TreatmentPlan option - SyncStatus: SyncStatus -} -``` - -### 2. Modified Client Architecture - -#### Stateless Client State -```fsharp -type ClientState = { - // NO PERSISTENT PATIENT DATA - ActiveSession: EhrSession option // Temporary session context - WorkingOrders: Map // Session-scoped orders - - // UI State Only - Page: Global.Pages - UISettings: UIConfiguration - - // Cached Resources (Non-Patient Data) - CachedFormulary: Deferred - CachedProducts: Deferred - CachedRules: Deferred - - // Real-time Session Data - CalculationResults: Map - ValidationStatus: ValidationResults - TreatmentPlan: TreatmentPlan option // Session-scoped only -} - -type ClientMessage = - | EhrSessionStarted of EhrSessionRequest - | EhrSessionClosed of SessionId - | OrderOperation of SessionId * OrderOperation - | SessionSyncRequested of SessionId - | SessionFinalized of SessionId - // Remove all patient-specific persistence messages -``` - -#### Session-Aware UI Components -```fsharp -let SessionAwarePatientView props = - match props.activeSession with - | None -> - // Display "Waiting for EHR session" state - WaitingForEhrView() - | Some session -> - // Display patient context from session - PatientView({ - patient = session.PatientContext - readonly = true // Patient data managed by EHR - orders = session.WorkingOrders - onOrderOperation = props.onOrderOperation - }) -``` - -### 3. Server Session Management - -#### Session Store -```fsharp -type SessionStore = { - ActiveSessions: Map - SessionsByEhr: Map - ExpirationQueue: PriorityQueue -} - -let sessionManager = { - CreateSession: EhrSessionRequest -> Async> - GetSession: SessionId -> Async - UpdateSession: SessionId -> SessionOperation -> Async> - SyncSession: SessionId -> Async> - FinalizeSession: SessionId -> Async> - CloseSession: SessionId -> Async> - CleanupExpiredSessions: unit -> Async // Returns number cleaned -} -``` - -#### Session Processing Pipeline -```fsharp -let processSessionOperation sessionId operation = async { - let! sessionOpt = SessionStore.getSession sessionId - match sessionOpt with - | None -> return Error [| "Session not found or expired" |] - | Some session -> - // Validate operation against user authorization context - let! authResult = validateOperation operation session.AuthorizationContext - match authResult with - | Error authErrors -> return Error authErrors - | Ok _ -> - // Apply operation to session state - let! updatedSession = applyOperation session operation - - // Recalculate affected orders using GenOrder.Lib - let! recalculatedOrders = recalculateOrders updatedSession.WorkingOrders - - // Validate complete order set - let! validationResults = validateOrderSet recalculatedOrders session.PatientContext - - // Update session with results - let! finalSession = updateSessionWithResults updatedSession recalculatedOrders validationResults - - // Auto-sync to EHR if enabled - let! syncResult = - if session.AutoSync then syncToEhr finalSession - else async { return Ok() } - - return Ok { - SessionId = sessionId - UpdatedOrders = finalSession.WorkingOrders - CalculatedScenarios = calculateAllScenarios finalSession - ValidationResults = validationResults - ClinicalAlerts = generateClinicalAlerts finalSession - TreatmentPlanUpdate = calculateTreatmentPlan finalSession - SyncStatus = syncResult - } -} -``` - -## EHR Integration Contract - -### 1. Session Lifecycle API -```fsharp -type IEhrIntegrationApi = { - // Session Management - InitializeSession: EhrSessionRequest -> Async> - CloseSession: SessionId -> Async> - - // Resource Management - UpdateInstitutionalResources: InstitutionId -> ResourceUpdate -> Async> - GetResourceVersions: InstitutionId -> Async> - - // Session Operations - ProcessOrderOperations: SessionId -> OrderOperation[] -> Async> - SyncSessionToEhr: SessionId -> Async> - GetSessionStatus: SessionId -> Async> -} -``` - -### 2. Clinician Interface API -```fsharp -type IClinicianApi = { - // Order CRUD (requires active session) - CreateOrder: SessionId -> OrderRequest -> Async> - UpdateOrder: SessionId -> OrderId -> OrderUpdate -> Async> - DeleteOrder: SessionId -> OrderId -> Async> - SelectOrderScenario: SessionId -> OrderId -> ScenarioId -> Async> - - // Session Queries - GetOrderScenarios: SessionId -> OrderId -> Async> - GetTreatmentPlan: SessionId -> Async> - ValidateAllOrders: SessionId -> Async> - - // Session Control - RequestEhrSync: SessionId -> Async> -} -``` - -## Data Flow Architecture - -### 1. Session Initialization Flow -``` -1. EHR → GenPRES: InitializeSession(patient_data, existing_orders, resources) -2. GenPRES: Create temporary session, load resources, validate existing orders -3. GenPRES → EHR: SessionInitResponse(session_id, calculated_scenarios) -4. EHR → Clinician: Open GenPRES interface with session_id -``` - -### 2. Active Session Flow -``` -1. Clinician → GenPRES: Order CRUD operations via session_id -2. GenPRES: Update session state, recalculate, validate -3. GenPRES → Clinician: Updated scenarios and validation results -4. Optional: GenPRES → EHR: Auto-sync if enabled -``` - -### 3. Session Finalization Flow -``` -1. Clinician/EHR → GenPRES: FinalizeSession(session_id) -2. GenPRES: Prepare complete order changeset -3. GenPRES → EHR: FinalizedOrders(created, modified, deleted orders) -4. EHR: Persist changes to patient record -5. GenPRES: Discard all session data (stateless achieved) -``` - -## Implementation Strategy - -### Phase 1: Session Abstraction Layer -Wrap existing architecture without breaking changes: -```fsharp -// Wrap current patient state in session container -type SessionContainer = { - Session: EhrSession - CurrentState: App.Elmish.State // Existing state wrapped - EhrSyncHandler: EhrSyncHandler -} - -// Add session awareness to existing components -let SessionAwareApp sessionContainer = - // Existing App.View with session context - App.View {| - // Map existing props but mark patient as readonly - patient = Some sessionContainer.Session.PatientContext - // ... other existing props - |} -``` - -### Phase 2: EHR Integration Endpoints -Add EHR APIs alongside existing functionality: -```fsharp -// Extend existing ServerApi -type IExtendedServerApi = { - // Existing API preserved - processCommand: Command -> Async> - testApi: unit -> Async - - // New EHR integration API - initializeEhrSession: EhrSessionRequest -> Async> - processSessionOperation: SessionId -> SessionOperation -> Async> - finalizeEhrSession: SessionId -> Async> -} -``` - -### Phase 3: Complete Stateless Mode -Remove persistent patient storage, maintain only session-based operation: -```fsharp -// Remove from client state -type CleanClientState = { - // REMOVED: Patient: Patient option - // REMOVED: Persistent OrderContext - - ActiveSession: EhrSession option // Temporary only - WorkingOrders: Map // Session-scoped - CachedResources: ResourceCache // Institution data only -} -``` - -## Technical Analysis - -### System Properties - -**Responsibility Boundaries** -- **EHR**: Patient data, authentication, authorization, long-term storage, regulatory compliance - - **Authentication**: Verifies user identity and maintains secure sessions - - **Authorization**: Determines user permissions, role-based access controls, and patient access rights - - **Session Context**: Provides complete authorization context to GenPRES so the service knows what the user can and cannot do -- **GenPRES**: Clinical calculations, validation, order optimization - - **Authorization Enforcement**: Respects EHR-provided permissions when presenting options and validating operations - - **No Identity Management**: Relies entirely on EHR for user identity and access decisions -- **Separation**: No overlap in data ownership or access control - -**Deployment Properties** -- Horizontal scaling: Any GenPRES instance can handle any session -- No database management: No patient database backup, recovery, or maintenance -- Multi-tenant support: Single instance serves multiple EHR systems -- Reduced compliance burden: No PHI storage - -**Integration Properties** -- EHR workflow integration: Each EHR integrates according to workflow requirements -- Version independence: EHR and GenPRES update independently -- Loose coupling: Patient data model changes don't require GenPRES updates - -### Implementation Requirements - -**Session Management** -- Session cleanup: Sessions must be reliably discarded to maintain stateless guarantee -- Memory management: Session data must be garbage collected properly -- Concurrent access: Multiple clinicians may work on same patient orders - -**Performance Optimization** -- Session-scoped caching: Calculation results cached within session, discarded after -- Resource preloading: Institutional data must be efficiently cached for session startup -- Network efficiency: Balance comprehensive data transfer against multiple round trips - -**Reliability Patterns** -- Session recovery: Handle service restarts during active sessions -- Timeout handling: Session expiration with EHR notification -- Error resilience: Failed operations must not corrupt session state - -## Refactoring Strategy from Current Implementation - -### 1. Wrap Existing State Management -```fsharp -// Current App.fs state becomes session-scoped -type SessionState = App.Elmish.State // Existing state structure - -type ServiceState = { - ActiveSessions: Map - CachedResources: ResourceCache - ServiceConfiguration: ServiceConfig -} -``` - -### 2. Add Session Lifecycle to Existing APIs -```fsharp -// Extend current ServerApi.fs -let processEhrCommand sessionId command = async { - let! session = getActiveSession sessionId - match session with - | Some sessionState -> - // Use existing Command.processCmd with session context - let! result = Command.processCmd provider command - let! updatedSession = updateSession sessionId result - return Ok result - | None -> return Error [| "Session not found" |] -} -``` - -### 3. Session-Aware Resource Management -```fsharp -// Keep existing resource caching but make it session-aware -type SessionResourceManager = { - LoadForSession: SessionId -> InstitutionId -> Async - GetCachedResources: InstitutionId -> ResourceVersions -> Async - UpdateInstitutionalCache: InstitutionId -> ResourceUpdate -> Async -} -``` - -## Deployment and Operations - -### 1. Container Configuration -```dockerfile -# Stateless service deployment -FROM mcr.microsoft.com/dotnet/aspnet:9.0 -COPY --from=build /app/publish . - -# Only resource cache storage needed -VOLUME ["/app/cache/resources"] - -# No patient data volumes -# No database connections needed -# No backup/recovery for patient data - -EXPOSE 8085 -ENTRYPOINT ["dotnet", "GenPresService.dll"] -``` - -### 2. Environment Configuration -```bash -# Service configuration - no persistent patient storage -GENPRES_SERVICE_MODE=stateless_persistence -GENPRES_SESSION_TIMEOUT_MINUTES=30 -GENPRES_MAX_CONCURRENT_SESSIONS=100 -GENPRES_RESOURCE_CACHE_SIZE=2GB - -# No patient database configuration needed -# No session storage configuration needed -# No backup configuration needed -``` - -### 3. Monitoring and Observability -```fsharp -type SessionMetrics = { - ActiveSessionCount: int - AverageSessionDuration: TimeSpan - OrdersPerSession: float - CalculationPerformance: PerformanceMetrics - EhrSyncSuccess: float - SessionCleanupRate: int -} -``` - -## EHR Integration Properties - -### 1. Data Sovereignty -- EHR maintains full ownership of patient data -- GenPRES operations don't affect EHR compliance posture -- All prescription activities flow through EHR audit systems -- EHR handles all data backup and recovery - -### 2. Workflow Integration -- GenPRES interface embedded in EHR workflow -- Session maintains clinical context during prescription process -- All clinical decisions transferred back to EHR for permanent storage -- EHR manages concurrent access to patient orders - -### 3. Operational Properties -- GenPRES and EHR can update on different schedules -- Multiple EHR systems can share GenPRES instance -- GenPRES can be scaled independently based on calculation load - -## Implementation Summary - -### Stateless Architecture -- No patient data persistence: All patient information discarded after session closure -- No authentication storage: EHR handles all identity and access management -- Complete state transfer: All order modifications returned to EHR -- Session isolation: Each session independent with no cross-contamination - -### Clinical Functionality -- Mathematical modeling during active sessions -- Prescription workflows with session context -- Cross-order validation within session scope -- Real-time optimization and feedback - -### Integration Architecture -- EHR maintains complete control over data and workflows -- Shared computational resources without data coupling -- Clear boundaries for compliance responsibilities - -GenPRES functions as a computational clinical service providing prescription support without data persistence requirements. The architecture enables multi-EHR deployment while maintaining clinical calculation capabilities. \ No newline at end of file diff --git a/docs/mdr/design-history/informedica-genform-lib.md b/docs/mdr/design-history/informedica-genform-lib.md deleted file mode 100644 index a34a347..0000000 --- a/docs/mdr/design-history/informedica-genform-lib.md +++ /dev/null @@ -1,789 +0,0 @@ -# Informedica.Genform Library Design History - -- [Informedica.Genform Library Design History](#informedicagenform-library-design-history) - - [Overview](#overview) - - [Product and Substance Data Structure](#product-and-substance-data-structure) - - [Product and Substance Model](#product-and-substance-model) - - [Z-Index Product Structure](#z-index-product-structure) - - [1. GenPRES Product Level Unique Identifiers](#1-genpres-product-level-unique-identifiers) - - [2. Generic Product Level Unique Identifiers](#2-generic-product-level-unique-identifiers) - - [3. Prescription Product Level Unique Identifiers](#3-prescription-product-level-unique-identifiers) - - [4. Trade Product Level Unique Identifiers](#4-trade-product-level-unique-identifiers) - - [5. Consumer Product Level Unique Identifiers](#5-consumer-product-level-unique-identifiers) - - [Reconstitution and Solution Rules Data Structure](#reconstitution-and-solution-rules-data-structure) - - [Solution and Reconstitution Model](#solution-and-reconstitution-model) - - [Reconstition Rules Table](#reconstition-rules-table) - - [Solution Rules Table](#solution-rules-table) - - [Dose Rules Data Structure](#dose-rules-data-structure) - - [Dose Rules Model](#dose-rules-model) - - [Table](#table) - - [Comparison with G-Standaard (ZForm) Implementation](#comparison-with-g-standaard-zform-implementation) - - [Overview GenForm vs ZForm](#overview-genform-vs-zform) - - [Architectural Differences](#architectural-differences) - - [GenForm Structure (Flat, Filter-Based)](#genform-structure-flat-filter-based) - - [ZForm Structure (Hierarchical, Collection-Based)](#zform-structure-hierarchical-collection-based) - - [ZIndex Source Structure (G-Standaard Data)](#zindex-source-structure-g-standaard-data) - - [Dose Representation Comparison](#dose-representation-comparison) - - [GenForm DoseLimit (Multi-Dimensional)](#genform-doselimit-multi-dimensional) - - [ZForm DoseRange (Six Explicit Fields)](#zform-doserange-six-explicit-fields) - - [ZForm Dosage (Multiple Dosage Types)](#zform-dosage-multiple-dosage-types) - - [ZIndex DoseRule (Source Data)](#zindex-doserule-source-data) - - [Mapping: GenForm ↔ ZForm ↔ ZIndex](#mapping-genform--zform--zindex) - - [ZIndex → ZForm Transformation (Implemented in GStand.fs)](#zindex--zform-transformation-implemented-in-gstandfs) - - [ZForm → GenForm Mapping (Conceptual - Not Implemented)](#zform--genform-mapping-conceptual---not-implemented) - - [GenForm → ZForm Mapping (Conceptual - Not Implemented)](#genform--zform-mapping-conceptual---not-implemented) - - [Patient Category Differences](#patient-category-differences) - - [Schedule and Timing Differences](#schedule-and-timing-differences) - - [Product and Classification Differences](#product-and-classification-differences) - - [DoseType Semantics Comparison](#dosetype-semantics-comparison) - - [GenForm DoseType (Categorical)](#genform-dosetype-categorical) - - [ZForm Dosage Types (Multi-Faceted)](#zform-dosage-types-multi-faceted) - - [Component vs Substance Organization](#component-vs-substance-organization) - - [GenForm (Component-Centric)](#genform-component-centric) - - [ZForm (Substance-Centric)](#zform-substance-centric) - - [Source and Provenance Tracking](#source-and-provenance-tracking) - - [Clinical Features Comparison](#clinical-features-comparison) - - [GenForm-Specific Features (Not in ZForm/ZIndex)](#genform-specific-features-not-in-zformzindex) - - [ZForm-Specific Features (Not in GenForm)](#zform-specific-features-not-in-genform) - - [ZIndex-Specific Features (Not in GenForm/ZForm)](#zindex-specific-features-not-in-genformzform) - - [Summary of Key Discrepancies](#summary-of-key-discrepancies) - - [1. Architectural Philosophy](#1-architectural-philosophy) - - [2. Dose Representation](#2-dose-representation) - - [3. Clinical Focus](#3-clinical-focus) - - [4. Organization Principle](#4-organization-principle) - - [5. Interoperability](#5-interoperability) - - [Use Case Alignment](#use-case-alignment) - - [GenForm Best For:](#genform-best-for) - - [ZForm Best For:](#zform-best-for) - - [ZIndex Best For:](#zindex-best-for) - - [Recommendations for Integration](#recommendations-for-integration) - -The Informedica.Genform library contains data structures to represent reconstitution steps and solution rules for medications. These data structures are designed to facilitate the management and application of reconstitution and solution guidelines in a clinical setting. - -## Overview - -- Objects that are bold are required. -- Atributes that are italic are conditionally required based on other attribute values. -- Atttributes that are bold underlined are required. - -If an Object is bold and all attributes are italic, the Object is required but the attributes are conditionally required based on other attribute values. If an Object is not bold, the Object is optional. - -Objects have the following relationships: - -- *1..N* : One to many relationship -- *1..n* : One to zero or many relationship -- *1..1* : One to one relationship - -When an object isn't required, the relationship is *1..n*, which means the relationship passes to the next object. - -## Product and Substance Data Structure - -### Product and Substance Model - -![Product and Substance model](https://docs.google.com/drawings/d/e/2PACX-1vS3xWXvNVpM6MHRH5aAJ0S-bliMviuW1fK0chOd1PA_i8TPDpBRB4MthbspBucUURaxu5vAUrQ3R5TU/pub?w=1614&h=1488) - -Products and substances are represented in the Informedica.Genform library using a structured data model. This model captures essential information about pharmaceutical products, including their generic names, brands, shapes, and associated substances. Then information is mapped from the Z-index and ParentMeds data sources. A Z-index is a comprehensive database of pharmaceutical products, while ParentMeds contains information about parent medications and their properties. - -GenForm.Lib has a simplified structure: - -❌ Missing: No GenPresProduct equivalent -❌ Missing: No PrescriptionProduct equivalent -❌ Missing: No TradeProduct equivalent -❌ Missing: No ConsumerProduct equivalent -✅ Has only a single Product type that conflates multiple levels - -| Documentation | GenForm.Lib Field | ZIndex.Lib Field | Status | -|---|---|---|---| -| GPK (Generic Product ID) | ✅ GPK: string | ✅ Id: int | Mismatch: Different types (string vs int) | -| Generic Name | ✅ Generic: string | ✅ Name: string | Naming inconsistency | -| Shape | ✅ Shape: string | ✅ Shape: string | ✅ Match | -| Brand | ❌ Missing | ✅ Brand: string (in TradeProduct) | Missing in GenForm | -| Company | ❌ Missing | ✅ Company: string (in TradeProduct) | Missing in GenForm | -| Container | ❌ Missing | ✅ Container: string (multiple levels) | Missing in GenForm | - -### Z-Index Product Structure - -The Z-Index product structure defines products at 4 levels: - -1. Generic Product -2. Prescription Product -3. Trade Product -4. Consumer Product - -An additional level can be defined above the Generic Product level, called a GenPRES Product. A GenPRES product can consist of multiple Generic Products. - -Each level has attributes that, together, makes them unique and identifiable. - -#### 1. GenPRES Product Level Unique Identifiers - -| Level | Unique Identifier | Description | -|-------|-------------------|-------------| -| GenPRES Product | Name | The combined name of Substance names from the Generic Products | -| GenPRES Product | Shape | The common shape of alle Generic Products | - -#### 2. Generic Product Level Unique Identifiers - -| Level | Unique Identifier | Description | -|-------|-------------------|-------------| -| Generic Product | Shape | The Shape of the Generic Product | -| Generic Product | Substances | The active substances | - -*Note*: A Generic Product contains one or more active substances. Along with the Name of the Substance the Quanity (= Concentration) and Unit also uniquely identify a Generic Product. - -#### 3. Prescription Product Level Unique Identifiers - -| Level | Unique Identifier | Description | -|-------|-------------------|-------------| -| Prescription Product | Quantity | The Quantity of the Prescription Product | - -A product quantity is added to the Generic Product to create a unique Prescription Product. - -#### 4. Trade Product Level Unique Identifiers - -| Level | Unique Identifier | Description | -|-------|-------------------|-------------| -| Trade Product | Brand | The Brand name of the Trade Product | -| Trade Product | Company | The Company of the Trade Product | - -A Brand and Company is added to the Prescription Product to create a unique Trade Product. Furthermore, a Trade Product can have a specific set of additional substances, that are brand specific. - -#### 5. Consumer Product Level Unique Identifiers - -| Level | Unique Identifier | Description | -|-------|-------------------|-------------| -| Consumer Product | Quantity | The quantity per Container | -| Consumer Product | Container | The Container type | - -A Container and Quantity is added to the Trade Product to create a unique Consumer Product. So, a Consumer Product can contain multiple Trade Products if the Container contains multiple units of the Trade Product. - -## Reconstitution and Solution Rules Data Structure - -### Solution and Reconstitution Model - -![Solution and Reconstitution model](https://docs.google.com/drawings/d/e/2PACX-1vTCmWhej7l1HTUelmCR8PGOjG-VbFCXpG4tBHLRSWIayhyk-okLkkqUENUOCKugOHZP6YafcFdE_Ti3/pub?w=1440&h=1080) - -### Reconstition Rules Table - -| Sheet | Object | Variable | Type | Unit | Description | Comments | -|-------|--------|----------|------|------|-------------|----------| -| Reconstitution | **Generic** | **GPK** | text | | The unique Generic Product Identifier | Corresponds with GPK in the Z-index | -| Reconstitution | **Generic** | **Medication** | text | | The generic drug name | The naming from the Z-index is used in all small caps. For multiple substance drugs, concatenated with '/' | -| Reconstitution | **Generic** | **Shape** | text | | The shape name of the generic drug | The naming from the Z-index is used. | -| Reconstitution | **Route** | *Route* | text | | The route | Can be any route name using the mapping in the Routes sheet | -| Reconstitution | Location | *Dep* | text | | The department | The department the reconstitution step applies to | -| Reconstitution | **Reconstitution** | **DiluentVol** | float | mL | The volume of the diluent | The amount of diluent solution the pharmacological shape is disolved in | -| Reconstitution | **Reconstitution** | *ExpansionVol* | float | mL | The expansion volume | The quantity of the volume after reconstitution, could be more than the dilution volume | -| Reconstitution | **Reconstitution** | **Diluents** | text list | | The possible diluents that can be used | Can be a name (or names separated with ';') from the ParentMeds sheet | - -### Solution Rules Table - -| Sheet | Object | Variable | Type | Unit | Description | Comments | -|-------|--------|----------|------|------|-------------|----------| -| SolutionRules | **Generic** | **Generic** | text | | The generic name | The naming from the Z-index is used in all small caps. For multiple substance drugs, concatenated with '/' | -| SolutionRules | **Generic** | **Shape** | text | | The shape name of the generic drug | The naming from the Z-index is used. | -| SolutionRules | **Generic** | *Indication* | text | | | | -| SolutionRules | **Route** | **Route** | text | | The route | Can be any route name using the mapping in the Routes sheet | -| SolutionRules | DoseType | *DoseType* | once / onceTimed / discontinuous / timed / continuous | | The dosetype | The dosetypes as mentioned in the DoseRules sheet | -| SolutionRules | Vascular Access | *CVL* | boolean | | Central Venous Line | Checked if the reconstitution only applies to a CVL | -| SolutionRules | Vascular Access | *PVL* | boolean | | Peripheral Venous Line | Checked if the reconstitution only applies to a PVL | -| SolutionRules | **Patient Category** | **Dep** | text | | The department | The department the reconstitution step applies to | -| SolutionRules | **Patient Category** | *MinAge* | int | days | The minimum age | The minimum age the solution rule applies to | -| SolutionRules | **Patient Category** | *MaxAge* | int | days | The maximum age | The maximum age the solution rule applies to | -| SolutionRules | **Patient Category** | *MinWeight* | int | gram | The minimum weight | The minimum weight the solution rule applies to | -| SolutionRules | **Patient Category** | *MaxWeight* | int | gram | The maximum weight | The maximum weight the solution rule applies to | -| SolutionRules | **SolutionRule** | *MinDose* | float | unit | The minimum dose | The minimum dose the solution rule applies to (uses the unit from 'Unit') | -| SolutionRules | **SolutionRule** | *MaxDose* | float | unit | The maximum dose | The maximum dose the solution rule applies to (uses the unit from 'Unit') | -| SolutionRules | **SolutionRule** | **Solutions** | text list | | The possible solutions that can be used | Can be a name (or names separated with ';') from the ParentMeds sheet | -| SolutionRules | **SolutionRule** | *Volumes* | float list | mL | The possible volume quantities that can be used | Specific volumes can be specified | -| SolutionRules | **SolutionRule** | *MinVol* | float | mL | The minimum volume (in mL) | The minimum volume that can be used for the solution | -| SolutionRules | **SolutionRule** | *MaxVol* | float | mL | The maximum volume (in mL) | The maximum volume that can be used for the solution | -| SolutionRules | **SolutionRule** | *MinVolAdj* | float | mL / kg | | | -| SolutionRules | **SolutionRule** | *MaxVolAdj* | float | mL / kg | | | -| SolutionRules | **SolutionRule** | *MinDrip* | float | mL / hour | | | -| SolutionRules | **SolutionRule** | *MaxDrip* | float | mL / hour | | | -| SolutionRules | **SolutionRule** | *MinPerc* | float | perc | The minimum percentage of the solution to use for the DoseQuantity | In order to calculate an administration dose, it is possible to use only a percentage of the prepared solution | -| SolutionRules | **SolutionRule** | *MaxPerc* | float | perc | The maximum percentage of the solution to use for the DoseQuantity | In order to calculate an administration dose, it is possible to use only a percentage of the prepared solution | -| SolutionRules | **SolutionLimit** | **Substance** | text | | The substance used for the below fields | The substance is the generic of part of the generic name | -| SolutionRules | **SolutionLimit** | **Unit** | text | | The unit to measures the substance in | Units can be used from the Units sheet | -| SolutionRules | **SolutionLimit** | *Quantities* | float list | unit | The substance quantities that can be used | Absolute quantities that can be used for the solution and/or | -| SolutionRules | **SolutionLimit** | *MinQty* | float | unit | The minimum substance quantity (in Unit) | The minimum substance quantity that can be in the solution | -| SolutionRules | **SolutionLimit** | *MaxQty* | float | unit | The maximum substance quantity (in Unit) | The maximum substance quantity that can be in the solution | -| SolutionRules | **SolutionLimit** | *MinConc* | float | unit / mL | The minimum substance concentration (in Unit/mL) | The minimum substance concentration of the solution | -| SolutionRules | **SolutionLimit** | *MaxConc* | float | unit / mL | The maximum substance concentration (in Unit/mL) | The maximum substance concentration of the solution | - -## Dose Rules Data Structure - -The Informedica.Genform library contains a comprehensive data structure to represent dose rules for medications. These dose rules are designed to accommodate various patient characteristics, medication properties, and administration guidelines. - -### Dose Rules Model - -![Dose Rules model](https://docs.google.com/drawings/d/e/2PACX-1vQ0JtMXGCuyZ4Tw_EjHErHbvI7b5qXSJjTQsveI8kBbRPyAkh1RzTtw_NsbaPNyiKYgPufPWAk-ZduD/pub?w=1566&h=1022) - -### Table - -| Sheet | Object | Variable | Type | Unit | Description | Comments | -|-------|--------|----------|------|------|-------------|----------| -| DoseRules | **Source** | **Source** | text | | The source of the dose rule | | -| DoseRules | **Generic** | **Name** | text | | The generic name | The naming from the Z-index is used in all small caps. For multiple substance drugs, concatenated with '/' | -| DoseRules | **Generic** | *Shape* | text | | A shape to narrow down the dose rule | The naming from the Z-index is used. | -| DoseRules | **Generic** | *Brand* | text | | A brand to narrow down the dose rule | | -| DoseRules | **Generic** | *GPKs* | text list | | A list of GPKs to narrow down the dose rule | | -| DoseRules | **Indication** | **Indication** | text | | The indication (label) for the dose rule | Indications are from the Kinderformularium or from the Farmacotherapeutisch compas | -| DoseRules | **Route** | **Route** | text | | The route | Can be any route name using the mapping in the Routes sheet | -| DoseRules | **Patient Category** | *Dep* | text | | The department (location) | The department the dose rule applies to | -| DoseRules | **Patient Category** | *Gender* | male / female | | The gender | The gender the doserule applies to | -| DoseRules | **Patient Category** | *MinAge* | int | days | The minimum age | The minimum age the dose rule applies to | -| DoseRules | **Patient Category** | *MaxAge* | int | days | The maximum age | The maximum age the dose rule applies to | -| DoseRules | **Patient Category** | *MinWeight* | int | gram | The minimum weight (in gram) | The minimum weight the dose rule applies to | -| DoseRules | **Patient Category** | *MaxWeight* | int | gram | The maximum weight | The maximum weight the dose rule applies to | -| DoseRules | **Patient Category** | *MinBSA* | float | m2 | The minimum bsa | The minimum bsa the dose rule applies to | -| DoseRules | **Patient Category** | *MaxBSA* | float | m2 | The maximum bsa | The maximum bsa the dose rule applies to | -| DoseRules | **Patient Category** | *MinGestAge* | int | days | The minimum gestational age | The minimum gestational age the dose rule applies to | -| DoseRules | **Patient Category** | *MaxGestAge* | int | days | The maximum gestational age | The maximum gestational age the dose rule applies to | -| DoseRules | **Patient Category** | *MinPMAge* | int | days | The minimum postmenstrual age | The minimum postmenstrual age the dose rule applies to | -| DoseRules | **Patient Category** | *MaxPMAge* | int | days | The maximum postmenstrual age | The maximum postmenstrual age the dose rule applies to | -| DoseRules | **DoseType** | **DoseType** | once / onceTimed / discontinuous / timed / continuous | | The dose type of the dose rule | Can be onderhoud, start, continu, eenmalig, conta, afbouw 'n', or prn. Afbouw can have a number of the 'afbouw' day | -| DoseRules | **DoseType** | *DoseText* | text | | A label for a dose type | | -| DoseRules | **Component** | **Component** | text | | The product the substance belongs to | | -| DoseRules | Substance | *Substance* | text | | The substance used for the below fields | The substance is the generic of part of the generic name, note if generic constists of n substances, there can be up to n dose rules for that generic | -| DoseRules | Schedule | *Freqs* | int list | count_unit/ freq_unit | The possible frequencies | A number list separated with ';', the per time unit = FreqUnit | -| DoseRules | Schedule | *FreqUnit* | text | | The freq unit | The time unit of the frequencies | -| DoseRules | Schedule | *MinTime* | float | time_unit | The minimum time for infusion of a dose | Can be used to calculate an infusion rate for a administration of a substance dose | -| DoseRules | Schedule | *MaxTime* | float | time_unit | The maximum time for infusion of a dose | Can be used to calculate an infusion rate for a administration of a substance dose | -| DoseRules | Schedule | *TimeUnit* | text | | The time unit to measure the infusion | Typically the time unit will be in minute or hours | -| DoseRules | Schedule | *MinInt* | float | int_unit | The minimum interval between two doses | The minimum time interfal between 2 doses, can also be used to calculated a range of frequencies | -| DoseRules | Schedule | *MaxInt* | float | int_unit | The maximum interval between two doses | The maximum time interfal between 2 doses, can also be used to calculate a range of frequencies | -| DoseRules | Schedule | *IntUnit* | text | | The interval unit | The time unit to measure a maximum or minimum interval | -| DoseRules | Schedule | *MinDur* | float | dur_unit | The minimum duration of the dose rule | The time the dose rule is applied | -| DoseRules | Schedule | *MaxDur* | float | dur_unit | The maximum duration of the dose rule | The time the dose rule is applied | -| DoseRules | Schedule | *DurUnit* | text | | The duration time unit | The time unit to measure a maximum or minimum duration | -| DoseRules | **DoseLimit** | **DoseUnit** | text | | The dose unit | The unit used to express the component or substance dose | -| DoseRules | **DoseLimit** | *RateUnit* | text | | The rate unit | The time unit for a dose rate | -| DoseRules | **DoseLimit** | *AdjustUnit* | kg / m2 | | The adjust unit | The unit to adjust the dose with, i.e. kg or m2 | -| DoseRules | **DoseLimit** | *MinQty* | float | dose_unit | The minimum dose quantity | The minimum dose that can be administered each time | -| DoseRules | **DoseLimit** | *MaxQty* | float | dose_unit | The maximum dose quantity | The maximum dose that can be administered each time | -| DoseRules | **DoseLimit** | *NormQtyAdj* | float | dose / adjust_unit | The 'normal' adjusted dose quantity | The recommended adjusted dose quantity, note that this or either a mimimum and/or maximum should be defined. From the normal adjusted dose a +/- 10% margin will be used. | -| DoseRules | **DoseLimit** | *MinQtyAdj* | float | dose / adjust_unit | The minimum adjusted dose quantity | The minimum adjusted dose quantity administered each time | -| DoseRules | **DoseLimit** | *MaxQtyAdj* | float | dose / adjust_unit | The maximum adjusted dose quantity | The maximum adjusted dose quantity administered each time | -| DoseRules | **DoseLimit** | *MinPerTime* | float | dose_unit / freq_unit | The minimum dose quantity per time | The total minimum dose per freq time unit | -| DoseRules | **DoseLimit** | *MaxPerTime* | float | dose_unit / freq_unit | The maximum dose quantity per time | The total maximum dose per freq time unit | -| DoseRules | **DoseLimit** | *NormPerTimeAdj* | float | dose_unit/ adjust_unit/freq_unit | The 'normal' adjusted dose quantity per time | The recommended total adjusted dose quantity per frequency unit, note that this or either a mimimum and/or maximum should be defined. From the normal adjusted dose a +/- 10% margin will be used. | -| DoseRules | **DoseLimit** | *MinPerTimeAdj* | float | dose_unit/ adjust_unit/freq_unit | The minimum adjusted dose quantity per time | The total minimum dose per freq time unit | -| DoseRules | **DoseLimit** | *MaxPerTimeAdj* | float | dose_unit/ adjust_unit/freq_unit | The maximum dose adjusted quantity per time | The total maximum dose per freq time unit | -| DoseRules | **DoseLimit** | *MinRate* | float | dose_unit / rate_unit | The minimum dose rate | The total minimum dose rate per rate time unit | -| DoseRules | **DoseLimit** | *MaxRate* | float | dose_unit / rate_unit | The maximum dose rate | The total maximum dose rate per rate time unit | -| DoseRules | **DoseLimit** | *MinRateAdj* | float | dose_unit / adjust_unit / rate_unit | The minimum adjusted dose rate | The total minimum adjusted dose rate per adjust unit per rate time unit | -| DoseRules | **DoseLimit** | *MaxRateAdj* | float | dose_unit / adjust_unit / rate_unit | The maximum adjusted dose rate | The total maximum adjusted dose rate per adjust unit per rate time unit | - -## Comparison with G-Standaard (ZForm) Implementation - -### Overview GenForm vs ZForm - -The GenForm library uses a flat, filter-based dose rule structure optimized for prescription generation, while the ZForm library (which processes G-Standaard data from the Dutch Z-Index) uses a hierarchical, collection-based structure. This section documents the key differences and mappings between these two implementations. - -### Architectural Differences - -#### GenForm Structure (Flat, Filter-Based) - -```text -DoseRule (single level) -├── PatientCategory (embedded filter) -├── ShapeLimit (optional) -└── ComponentLimits[] (array) - └── SubstanceLimits[] (array of DoseLimit) -``` - -**Key characteristics**: - -- Flat structure with embedded patient category -- One rule per - - Indication, - - Generic, - - Product identifier list, - - Brand option, - - Shape option, - - Route, - - Patient Category, - - DoseType + DoseText -- Filter-oriented: patient attributes are ranges to match against -- Optional atributes can be used to refine applicability of the rule -- Component-centric: explicit Component grouping of substances - -*Note*: The presence or absence of optional attributes means that the rule can be generelalized or specialized as needed. At minumum, a DoseRule must specify the Generic name, Indication, Route, Patient Category, and DoseType to be valid. - -#### ZForm Structure (Hierarchical, Collection-Based) - -```text -DoseRule (G-Standaard based) -└── IndicationDosage[] (list - groups by indication) - └── RouteDosage[] (list - groups by route) - └── ShapeDosage[] (list - groups by shape) - └── PatientDosage[] (list - groups by patient category) - ├── ShapeDosage (single Dosage) - └── SubstanceDosages[] (list of Dosage) -``` - -**Key characteristics**: - -- Five-level hierarchy: Generic → Indication → Route → Shape → Patient -- Collection-oriented: multiple indications/routes/shapes per rule -- Preserves G-Standaard organization structure -- Substance-centric: no explicit Component level - -#### ZIndex Source Structure (G-Standaard Data) - -```text -DoseRule (flat record from Z-Index database) -├── Identification fields (Id, CareGroup, Usage, DoseType) -├── Product arrays (GenericProduct[], PrescriptionProduct[], TradeProduct[]) -├── Filter fields (Routes[], IndicationId, Indication, Gender, Age, Weight, BSA) -├── Frequency (Freq.Frequency, Freq.Time) -└── Six dose fields: Norm, Abs, NormKg, AbsKg, NormM2, AbsM2 -``` - -**Key characteristics**: - -- Flat structure directly from database -- Six explicit dose fields (normal/absolute × unadjusted/per-kg/per-m²) -- String-based units and simple numeric types -- Dutch healthcare-specific fields (CareGroup, HighRisk) - -### Dose Representation Comparison - -#### GenForm DoseLimit (Multi-Dimensional) - -```fsharp -type DoseLimit = { - DoseLimitTarget: LimitTarget // Shape, Component, or Substance - AdjustUnit: Unit option // kg or m² (parameterizes adjustment) - DoseUnit: Unit // Primary dose unit - Quantity: MinMax // Unadjusted dose range - NormQuantityAdjust: ValueUnit option // Normal adjusted dose (±10%) - QuantityAdjust: MinMax // Adjusted dose range - PerTime: MinMax // Total dose per time period - NormPerTimeAdjust: ValueUnit option // Normal per-time adjusted (±10%) - PerTimeAdjust: MinMax // Adjusted per-time range - Rate: MinMax // Infusion rate - RateAdjust: MinMax // Adjusted infusion rate -} -``` - -**Design rationale**: - -- Single structure with AdjustUnit parameter to handle kg vs m² adjustment -- Separates quantity, per-time, and rate dimensions -- Uses "Norm" values to establish ±10% acceptable range -- Strongly typed with ValueUnit - -#### ZForm DoseRange (Six Explicit Fields) - -```fsharp -type DoseRange = { - Norm: MinMax // Normal unadjusted - NormWeight: MinMax * Unit // Normal per kg - NormBSA: MinMax * Unit // Normal per m² - Abs: MinMax // Absolute unadjusted - AbsWeight: MinMax * Unit // Absolute per kg - AbsBSA: MinMax * Unit // Absolute per m² -} -``` - -**Design rationale**: - -- Directly mirrors G-Standaard's six-field structure -- Explicit separation of normal vs absolute limits -- Explicit separation of unadjusted vs weight-adjusted vs BSA-adjusted -- Tuple pairs include the adjustment unit with the range - -#### ZForm Dosage (Multiple Dosage Types) - -```fsharp -type Dosage = { - Name: string // Substance name - StartDosage: DoseRange // Loading/initial dose - SingleDosage: DoseRange // Dose per administration - RateDosage: DoseRange * RateUnit // Continuous infusion rate - TotalDosage: DoseRange * Frequency // Total dose per time period - Rules: Rule list // Original G-Standaard/PedForm rules -} -``` - -**Design rationale**: - -- Four dosage aspects per substance (start/single/rate/total) -- Each aspect has the full six-field DoseRange -- Preserves provenance via Rules field -- Frequency embedded in TotalDosage with structured Frequency type - -*Note*: The original G-Standaard dose rules do not have a direct equivalent to ZForm's Dosage structure. The structure is derived during the ZIndex → ZForm transformation based on the dose fields present in the source data. - -#### ZIndex DoseRule (Source Data) - -```fsharp -type DoseRule = { - // ... other fields ... - Freq: RuleFrequency // { Frequency: float; Time: string } - Norm: RuleMinMax // { Min: float option; Max: float option } - Abs: RuleMinMax - NormKg: RuleMinMax - AbsKg: RuleMinMax - NormM2: RuleMinMax - AbsM2: RuleMinMax - Unit: string // Dose unit as string -} -``` - -**Design rationale**: - -- Exactly matches G-Standaard database schema -- Simple types (float, string) for database mapping -- Six fields correspond to Dutch prescribing guidelines -- Single frequency per rule - -### Mapping: GenForm ↔ ZForm ↔ ZIndex - -#### ZIndex → ZForm Transformation (Implemented in GStand.fs) - -The `GStand.createDoseRules` function performs this transformation: - -1. **Grouping**: Flat ZIndex rules → grouped by (Generic, ATC groups, Indication, Route, Shape, Patient category) -2. **Dose mapping**: Six flat fields → DoseRange record with tuples -3. **Frequency parsing**: String-based `RuleFrequency` → typed `Frequency` with `BigRational list` and `TimeUnit` -4. **Patient aggregation**: Individual rule filters → grouped `PatientCategory` with merged ranges -5. **Hierarchy building**: Flat rules → nested Indication → Route → Shape → Patient structure -6. **Dosage categorization**: Based on `CreateConfig.IsRate`: - - If rate: populate `RateDosage` - - Otherwise: populate `SingleDosage` and `TotalDosage` -7. **Unit conversion**: String units → strongly typed `Unit` from GenUnits library - -**Key functions**: - -- `mapDoses`: Maps six dose fields to DoseRange, multiplies by frequency -- `getDoseRange`: Aggregates multiple doses into single DoseRange -- `getSubstanceDoses`: Creates Dosages per substance with appropriate dosage type -- `getPatients`: Groups rules by patient category -- `groupGenPresProducts`: Builds indication/route/shape/patient hierarchy - -#### ZForm → GenForm Mapping (Conceptual - Not Implemented) - -This mapping would require: - -1. **Hierarchy flattening**: Create separate GenForm DoseRule for each (Indication, Route, Shape, PatientDosage) combination -2. **DoseRange → DoseLimit consolidation**: - - Extract `Quantity` from Norm (min) and Abs (max) if both present - - Determine `AdjustUnit` from presence of NormWeight/AbsWeight (kg) vs NormBSA/AbsBSA (m²) - - Populate `QuantityAdjust` from weight or BSA ranges - - If both weight and BSA present, create two separate rules or choose based on policy -3. **Dosage type selection**: - - Map `RateDosage` → GenForm rule with Rate/RateAdjust populated - - Map `TotalDosage` → GenForm rule with PerTime/PerTimeAdj populated - - Map `SingleDosage` → GenForm rule with Quantity/QuantityAdjust populated -4. **Frequency extraction**: From `TotalDosage.Frequency` → `Frequencies: ValueUnit option` -5. **Component creation**: - - Group SubstanceDosages by product (if available) → ComponentLimit - - Each SubstanceDosage → separate SubstanceLimit in ComponentLimit -6. **Patient category mapping**: - - ZForm PatientCategory → GenForm PatientCategory (mostly compatible) - - Add GenForm-specific fields: Department, Location (default to AnyAccess), PMAge (default to empty) -7. **Provenance**: Extract Rules list → Source field (take first or concatenate) - -**Challenges**: - -- Loss of hierarchy information (multiple indications/routes flattened) -- Ambiguity when both weight and BSA adjustments exist -- Multiple dosage types (Start/Single/Rate/Total) need policy for priority -- GenForm's Component concept has no ZForm equivalent - -#### GenForm → ZForm Mapping (Conceptual - Not Implemented) - -This reverse mapping would require: - -1. **Grouping for hierarchy**: - - Group GenForm DoseRules by (Generic, Indication, Route, Shape) - - Create IndicationDosage for each unique (Generic, Indication) - - Create RouteDosage for each unique (Generic, Indication, Route) - - Create ShapeDosage for each unique (Generic, Indication, Route, Shape) - - Create PatientDosage for each GenForm DoseRule's PatientCategory -2. **DoseLimit → DoseRange expansion**: - - Quantity → Norm or Abs (need policy: use Norm if within normal practice) - - QuantityAdjust + AdjustUnit=kg → NormWeight or AbsWeight - - QuantityAdjust + AdjustUnit=m² → NormBSA or AbsBSA - - If NormQuantityAdjust present, use as center with ±10% for range -3. **Dosage type distribution**: - - If Rate/RateAdjust populated → RateDosage - - If PerTime/PerTimeAdj populated → TotalDosage - - Quantity/QuantityAdjust → SingleDosage - - StartDosage: requires heuristic or left empty -4. **Frequency creation**: - - Extract from GenForm Frequencies → structured Frequency record - - Parse time unit → TimeUnit - - IntervalTime → MinimalInterval -5. **Substance extraction**: - - ComponentLimits[] → flatten to SubstanceDosages list - - Each SubstanceLimit → Dosage record - - ShapeLimit → ShapeDosage (if present) -6. **Product mapping**: - - Extract GPKs from ComponentLimits or DoseRule - - Map to GenericProductLabel list (need GPK int conversion) - - TradeProductLabel: not available in GenForm -7. **ATC and groups**: Not available in GenForm, would need lookup - -**Challenges**: - -- Component structure doesn't map to ZForm's flat substance list -- GenForm's three dose dimensions (Quantity/PerTime/Rate) need distribution to four ZForm dosages -- Missing ATC, therapy groups, generic groups -- Loss of brand/trade product information -- Department, Location, PMAge, RenalRule have no ZForm equivalent - -### Patient Category Differences - -| Field | GenForm | ZForm | ZIndex | Mapping Notes | -|-------|---------|-------|--------|---------------| -| **Department** | `string option` | ❌ Not present | ❌ Not present | GenForm-specific; drop when mapping to ZForm | -| **Gender** | `Male \| Female \| AnyGender` | `Male \| Female \| Undetermined` | `string` ("man"/"vrouw"/"") | Enum name differs; `AnyGender` ↔ `Undetermined` ↔ "" | -| **Age** | `MinMax` (ValueUnit) | `MinMax` (ValueUnit) | `RuleMinMax` (float option) | Compatible between GenForm/ZForm; ZIndex needs unit conversion | -| **Weight** | `MinMax` (ValueUnit) | `MinMax` (ValueUnit) | `RuleMinMax` (float option) | Compatible between GenForm/ZForm; ZIndex needs unit conversion | -| **BSA** | `MinMax` (ValueUnit) | `MinMax` (ValueUnit) | `RuleMinMax` (float option) | Compatible between GenForm/ZForm; ZIndex needs unit conversion | -| **GestAge** | `MinMax` (ValueUnit) | `MinMax` (ValueUnit) | ❌ Not present | Compatible GenForm/ZForm; ZIndex lacks gestational age | -| **PMAge** | `MinMax` (ValueUnit) | ❌ Not present | ❌ Not present | GenForm-specific for neonates; drop when mapping to ZForm | -| **Location** | `PVL \| CVL \| AnyAccess` | ❌ Not present | ❌ Not present | GenForm-specific for venous access; drop when mapping to ZForm | - -### Schedule and Timing Differences - -| Aspect | GenForm | ZForm | ZIndex | Notes | -|--------|---------|-------|--------|-------| -| **Frequency** | `Frequencies: ValueUnit option` | `Frequencies: BigRational list` + `TimeUnit: Unit` + `MinimalInterval: ValueUnit option` | `Freq: { Frequency: float; Time: string }` | ZForm most structured; GenForm simplest | -| **Administration time** | `AdministrationTime: MinMax` | ❌ Not present | ❌ Not present | GenForm-specific for infusion duration | -| **Interval** | `IntervalTime: MinMax` | `MinimalInterval` (in Frequency) | ❌ Not present | Different concepts: GenForm has full range, ZForm has minimum only | -| **Duration** | `Duration: MinMax` | ❌ Not present | ❌ Not present | GenForm-specific for therapy duration | - -### Product and Classification Differences - -| Aspect | GenForm | ZForm | ZIndex | Notes | -|--------|---------|-------|--------|-------| -| **Generic name** | `Generic: string` | `Generic: string` | `Name: string` (in GenPresProduct) | Compatible, field name differs | -| **Shape** | `Shape: string` | `Shape: string list` | `Shape: string` (in GenPresProduct) | ZForm allows multiple shapes | -| **Route** | `Route: string` | `Route: string` | `Routes: string[]` | ZForm/ZIndex allow multiple routes | -| **Brand** | `Brand: string option` | ❌ Not present | `Brand: string` (in TradeProduct) | GenForm and ZIndex have brand, ZForm doesn't | -| **GPK** | In ComponentLimits as `string array` | `GPK: int` (in GenericProductLabel) | `Id: int` (in GenericProduct) | Type difference: GenForm uses string, ZForm/ZIndex use int | -| **HPK** | ❌ Not present | `HPK: int` (in TradeProductLabel) | `Id: int` (in TradeProduct) | ZForm and ZIndex track trade products | -| **ATC** | ❌ Not present | `ATC: string` | `ATC: string` (in GenericProduct) | ZForm and ZIndex include ATC classification | -| **Therapy groups** | ❌ Not present | `ATCTherapyGroup: string`, `ATCTherapySubGroup: string` | ❌ Not present (computed) | ZForm-specific from ATC | -| **Generic groups** | ❌ Not present | `GenericGroup: string`, `GenericSubGroup: string` | ❌ Not present (computed) | ZForm-specific grouping | -| **Synonyms** | ❌ Not present | `Synonyms: string list` | `Synonyms: string[]` (in GenPresProduct) | ZForm and ZIndex track alternative names | - -### DoseType Semantics Comparison - -#### GenForm DoseType (Categorical) - -```fsharp -type DoseType = - | Once of string // Single dose (e.g., pre-operative) - | Discontinuous of string // Maintenance dosing (e.g., q6h) - | Continuous of string // Continuous infusion - | Timed of string // Discontinuous with time specification - | OnceTimed of string // Once with time specification - | NoDoseType -``` - -**Semantics**: Categorizes the entire rule by usage pattern. Each rule has exactly one DoseType. - -#### ZForm Dosage Types (Multi-Faceted) - -```fsharp -type Dosage = { - StartDosage: DoseRange // Initial/loading dose - SingleDosage: DoseRange // Per-administration dose - RateDosage: DoseRange // Continuous rate - TotalDosage: DoseRange // Total per time period -} -``` - -**Semantics**: Each substance has four dosage aspects. All can be populated simultaneously. Not mutually exclusive. - -**Mapping implications**: - -- GenForm's categorical DoseType doesn't directly map to ZForm's multi-faceted Dosage -- GenForm Continuous → ZForm RateDosage populated -- GenForm Discontinuous → ZForm SingleDosage and TotalDosage populated -- GenForm Once → ZForm SingleDosage populated, frequency = 1 -- Reverse mapping requires policy: which ZForm dosage to use for GenForm DoseType? - -### Component vs Substance Organization - -#### GenForm (Component-Centric) - -```fsharp -type DoseRule = { - ShapeLimit: DoseLimit option // Limits at shape level - ComponentLimits: ComponentLimit[] -} - -type ComponentLimit = { - Name: string // Component identifier - GPKs: string array // Products in this component - Limit: DoseLimit option // Component-level limits - Products: Product[] // Product details - SubstanceLimits: DoseLimit[] // Substance-level limits -} -``` - -**Semantics**: - -- Explicit "Component" grouping (e.g., "Component A" + "Component B") -- Allows different products within same component -- Three-level limit hierarchy: Shape → Component → Substance - -#### ZForm (Substance-Centric) - -```fsharp -type PatientDosage = { - ShapeDosage: Dosage // Shape-level dosing - SubstanceDosages: Dosage list // Substance-level dosing -} - -type ShapeDosage = { - GenericProducts: GenericProductLabel list // Products for this shape - TradeProducts: TradeProductLabel list - // ... -} -``` - -**Semantics**: - -- No explicit Component level -- Substances are directly under PatientDosage -- Two-level limit hierarchy: Shape → Substance -- Products associated at ShapeDosage level, not per substance - -**Mapping implications**: - -- GenForm Component concept has no ZForm equivalent -- When mapping GenForm → ZForm: flatten ComponentLimits to SubstanceDosages, lose component grouping -- When mapping ZForm → GenForm: all substances become separate components, or group heuristically - -### Source and Provenance Tracking - -| Aspect | GenForm | ZForm | ZIndex | Purpose | -|--------|---------|-------|--------|---------| -| **Source identifier** | `Source: string` | ❌ Not present | ❌ Not present | GenForm tracks source (e.g., "Kinderformularium") | -| **Original rules** | ❌ Not present | `Rules: Rule list` where `Rule = GStandRule of string \| PedFormRule of string` | ❌ Not present (is the source) | ZForm preserves original rule text | -| **Schedule text** | `ScheduleText: string` | ❌ Not present | ❌ Not present | GenForm keeps human-readable schedule | -| **Rule ID** | ❌ Not present | ❌ Not present | `Id: int` | ZIndex has unique rule identifier | -| **Care group** | ❌ Not present | ❌ Not present | `CareGroup: string` | ZIndex tracks intensive/non-intensive care | -| **Usage** | ❌ Not present | ❌ Not present | `Usage: string` | ZIndex tracks therapeutic/prophylactic | -| **High risk** | ❌ Not present | ❌ Not present | `HighRisk: bool` | ZIndex flags high-risk medications | - -### Clinical Features Comparison - -#### GenForm-Specific Features (Not in ZForm/ZIndex) - -1. **Post-Menstrual Age (PMAge)**: Critical for neonatal dosing -2. **Venous Access Location**: PVL vs CVL affects concentration limits -3. **Administration Time**: Infusion duration for rate calculation -4. **Interval Time**: Full range (not just minimum) -5. **Duration**: Therapy duration limits -6. **Department**: Location-specific rules (ICU, NICU, etc.) -7. **Brand-Specific Rules**: Some rules only for specific brands -8. **Renal Rules**: Link to renal dose adjustments -9. **Component Organization**: Multi-component products (e.g., TPN) -10. **Schedule Text**: Human-readable schedule for display - -**Rationale**: GenForm optimized for pediatric/neonatal intensive care prescription generation. - -#### ZForm-Specific Features (Not in GenForm) - -1. **ATC Classification**: Full ATC code and derived groups -2. **Therapy Groups**: ATCTherapyGroup, ATCTherapySubGroup -3. **Generic Groups**: GenericGroup, GenericSubGroup -4. **Synonyms**: Trade names and alternatives -5. **Hierarchical Organization**: Indication → Route → Shape → Patient -6. **Product Labels**: Separate GenericProductLabel and TradeProductLabel tracking -7. **Rule Provenance**: Original G-Standaard or PedForm rule text -8. **Multiple Shapes/Routes**: One rule can cover multiple shapes and routes - -**Rationale**: ZForm preserves G-Standaard structure and provides comprehensive drug classification. - -#### ZIndex-Specific Features (Not in GenForm/ZForm) - -1. **Rule ID**: Unique database identifier -2. **Care Group**: Intensive vs non-intensive care -3. **Usage**: Therapeutic vs prophylactic -4. **DoseType**: "standaard" vs "verbyzondering" (standard vs special indication) -5. **High Risk**: Medication risk flag -6. **Indication ID**: ICPC/ICD-10 code - -**Rationale**: ZIndex is the authoritative Dutch pharmaceutical database with regulatory tracking. - -### Summary of Key Discrepancies - -#### 1. Architectural Philosophy - -- **GenForm**: Flat, filter-based, one rule per clinical scenario -- **ZForm**: Hierarchical, collection-based, groups related scenarios -- **ZIndex**: Flat, database-oriented, simple types - -#### 2. Dose Representation - -- **GenForm**: Parameterized with AdjustUnit (kg vs m²), three dimensions (Qty/PerTime/Rate) -- **ZForm**: Explicit six fields (Norm/Abs × None/Weight/BSA), four dosage types (Start/Single/Rate/Total) -- **ZIndex**: Explicit six fields matching G-Standaard schema - -#### 3. Clinical Focus - -- **GenForm**: Pediatric/neonatal intensive care (PMAge, Location, Department, infusion timing) -- **ZForm**: General Dutch prescribing (ATC classification, comprehensive grouping) -- **ZIndex**: Dutch pharmaceutical database (regulatory fields, care group, high-risk flags) - -#### 4. Organization Principle - -- **GenForm**: Component-centric with three-level limits (Shape → Component → Substance) -- **ZForm**: Substance-centric with two-level limits (Shape → Substance) -- **ZIndex**: Product-centric with flat dose fields - -#### 5. Interoperability - -- **ZIndex → ZForm**: Implemented in `GStand.fs` with comprehensive transformation -- **ZForm → GenForm**: Not implemented; would require hierarchy flattening and dose consolidation -- **GenForm → ZForm**: Not implemented; would require grouping and dose expansion -- **Direct ZIndex → GenForm**: Not implemented; would need custom mapping - -### Use Case Alignment - -#### GenForm Best For: - -- Clinical prescription generation -- Pediatric and neonatal care -- Complex multi-component products (TPN, chemotherapy) -- Venous access-specific rules -- Department-specific protocols -- Infusion rate calculation - -#### ZForm Best For: - -- G-Standaard data processing -- Drug classification and grouping -- Multiple route/shape scenarios -- Preserving original rule provenance -- Dutch healthcare integration -- Comprehensive pharmaceutical database queries - -#### ZIndex Best For: - -- Authoritative pharmaceutical data source -- Regulatory compliance -- Dutch prescribing guidelines -- High-risk medication tracking -- ICPC/ICD-10 indication coding -- Care group stratification - -### Recommendations for Integration - -1. **Keep Separate**: GenForm and ZForm serve different purposes and should remain separate libraries -2. **Mapping Layer**: Create explicit mapping functions if cross-library queries needed -3. **Shared Types**: Consider extracting common types (MinMax, ValueUnit, Gender) to shared library -4. **Data Flow**: ZIndex → ZForm (implemented) → potential future GenForm mapping layer -5. **Documentation**: Maintain clear documentation of which implementation to use for which scenario -6. **Testing**: If mapping implemented, extensive property-based testing for round-trip conversions where possible - diff --git a/docs/mdr/design-history/order_value_logic.md b/docs/mdr/design-history/order_value_logic.md deleted file mode 100644 index af1b34f..0000000 --- a/docs/mdr/design-history/order_value_logic.md +++ /dev/null @@ -1,191 +0,0 @@ -# Order Value Constraint Logic Design - -## OrderVariable design - -An `OrderVariable` pairs a solver `Variable` with a set of `Constraints`. - -- Variable: identified by `Name`, holding a `ValueRange` (not a single “value”). The `ValueRange` can be unrestricted, range-shaped (min/max), incremented (min/incr/max), or a discrete `ValueSet`. -- Constraints: optional bounds and enumerations that describe what’s allowed for the variable. In code this is a record of four optionals: `Min`, `Max`, `Incr`, and `Values`. - -Applying constraints and/or evaluations leads to recognizable states. The names below align with the current implementation in `OrderVariable`: - -- Unbounded - - Meaning: the constraints record is effectively empty (no `Min`, `Max`, `Incr`, or `Values`). - - Code: `Constraints.isEmpty` returns true. - -- Bounded - - Meaning: constraints define a minimum and/or maximum (and possibly an increment), but no discrete value set has been materialized yet. - - Code: `Constraints.toValueRange` produces a min/max (and optionally incr) range. - -- Enumerable - - Meaning: the variable’s `ValueRange` is in the min/incr/max form, which can be expanded into a discrete set of values. - - Code: `Variable.isMinIncrMax` checks shape; `OrderVariable.minIncrMaxToValues` materializes into a `ValueSet` (optionally pruned). - -- HasValues - - Meaning: there are multiple selectable values remaining (cardinality > 1). - - Code: `OrderVariable.hasValues` delegates to `Variable.hasValues` with the >1 interpretation used by the order logic. - -- Solved - - Meaning: the system considers the variable “done”. This includes the single-value case, but also certain “default” shapes. - - Code: `OrderVariable.isSolved` is true if the variable is a single value OR is unrestricted OR is non‑zero‑positive. This is a deliberate shortcut used broadly in the order math. - -Notes on terminology adjustments: - -- Replaced misspellings/ambiguous terms: - - `UnConstraint` → `Unconstrained` - - `NotContrstraint` → removed in favor of explicit notions above - - `Constraint` → “constraints applied” is implicit via `applyConstraints` and `isWithinConstraints` - - `CanHaveValues` → expressed as the `MinIncrMax` shape that can be materialized into a `ValueSet` - - `Cleared` now explicitly means “unrestricted”, not “empty set of values” - -Key operations (for reference): - -- Apply constraints to the variable: `OrderVariable.applyConstraints` -- Check if current values obey constraints: `OrderVariable.isWithinConstraints` -- Materialize min/incr/max: `OrderVariable.minIncrMaxToValues` -- Inspect cardinality: `OrderVariable.hasValues` (multiple), `OrderVariable.isSolved` (single or default shapes) - -## Order.hasValues: variables checked per prescription type - -An `Order` consists of an `Orderable` and a `Prescription`. The `Prescription` determines the administration type. The `Orderable` has one or more `Components`; each `Component` has zero or more `Items`. The concentration of each `Item` is fixed; the concentration of a `Component` relative to other `Components` can be adjusted. An `Order` can only be changed by selecting a value from a `ValueSet` contained in an `OrderVariable`. - -This note documents the logic for the selection process and the clearing of `OrderVariables`. - -It reviews `Informedica.GenOrder.Lib.Order.hasValues` and maps which variables are checked per prescription type, including filters and caveats. The purpose of `hasValues` is to check whether there are any values left that can/should be selected so an `Order` is sufficiently entered. - -## Checklist - -- Inspect `Order.hasValues` implementation -- Identify variables checked per prescription kind -- Call out filters (constraints/name-based), scope limits (first component/item), and the “any vs all” logic - -## Findings - -### Meaning of “has values” - -An `OrderVariable` “has values” when its underlying `Variable` has a `ValueSet` with multiple selectable values (`Variable.hasValues` → `ValueRange.cardinality > 1`). - -- A single selectable value (cardinality = 1) is not considered “has values”. -- Range-only constraints (min/max) are not considered “values”; they don’t count toward `hasValues`. - -### “Constraints” as used here - -`OrderVariable.hasConstraints` returns true when the variable is neither unrestricted, nor non‑zero‑positive, nor min‑exclusive‑zero. In other words, variables with only these default/non-restrictive shapes are treated as having no effective constraints. - -### Continuous prescriptions - -Explicitly checked variables: - -- Orderable dose rate: `ord.Orderable.Dose.Rate |> Rate.toOrdVar` -- First component’s first item dose rate (if present): first component → first item → `item.Dose.Rate |> Rate.toOrdVar` -- First component’s first item orderable concentration (if present): first component → first item → `item.OrderableConcentration |> Concentration.toOrdVar` - -Scope/caveats: - -- Only the first component and the first item are considered (`List.tryHead` twice); other components/items are ignored by this check. -- Uses `List.exists OrderVariable.hasValues` (true if any of the above has values). - -Included variables (explicitly checked): - -- `id.orb.dos.rte` (OrderableDoseRate) -- `id.n.g.itm.dos.rte` (ItemDoseRate) — only for the first component’s first item -- `id.n.g.itm.orb.cnc` (ItemOrderableConcentration) — only for the first component’s first item - -Excluded in this check: - -- All other variables; they are not considered by `hasValues` for Continuous prescriptions. - -### Discontinuous prescriptions - -Selection: - -- All order variables from `ord |> toOrdVars` -- Filtered to those that have constraints: `List.filter OrderVariable.hasConstraints` -- Excludes variables whose name contains any of: - - `_cmp_qty` - - `_cmp_cnc` - - `_orb_cnt` - - `_orb_cnc` - -Evaluation: - -- `List.exists OrderVariable.hasValues` (true if any remaining variable has values). - -Included (subject to `OrderVariable.hasConstraints`): - -- Prescription-level: `id.pres.freq`, `id.pres.time` (noting equations refer to these as `pres.freq` and `pres.time`) -- Order-level: `id.ord.adj`, `id.ord.time` -- Orderable-level: - - `id.orb.qty`, `id.orb.ord.qty` - - `id.orb.dos.qty`, `id.orb.dos.tot`, `id.orb.dos.rte` - - Adjust variants: `id.orb.dos.qty.adj`, `id.orb.dos.tot.adj`, `id.orb.dos.rte.adj` -- Component-level: - - `id.n.cmp.ord.cnt` - - `id.n.cmp.dos.qty`, `id.n.cmp.dos.tot`, `id.n.cmp.dos.rte` - - Adjust variants: `id.n.cmp.dos.qty.adj`, `id.n.cmp.dos.tot.adj`, `id.n.cmp.dos.rte.adj` -- Item-level: - - `id.n.g.itm.orb.qty` - - `id.n.g.itm.dos.qty`, `id.n.g.itm.dos.tot`, `id.n.g.itm.dos.rte` - - Adjust variants: `id.n.g.itm.dos.qty.adj`, `id.n.g.itm.dos.tot.adj`, `id.n.g.itm.dos.rte.adj` - -Excluded by name filter (variables whose names contain these substrings are excluded): - -- `_cmp_qty` (e.g., `id.n.g.itm.cmp.qty`, `id.n.cmp.qty`) -- `_cmp_cnc` (e.g., `id.n.g.itm.cmp.cnc`) -- `_orb_cnt` (e.g., `id.n.cmp.orb.cnt`) -- `_orb_cnc` (e.g., `id.n.g.itm.orb.cnc`, `id.n.cmp.orb.cnc`) - -Notes: - -- Unit-group conversion (`id.n.g.itm.cnv`) and sum variables are generally computed and may not surface as constrained `OrderVariable`s. - -### Timed prescriptions - -Same as Discontinuous: - -- All `ord |> toOrdVars` with constraints -- Exclude by name substrings: `_cmp_qty`, `_cmp_cnc`, `_orb_cnt`, `_orb_cnc` -- Exists check for `hasValues`. - -Included and excluded sets are the same as for Discontinuous prescriptions (subject to `OrderVariable.hasConstraints` and the same name-based exclusions). - -### Once prescriptions - -Same as Discontinuous/Timed: - -- All `ord |> toOrdVars` with constraints -- Exclude by name substrings: `_cmp_qty`, `_cmp_cnc`, `_orb_cnt`, `_orb_cnc` -- Exists check for `hasValues`. - -Included and excluded sets are the same as for Discontinuous prescriptions (subject to `OrderVariable.hasConstraints` and the same name-based exclusions). - -### OnceTimed prescriptions - -Same as Discontinuous/Timed/Once: - -- All `ord |> toOrdVars` with constraints -- Exclude by name substrings: `_cmp_qty`, `_cmp_cnc`, `_orb_cnt`, `_orb_cnc` -- Exists check for `hasValues`. - -Included and excluded sets are the same as for Discontinuous prescriptions (subject to `OrderVariable.hasConstraints` and the same name-based exclusions). - -### Observations - -- The function returns true if any relevant variable has multiple values to pick from (exists), not if all relevant variables do. -- For Continuous, the check is narrowly scoped to: - - The drip rate of the orderable - - The first item’s dose rate - - The first item’s orderable concentration - -- For the other prescription types, relevance is decided by constraints presence and by excluding names containing the specified substrings. - -### Known limitations and TODOs - -- Name-based exclusions are heuristic and currently marked with a TODO in code; they’re subject to change. The substrings roughly refer to: - - `_cmp_qty`: component quantity - - `_cmp_cnc`: component concentration - - `_orb_cnt`: orderable content/count - - `_orb_cnc`: orderable concentration -- For Continuous, only the first component and its first item are checked. -- `hasValues` only considers ValueSets with cardinality > 1; range-only constraints won’t trip this check, even if user input may still be required elsewhere in the flow. -- For the other prescription types, relevance is decided by constraints presence and by excluding names containing the specified substrings. diff --git a/docs/mdr/design-history/state-of-affairs.md b/docs/mdr/design-history/state-of-affairs.md index f9cacdc..d274622 100644 --- a/docs/mdr/design-history/state-of-affairs.md +++ b/docs/mdr/design-history/state-of-affairs.md @@ -1,4 +1,4 @@ -# The State of the Affairs of the GenPres project. +# The State of the Affairs of the GenPres project The current (i.e. 2nd of December 2021) of the GenPres project will be described in this "Wiki blog". @@ -8,41 +8,40 @@ The GenPres project aims to build a 'one-click' medical prescription system. All - Looking things up. For example the right dose. - Calculations. Like the amount and frequency or the preparation of a prescription and -- Evaluation. Was the prescription applied to the right patient, when, how and to what effect +- Evaluation. Was the prescription applied to the right patient, when, how and to what effect will be covered by the GenPres system. This system in its prototypical form has already been used for years on a Pediatric Critical Care unit with a substantial amount of success. The main challenge in this project is to enable all the necessary calculations in such way that the order of entry of the required quantitative data doesn't matter and the system always feeds back what the range is of the possible remaining quantitative variables. This enables the system to be able to calculate all possible scenarios from which the prescriber just needs to make a choice. Hence the one click. -The calculations involved and how to solve those are described [here](https://github.com/informedica/Informedica.GenPres.Lib/wiki/Informedica.GenOrder.Lib). +The calculations involved and how to solve those are described in the [domain documentation](../../domain/core-domain.md). ## Short History -This project actually started years ago. The 10th of June 2013 there was the first commit in a repository that was trying to solve this problem. Due to entry of some sensitive data the repository remains private. But a small presentation of the capabilities of the system was recorded and can be viewed at [Vimeo](https://vimeo.com/manage/videos/78822206). +This project actually started years ago. The 10th of June 2013 there was the first commit in a repository that was trying to solve this problem. Due to entry of some sensitive data the repository remains private. But a small presentation of the capabilities of the system was recorded and can be viewed at [Vimeo](https://vimeo.com/manage/videos/78822206). -Currently we are working on a more definitive solution. +Currently we are working on a more definitive solution. ## The Current State The GenPres project has to tackle a number of problems: -1. [x] The calculations involved have to be solved in any possible order. This means that if you calculate something like, total dose = frequency x dose. Then either a total dose and a frequency or total dose and a dose or a dose and a frequency can be entered and the rest will be calculated. This has to be done for a whole set of equations in which variables can be reoccur. +1. [x] The calculations involved have to be solved in any possible order. This means that if you calculate something like, total dose = frequency x dose. Then either a total dose and a frequency or total dose and a dose or a dose and a frequency can be entered and the rest will be calculated. This has to be done for a whole set of equations in which variables can be reoccur. 2. [x] All calculations have to performed without the need to explicitly supply the units of measurement. This is done by calculating the dependent units of measurement by the supplied values. All calculations are then performed in 'base units' and then converted back to the appropriate units. -3. [x] Calculations have to be performed using absolute precision quantities. Meaning 1/3 cannot be rounded to 0.333 as it is then impossible to know whether the resulting value is precise enough and whether this value has been calculated for other equations. Therefore, the GenPres system uses BigRationals. -4. [x] The calculations are further complicated by the fact that this is actually a process of applying restrictions of the possible ranges of values. So in the case of calculating total dose = frequency x dose, each variable total dose, frequency and dose can be restricted by a minimum, maximum, set of increments or a specific set of values. Therefore, the calculation can look like total dose [60 .. 80] = frequency [2, 3, 4] x dose [120 .. 320]. -4. [ ] The system has to be performant in doing the calculations. However, for some calculations the list of possible values can be large resulting in long calculation times. This has to be resolved using a mathematical modelling. -5. [ ] The system needs 2 large sources of information, 1) product information, which products are available and 2) dosing and preparation rules. Using these information sources the system is able to calculate the exact possible scenarios from which a clinician or health care worker can choose from. -6. [ ] In the end the users need to interact with the system. In order for the system to be usable on different devices a web based solution seems appropriate. +3. [x] Calculations have to be performed using absolute precision quantities. Meaning 1/3 cannot be rounded to 0.333 as it is then impossible to know whether the resulting value is precise enough and whether this value has been calculated for other equations. Therefore, the GenPres system uses BigRationals. +4. [x] The calculations are further complicated by the fact that this is actually a process of applying restrictions of the possible ranges of values. So in the case of calculating total dose = frequency x dose, each variable total dose, frequency and dose can be restricted by a minimum, maximum, set of increments or a specific set of values. Therefore, the calculation can look like total dose [60 .. 80] = frequency [2, 3, 4] x dose [120 .. 320]. +5. [ ] The system has to be performant in doing the calculations. However, for some calculations the list of possible values can be large resulting in long calculation times. This has to be resolved using a mathematical modelling. +6. [ ] The system needs 2 large sources of information, 1) product information, which products are available and 2) dosing and preparation rules. Using these information sources the system is able to calculate the exact possible scenarios from which a clinician or health care worker can choose from. +7. [ ] In the end the users need to interact with the system. In order for the system to be usable on different devices a web based solution seems appropriate. ## The Big Issues Overall there are 3 remaining issues that have to be resolved. -1. The performance problem. For this there a cooperation has started with the mathematical department of the Utrecht University. The aim is to model ranges such that they enable efficient calculations. -2. Available information depends on a nation wide product database. There is already code to extract, transform and load all product data such that it can be used for calculations. For the dosing and preparation rules -3. The user needs to interact with the system. A first usability project could be started with calculations limited to the scenarios in which the system is already performant. This is the case for all calculations involving an intermittent dosing regime or standard concentrations. +1. The performance problem. For this there a cooperation has started with the mathematical department of the Utrecht University. The aim is to model ranges such that they enable efficient calculations. +2. Available information depends on a nation wide product database. There is already code to extract, transform and load all product data such that it can be used for calculations. For the dosing and preparation rules +3. The user needs to interact with the system. A first usability project could be started with calculations limited to the scenarios in which the system is already performant. This is the case for all calculations involving an intermittent dosing regime or standard concentrations. ## Specific Use Case A first specific use case could be the creation of an emergency medication list, to be used in acute situations in pediatric medicine. Currently incentive is collected to enable funding of this project. - diff --git a/docs/mdr/design-history/ui-wireframes.md b/docs/mdr/design-history/ui-wireframes.md index 1fd177b..32af21a 100644 --- a/docs/mdr/design-history/ui-wireframes.md +++ b/docs/mdr/design-history/ui-wireframes.md @@ -146,4 +146,4 @@ These wireframes describe the main user interface flows for GenPRES, a clinical --- -> These wireframes are based on repository structure, README details, and standard clinical workflow for drug order support. Adapt as needed for final visual or interactive prototypes. \ No newline at end of file +> These wireframes are based on repository structure, README details, and standard clinical workflow for drug order support. Adapt as needed for final visual or interactive prototypes.