openEHR logo

openEHR CDS, Guidelines and Planning Examples

Issuer: openEHR Specification Program

Release: PROC latest

Status: DEVELOPMENT

Revision: [latest_issue]

Date: [latest_issue_date]

Keywords: process, task planning, CDS, CPG, decision logic, examples, workflow

openEHR components
© 2017 - 2022 The openEHR Foundation

The openEHR Foundation is an independent, non-profit foundation, facilitating the sharing of health records by consumers and clinicians via open specifications, clinical models and open platform implementations.

Licence

image Creative Commons Attribution-NoDerivs 3.0 Unported. https://creativecommons.org/licenses/by-nd/3.0/

Support

Issues: Problem Reports
Web: specifications.openEHR.org

Amendment Record

Issue Details Raiser Completed

PROC Release 1.6.0

1.0.1

Convert [term_code] to #term_code.

T Beale

22 Feb 2022

1.0.0

Add initial version of BMJ Sepsis example.

T Beale

02 Mar 2021

Add initial version of NEWS2 DLM.

T Beale

02 Mar 2021

Add CHA2DS2-VASc, qRISK3 and common DLM (BMI, BSA) examples.

T Beale

31 Jan 2021

Add ACEP Covid19 severity guideline (version 1).

T Beale

03 Dec 2020

Add perinatal care DLM.

D S Alves

18 Nov 2020

Add RCHOPS21 chemotherapy example.

T Beale

02 Jun 2020

PROC Release 1.5.0

PROC Release 1.0.0

0.1.1

Replace 'manual notification' callback by normal Handoff followed by manual notification Task wait state.

M Polajnar,
T Beale

16 Apr 2020

0.1.0

Initial writing.

T Beale,
B Næss

25 Apr 2019

Acknowledgements

Contributors

  • Danielle S Alves, RN, midwife, Federal University of Pernambuco (UFPE), Brazil

  • Bjørn Næss, DIPS, Norway

Support

The work reported in this specification has been funded by the following organisations:

  • DIPS, Norway

  • Marand d.o.o., Slovenia

Trademarks

  • 'openEHR' is a trademark of the openEHR Foundation.

  • 'OMG' is a trademark of the Object Management Group.

1. Preface

1.1. Purpose

This document contains elaborated examples of the openEHR Process framework, including Task Plans and Decision Logic Modules, with diagrams in TP-VML.

The intended audience includes:

  • Plan and Guideline authors;

  • Tool vendors.

Prerequisite documents for reading this document include:

1.3. Status

This specification is in the DEVELOPMENT state. The development version of this document can be found at https://specifications.openehr.org/releases/PROC/latest/process_examples.html.

Known omissions or questions are indicated in the text with a 'to be determined' paragraph, as follows:

TBD: (example To Be Determined paragraph)

1.4. Feedback

Feedback may be provided on the process specifications forum.

Issues may be raised on the specifications Problem Report tracker.

To see changes made due to previously reported issues, see the PROC component Change Request tracker.

2. Overview

2.1. Draw.io Tool mode

The following files can be downloaded and then imported into draw.io as libraries to provide a working palette for TP-VML diagrams.

3. Teamwork

The examples in this section illustrate the use of TP for team-based work plans, including hand-offs, callbacks and other kinds of coordination.

3.1. Out-patient Eye Clinic Encounter

This example is based on the original description of DIPS Eye encounter example.

outpatient eye clinic
Figure 1. Outpatient eye clinic encounter

3.1.1. Plan Overview

As for all Plans defined in the Task Planning formalism, it must be remembered that the Plan definition above is what the TP engine executes. It is the result of the execution (including worker allocation and communication, which is not shown in the definition) that causes workers in the real world to do things. Additionally, what the TP engine knows about the real world is limited to what it is told - many actions and events can occur outside the TP computing environment that will remain unknown to the system unless it is informed (e.g. by Manual notification).

The Work Plan consists of two top-level Task Plans, one for the patient and one for the clinic administrator / reception. The latter has two sub-plans linked by hand-off Tasks.

The purpose of the patient top-level Task Plan is to allow the system to notify the patient of the visit, via a reminder on the day of the visit, or some fixed time beforehand. The driving event is the calendar appointment, which is waited on by both the patient and the clinic admin Task Plans. It is assumed that longer term reminders, opportunities for changing appointments and so on are managed by another system that see the same calendar events, and is responsible for setting the calendar events in the first place. Thus, in the model above, the patient top-level plan is not really necessary (he/she will be notified by the appointment system), and is mainly included for purposes of demonstration.

3.1.2. Detailed Description

The main work of the Work Plan is in the other three Task Plans, which essentially encode the following logic:

Clinic Administrator:

  • clinic has a live Task Plan waiting on appointment A for patient P, at 2019-02-15 09:30:00;

  • when this calendar timepoint is reached, the TP system 'opens' the appointment via a System Request to the clinic appointment system (details not shown);

  • WAIT: the clinic Task Plan enters a new wait state for patient P, for appointment A;

Patient:

  • patient arrives at clinic (modelled as a Manual notification);

Clinic Administrator:

  • receive patient, record presence;

  • Hand-off: pass to consultation (e.g. send to waiting area);

  • WAIT: until manual notification (patient returns)

Nurse:

  • receive patient & check EMR

  • review eye function, decide on whether to send to doc or not:

    • EITHER: return to reception

    • OR: pass to doctor

Specialist:

  • receive patient and check EMR

  • perform examination

  • update EMR

  • send patient back to reception.

4. Order Management

The examples in this section illustrate the use of TP for order management, where openEHR Instructions and Actions (or other non-openEHR equivalents) are created and tracked.

4.1. Order Coordination

This example is based on a standard Moscow City clinic protocol, and covers a 12 month period.

order coordination
Figure 2. GP order coordination

4.1.1. Plan Overview

The Work Plan shown above defines the tasks for a 'standard health check' that includes a chest x-ray, a full blood panel and a hypertension checkup. The Plan executes over the periof a year, and consists of a health coordinator creating orders for the three items, via UI forms. The result of creating these orders will be the creation of a normal Composition and Instruction in the openEHR EHR for the patient. At some later point in time, the coordinator will action these orders, which will cause the EHR data to be used to create appropriate API calls / messages to the relevant target systems (radiology clinic, pathology lab, consultant) that will further cause appointments and attendances in the normal way by the patient. Each of these 'execute order' Tasks will block and wait for appropriate callbacks resulting from each of the orders being fulfilled and corresponding Actions being committed to the EHR (or else timeouts, if nothing happens). With the received results, the coordinator creates a health summary for the patient and commits that to the EHR.

4.1.2. Detailed Description

TBD

5. Multi-drug Chemotherapy

This section illustrates multi-drug chemotherapy with complex dosing and timing arrangements.

This example is based on the version of RCHOPS-21 documented by NHS Thames Valley Cancer Network.

5.1. Limitations

The following elements of the plan are not yet included (mainly for brevity of the example):

  • Vincristine dose modification due to hepatic impairment;

  • Concurrent meds only shown in summarised form;

  • Exception pathways to handle patient reactions not shown.

5.2. Plan Definition

The following shows the pre-medication phase.

RCHOPS21 pre
Figure 3. RCHOPS21 pre-med phase

The following shows the main regime, including conditional addition of Rituximab / methotrexate for high IPI patients.

RCHOPS21 admin
Figure 4. RCHOPS21 administration phase

5.3. RCHOPS21 Decision Logic Module

dlm RCHOPS21

definitions -- Descriptive

    language = {
        original_language: [ISO_639-1::en]
    }
    ;

    description = {
        lifecycle_state: "unmanaged",
        original_author: {
            name:           "Thomas Beale",
            email:          "thomas.beale@openEHR.org",
            organisation:   "openEHR Foundation <http://www.openEHR.org>",
            date:           "2021-01-10"
        },
        details: {
            "en" : {
                language: [ISO_639-1::en],
                purpose: "NHS CHOPS-21 chemotherapy guideline ...."
            }
        }
    }
    ;

use
    BSA: Body_surface_area.v0.5.0

preconditions
    has_lymphoma_diagnosis

definitions -- Reference

    paracetamol_dose: Quantity = 1g;
    chlorphenamine_dose: Quantity = 10mg;
    prednisolone_dose_per_m2: Quantity = 40mg;
    rituximab_dose_per_m2: Quantity = 375mg;
    doxorubicin_dose_per_m2: Quantity = 50mg;
    vincristine_dose_per_m2: Quantity = 1.4mg;
    cyclophosphamide_dose_per_m2: Quantity = 750mg;
    cycle_period: Duration = 3w;
    cycle_repeats: Integer = 6;

input -- State

    has_lymphoma_diagnosis: Boolean
        time_window = tw_current_episode

input -- Tracked state

    staging: Terminology_term «ann_arbor_staging»
        currency = 30 days
        time_window = tw_current_episode
        ;

    has_metastases: Boolean
        currency = 30 days
        time_window = tw_current_episode
        ;

    |
    | Neutrophils
    |
    neutrophils: Real
        currency = 3d,
        ranges["/L"] =
            --------------------------------
            |>1 x 10^9|:          #high,
            |0.5 - 1 x 10^9|:     #low,
            |<0.5 x 10^9|:        #very_low
            --------------------------------
        ;

    |
    | Platelets
    |
    platelets: Real
        currency = 12h,
        ranges["/L"] =
            ------------------------------
            |>75 x 10^9|:       #normal,
            |50 - 74 x 10^9|:   #low,
            |<50 x 10^9|:       #very_low
            ------------------------------
        ;

    |
    | Bilirubins
    |
    bilirubin: Real
        currency = 12h,
        ranges["mmol/L"] =
            ----------------------------
            |<20|:          #normal,
            |20 - 51|:      #high,
            |51 - 85|:      #very_high,
            |>85|:          #crit_high
            ---------------------------
        ;

    |
    | Glomerular filtration rate
    |
    gfr: Real
        currency = 24h,
        ranges["mL/min"] =
            ----------------------
            |>20|:      #normal,
            |10 - 20|:  #low,
            |<10|:      #very_low
            ----------------------
        ;

    |
    | Lactate dehydrogenase
    |
    ldh: Real
        currency = 24h,
        ranges["mL/min"] =
            --------------------------
            |>20 |:         #normal,
            |10 - 20|:      #low,
            |<10|:          #very_low
            --------------------------
        ;

rules -- Conditions

    high_ipi:
        Result := ipi_risk  {#ipi_high_risk, #ipi_intermediate_high_risk}
        ;

rules -- Main

    |
    | patient fit to undertake regime
    |
    patient_fit:
        Result := not
            (platelets.in_range (#very_low) or
             neutrophils.in_range (#very_low))
        ;

    prednisolone_dose: Quantity
        Result := prednisolone_dose_per_m2 * BSA.bsa_m2
        ;

    rituximab_dose: Quantity
        Result := rituximab_dose_per_m2 * BSA.bsa_m2
        ;

    doxorubicin_dose: Quantity
        Result := doxorubicin_dose_per_m2 * BSA.bsa_m2
            * case bilirubin.range in
                ====================
                #high:        0.5,
                #very_high:   0.25,
                #crit_high:   0.0
                ====================
        ;

    |
    | TODO: hepatic impairment dose modification
    |
    vincristine_dose: Quantity
        Result := vincristine_dose_per_m2 * BSA.bsa_m2
        ;

    |
    | CHECK: is low platelets and GFR dose modification
    | cumulative?
    |
    cyclophosphamide_dose: Quantity
        Result := cyclophosphamide_dose_per_m2 * BSA.bsa_m2
            * case platelets.range in
                ===================
                #normal:      1,
                #low:         0.75
                ===================
                ;
            * case gfr.range in
                ===================
                #normal:      1,
                #low:         0.75,
                #very_low:    0.5
                ===================
        ;

    |
    | International Prognostic Index
    | ref: https:|en.wikipedia.org/wiki/International_Prognostic_Index
    |
    | One point is assigned for each of the following risk factors:
    |     Age greater than 60 years
    |     Stage III or IV disease
    |     Elevated serum LDH
    |     ECOG/Zubrod performance status of 2, 3, or 4
    |     More than 1 extranodal site
    |
    | The sum of the points allotted correlates with the following risk groups:
    |     Low risk (0-1 points) - 5-year survival of 73%
    |     Low-intermediate risk (2 points) - 5-year survival of 51%
    |     High-intermediate risk (3 points) - 5-year survival of 43%
    |     High risk (4-5 points) - 5-year survival of 26%
    |
    ipi_raw_score: Integer
        Result.add (
            ---------------------------------------------
            age > 60                             ? 1 : 0,
            staging  {#stage_III, #stage_IV} ? 1 : 0,
            ldh.in_range (#normal)              ? 1 : 0,
            ecog > 1                             ? 1 : 0,
            extranodal_sites > 1                 ? 1 : 0
            ---------------------------------------------
        )
        ;

    ipi_risk: Terminology_code
        Result :=
            case ipi_raw_score in
                =======================================
                |0..1|  : #ipi_low_risk,
                |2|     : #ipi_intermediate_low_risk,
                |3|     : #ipi_intermediate_high_risk,
                |4..5|  : #ipi_high_risk;
                =======================================
        ;

definitions -- Terminology

    terminology = {
        term_definitions: {
            "en" : {
                "paracetamol_dose" : {
                    text: "paracetamol dose",
                    description: "paracetamol base dose level per sq. m of BSA"
                },
                "chlorphenamine_dose" : {
                    text: "chlorphenamine dose",
                    description: "chlorphenamine base dose level per sq. m of BSA"
                },
                "staging" : {
                    text: "Cancer staging",
                    description: "Cancer staging (Ann Arbor system)"
                },
                "has_metastases" : {
                    text: "Metastatic status",
                    description: "Status of metastasis of cancer"
                },
                "neutrophils" : {
                    text: "neutrophils",
                    description: "neutrophils level"
                },
                "platelets" : {
                    text: "platelets",
                    description: "platelets level"
                },
                "ipi_low_risk" : {
                    text: "low risk: 5y survival - 73%",
                    description: ".."
                },
                "ipi_intermediate_low_risk" : {
                    text: "intermediate-low risk: 5y survival - 51%",
                    description: ".."
                },
                "ipi_intermediate_high_risk" : {
                    text: "intermediate-high risk: 5y survival - 43%",
                    description: "..."
                },
                "ipi_high_risk" : {
                    text: "high risk: 5y survival - 26%",
                    description: "..."
                }
            }
        }
    }

6. Antenatal Care

The following pregnancy care DLM was developed by Danielle S Alves (RN, midwife) as part of her PhD thesis at Federal University of Pernambuco (UFPE), Brazil.

6.1. Work Plan

The following Work Plan is the standard risk assessment for an antenatal visit.

prenatal risk assessment2
Figure 5. Pre-natal risk assessment Work Plan

6.2. Pregnancy Risk Assessment DLM

dlm ruleset pregnancy_risk_assessment.v0.5.0

definitions -- Descriptive

    language = {
            original_language: [ISO_639-1::en]
        }
        ;

    description = {
            lifecycle_state: "unmanaged",
            original_author: {
                name:           "Danielle Santos Alves",
                email:          "dsa3@cin.ufpe.br",
                organisation :  "Universidade Federal de Pernambuco",
                date:           2020-12-02
            },
            details = {
                "en" : {
                    language: [ISO_639-1::en],
                    purpose:  "Rules representing the risks during pregnancy."
                }
            },
            copyright: "© 2020 Danielle Santos Alves",
            licence: "Creative Commons CC-BY <https://creativecommons.org/licenses/by/3.0/>",
        }
        ;

preconditions

    is_pregnant

definitions -- Types

    Risk_type ::= Ordinal
        map =
            -------------------
            #emergency:    2,
            #high_risk:    1,
            #low_risk:     0
            -------------------
        ;

input -- Historical state

    is_type1_diabetic: Boolean
        ;

    previous_obstetric_hypertension: Boolean
        ;

    previous_pre_eclampsia: Boolean
        ;

    previous_eclampsia: Boolean
        ;

    previous_gestational_diabetes: Boolean
        ;

    family_history_of_diabetes: Boolean
        ;

    race_related_diabetes_risk: Boolean
        ;

    |
    | Macrosomic baby from any previous pregnancy
    |
    previous_macrosomic_baby: Boolean
        ;

    is_pregnant: Boolean
        ;

    has_gestational_diabetes: Boolean
        ;

    has_pregnancy_hypertension: Boolean
        ;

    has_pre_eclampsia: Boolean
        ;

    has_eclampsia: Boolean
        ;

    has_anaemia_of_pregnancy: Boolean
        ;

input -- Tracked State

    |
    | Possible values:
    |   [premature rupture],
    |   #polyhydramnios, #oligohydramnios,
    |   [severe polyhydramnios], [severe oligohydramnios]
    |
    amniotic_fluid_state: Terminology_term «amniotic_fluid_state»
        currency = 24h
        ;

    uterine_fundal_height: Quantity
        currency = 24h
        ;

    vaginal_blood_flow: Quantity
        currency = 30mins,
        ranges["mL/hr"] =
            ---------------------------
            |> 500|:    #critical_high
            ---------------------------
        ;

    |
    | Assessment of vaginal bleeding, pain, confirm
    | with ultrasound. Result value-set includes
    | |placenta previa|, |risk of miscarriage|,
    | |ectopic pregnancy| etc
    |
    vaginal_physical_exam_assessment: Terminology_term
        currency = 48h
        ;

    vomiting_assessment: Terminology_term
        currency = 48h
        ;

    ultrasound_finding: Terminology_term
        currency = 48h
        ;

    |
    | Amniotic fluid index (cm) via 4-quadrant method
    |
    amniotic_fluid_index: Real
        currency = 24h,
        ranges["cm"] =
            ------------------------------------
            |> 14|:            #polyhydramnios,
            | 5 ..  14|:     #normal,
            |< 5|:             #oligohydramnios
            ------------------------------------
        ;

    labour_onset_assessment: Terminology_term
        currency = 24h
        ;

rules -- Main

    |
    | Convert BMI to ranges
    |
    bmi_range: Terminology_code «COMMON.simple_ranges»,
        Result := case BMI.BMI in
            ===========================
            |> 30|:           #high,
            ---------------------------
            | 15 ..  30|:   #normal,
            ---------------------------
            |< 15|:           #low
            ===========================
        ;

    |
    | Possible values:
    |    |excluded|, |anaemia of pregnancy|
    |
    anaemia_type: Terminology_term «anaemia_type»,
        Result := not has_anaemia_of_pregnancy ? #excluded : #anaemia_of_pregnancy
        ;

    ultrasound_required: Boolean
        Result := fundal_height_related_risk != #low_risk or
                amniotic_fluid_risk != #low_risk or
                vaginal_bleeding_related_risk != #low_risk
        ;

    anaemia_risk: Risk_type
        Result := case anaemia_type in
            ============================================
            #severe_anaemia_of_pregnancy:  #emergency,
            --------------------------------------------
            #anaemia_of_pregnancy:         #high_risk,
            --------------------------------------------
            *:                              #low_risk
            ============================================
        ;

    fundal_height_related_risk: Risk_type
        Result := case ultrasound_finding in
            =================================================
            #interuterine_growth_retardation,
            #multiple_pregnancy,
            #macrosomia:                        #high_risk,
            -------------------------------------------------
            *:                                   #low_risk
            =================================================
        ;

    amniotic_fluid_risk: Risk_type
        Result := case amniotic_fluid_state in
            =========================================
            #premature_rupture,
            #severe_oligohydramnios,
            #severe_polyhydramnios:     #emergency,
            -----------------------------------------
            #polyhydramnios,
            #oligohydramnios:           #high_risk,
            -----------------------------------------
            *:                            #low_risk
            =========================================
        ;

    vaginal_bleeding_related_risk: Risk_type
        Result := case vaginal_physical_exam_assessment in
            =================================================
            #ectopic_pregnancy,
            #gestational_trophoblastic_disease: #emergency,
            -------------------------------------------------
            #placenta_previa,
            #risk_of_miscarriage:               #high_risk,
            -------------------------------------------------
            *:                                   #low_risk
            =================================================
        ;

    gestational_diabetes_risk: Risk_type
        Result := choice of
            =================================================
            bmi_range = #high or
            previous_macrosomic_baby or
            previous_gestational_diabetes or
            family_history_of_diabetes or
            race_related_diabetes_risk or
            has_gestational_diabetes or
            is_type1_diabetic:                  #high_risk,
            -------------------------------------------------
            *:                                  #low_risk
            =================================================
        ;

    hypertension_risk: Risk_type
        Result := choice of
            =================================================
            has_pre_eclampsia or
            has_eclampsia:                      #emergency,
            -------------------------------------------------
            previous_obstetric_hypertension or
            previous_pre_eclampsia or
            previous_eclampsia or
            has_pregnancy_hypertension:         #high_risk,
            -------------------------------------------------
            *:                                  #low_risk
            =================================================
        ;

   labour_onset_pathway: Terminology
        Result := case labour_onset_assessment in
            ====================================
            #placental_abruption,
            #premature_labour:    #emergency,
            ------------------------------------
            #onset_of_labour,
            #labour_first_stage:  #maternity,
            ------------------------------------
            *:                     #observation
            ====================================
        ;

rules -- Output

    |
    | Return the highest level risk of any of the
    | assessed risks
    |
    effective_risk: Risk_type
        Result := Result.max ({fundal_height_related_risk,
                    amniotic_fluid_risk,
                    vaginal_bleeding_related_risk,
                    hypertension_risk,
                    hyperemesis_related_risk,
                    gestational_diabetes_risk,
                    anaemia_risk})
        ;

definitions -- Terminology

    terminology = {
        term_definitions = {
            "en" : {
                "low_risk" : {
                    text: "Normal obstetric care",
                    description: "..."
                },
                "emergency" : {
                    text: "Obstetric emergency",
                    description: "..."
                },
                "high_risk" : {
                    text: "Refer to high risk care",
                    description: "..."
                },
                "premature_rupture" : {
                    text: "Premature rupture of membranes",
                    description: "..."
                },
                "polyhydramnios" : {
                    text: "polyhydramnios",
                    description: "..."
                },
                "oligohydramnios" : {
                    text: "oligohydramnios",
                    description: "..."
                },
                "severe_polyhydramnios" : {
                    text: "severe polyhydramnios",
                    description: "..."
                },
                "severe_oligohydramnios" : {
                    text: "severe oligohydramnios",
                    description: "..."
                },
                "severe_anaemia_of_pregnancy" : {
                    text: "anaemia of pregnancy, severe",
                    description: "..."
                },
                "anaemia_of_pregnancy" : {
                    text: "anaemia of pregnancy",
                    description: "..."
                },
                "amniotic_fluid_risk" : {
                    text: "Risk of pregnancy-related amniotic fluid",
                    description: "..."
                },
                "hypertension_risk" : {
                    text: "Risk of pregnancy-related hypertension",
                    description: "..."
                },
                "diabetes_risk" : {
                    text: "Risk of pregnancy-related diabetes",
                    description: "..."
                },
                "anaemia_risk" : {
                    text: "Risk of pregnancy-related anaemia",
                    description: "..."
                },
                "previous_macrosomic_baby" : {
                    text: "Baby weighing 4.5kg or above",
                    description: "..."
                },
                "previous_gestational_diabetes" : {
                    text: "xxx",
                    description: "..."
                },

                "ectopic_pregnancy" : {
                    text: "Ectopic pregnancy",
                    description: "..."
                },
                "gestational_trophoblastic_disease" : {
                    text: "Gestational trophoblastic disease",
                    description: "..."
                },
                "previous_macrosomic_baby" : {
                    text: "Baby weighing 4.5kg or above",
                    description: "..."
                },
                "previous_gestational_diabetes" : {
                    text: "xxx",
                    description: "..."
                }
            }
        },
        value_sets = {
            "amniotic_fluid_state" : {
                id: "amniotic_fluid_state",
                members: ["premature_rupture", "polyhydramnios", "oligohydramnios", "severe_polyhydramnios", "severe_oligohydramnios"]
            },
            "anaemia_type" : {
                id: "anaemia_type",
                members: ["excluded", "anaemia_of_pregnancy"]
            }
        }
    }
    ;

7. Breast Cancer Decision Protocol

7.1. Decision Logic Module

dlm guideline Oncology_breast_cancer.v0.5.0

input -- Historical state

    has_heart_failure_class_II: Boolean

    has_heart_failure_class_III: Boolean

    has_heart_failure_class_IV: Boolean

    has_allergy_to_taxanes: Boolean

input -- Tracked State

    tnm_t: String
        currency = 60 days

    tnm_n: String
        currency = 60 days

    tnm_m: String
        currency = 60 days

    tnm_g: String
        currency = 60 days

    estrogen_receptor: Terminology_term «pos_neg»
        currency = 60 days

    progesterone_receptor:  Terminology_term «pos_neg»
        currency = 60 days

    her2_expression: Terminology_term «pos_neg»
        currency = 60 days

    ki67: Quantity
        currency = 60 days
        ranges["%"] =
            ------------------
            | 14|:   #high,
            |< 14|:   #normal
            ------------------
        ;

    ejection_fraction: Quantity
        currency = 60 days
        ranges["%"] =
            -------------------
            | 40|:   #normal,
            |< 40|:   #low
            -------------------
        ;

rules -- Conditions

    er_negative:
        Result := estrogen_receptor = #negative

    er_positive:
        Result := estrogen_receptor = #positive

    pr_negative:
        Result := progesterone_receptor = #negative

    pr_positive:
        Result := progesterone_receptor = #positive

    her2_negative:
        Result := her2_expression = #negative

    her2_positive:
        Result := her2_expression = #positive

    has_non_class_I_heart_failure:
        Result := has_heart_failure_class_II
                  or has_heart_failure_class_III
                  or has_heart_failure_class_IV

    anthracyclines_contraindicated:
        Result := has_transmural_MI
            or ejection_fraction.in_range (#low)
            or has_non_class_I_heart_failure

    taxanes_contraindicated:
        Result := is_type1_diabetic
            or has_allergy_to_taxanes
            or has_intolerance (#taxanes)

rules -- Main

    molecular_subtype: Terminology_term
        Result :=
            choice of
                =========================================================
                er_positive and
                her2_negative and
                not ki67.in_range (#high):    #luminal_A,
                ---------------------------------------------------------
                er_positive and
                her2_negative and
                ki67.in_range (#high):        #luminal_B_HER2_negative,
                ---------------------------------------------------------
                er_positive and
                her2_positive:                 #luminal_B_HER2_positive,
                ---------------------------------------------------------
                er_negative and
                pr_negative and
                her2_positive and
                ki67.in_range (#high):        #HER2,
                ---------------------------------------------------------
                er_negative and
                pr_negative and
                her2_negative and
                ki67.in_range (#high):        #triple_negative,
                ---------------------------------------------------------
                *:                             #none;
                =========================================================
            ;

rules -- Output

    chemotherapy_regime: Terminology_term
        Result :=
            choice of
                ================================================================================
                not metastatic:
                    choice of
                        ========================================================================
                        molecular_subtype in
                            {#luminal_B_HER2_negative,
                             #triple_negative} and
                        (tnm_t > '1a' or tnm_n > '0'):                   #taxanes,
                        ------------------------------------------------------------------------
                        molecular_subtype = #luminal_A and
                        (tnm_t  '3' or tnm_n  '2' or tnm_g  '3'):  #anthracyclines,
                        ------------------------------------------------------------------------
                        molecular_subtype = #luminal_B_HER2_positive and
                        (tnm_t = '1b' or tnm_t = '1c' and tnm_n = '0') or
                        molecular_subtype = #HER2_positive and
                        (tnm_t = '1b' and tnm_n = '0'):                  #paditaxel_trastuzumab
                        ========================================================================
                    ;,
                --------------------------------------------------------------------------------
                *:
                    choice of
                        =====================
                        yyy:        aaa,
                        ---------------------
                        xxx:        bbb,
                        ---------------------
                        *:          ccc
                        =====================
                    ;
                =================================================================================
            ;

definitions -- Terminology

    terminology = {
        term_definitions: {
            "en" : {
                "luminal_A" : {
                    text: "luminal A"
                },
                "luminal_B_HER2_positive" : {
                    text: "luminal B HER2-positive"
                },
                "luminal_B_HER2_negative" : {
                    text: "luminal B HER2-negative"
                },
                "HER2_positive" : {
                    text: "HER2-positive"
                },
                "HER2_negative" : {
                    text: "HER2-negative"
                },
                "triple_negative" : {
                    text: "triple-negative"
                },
                "negative" : {
                    text: "negative presence of gene"
                },
                "positive" : {
                    text: "positive presence of gene"
                }
            }
        },
        value_sets = {
            "pos_neg" : {
                id: "pos_neg",
                members: ["positive", "negative"]
            }
        }
    }
    ;

8. Covid19 Severity Classification

8.1. Work Plan

The following work plan is a rendition of the ACEP Covid19 severity guideline multi-step structure.

ACEP covid19 severity
Figure 6. ACEP Covid19 Work Plan

8.2. Decision Logic Module

dlm ACEP_COVID19_severity_classification.v0.5.0

definitions -- Descriptive

    language = {
            original_language: [ISO_639-1::en]
        }
        ;

    description = {
            lifecycle_state: "unmanaged",
            original_author: {
                name:           "Thomas Beale",
                email:          "thomas.beale@openEHR.org",
                organisation :  "openEHR Foundation <http://www.openEHR.org>",
                date:           2020-12-02
            },
            details = {
                "en" : {
                    language: [ISO_639-1::en],
                    purpose:  "This tool was developed by ACEP and EvidenceCare to assist
                                in determining the appropriate evaluation and disposition
                                for adult patients with suspected or confirmed COVID-19.",
                }
            },
            copyright: "© 2020 openEHR Foundation",
            licence: "Creative Commons CC-BY <https://creativecommons.org/licenses/by/3.0/>",
            ip_acknowledgements = {
                "ACEP_EvidenceCare" : {"This content developed from original publication of
                    © 2020 American College of Emergency Physicians (ACEP), EvidenceCare,
                    see https://www.acep.org/globalassets/sites/acep/media/covid-19-main/acep_evidencecare_covid19severitytool.pdf"},
            }
        }
        ;

use
    BASIC: Basic_patient_data.v0.5.0
    BMI: Body_mass_index.v0.5.0

input -- Administrative State

    is_LT_care_resident: Boolean
        ;

input -- Historical State

    |
    | Extract from master problem list or ask patient
    |
    has_cardiovascular_disease: Boolean
        ;

    |
    | Extract from master problem list or ask patient
    |
    has cerebrovascular_disease: Boolean
        ;

    |
    | Extract from master problem list or ask patient
    |
    has_COPD: Boolean
        ;

    |
    | Extract from master problem list or ask patient
    |
    is_type_2_diabetic: Boolean
        ;

    |
    | Extract from master problem list or ask patient
    |
    has_hypertension: Boolean
        ;

    |
    | True if any cancer diagnosis on master problem list
    | or ask patient
    |
    has_malignancy: Boolean
        ;

input -- Tracked State

    heart_rate: Count
        currency = 1 min,
        ranges["/min"] =
            ------------------------------
            |99|:       #mild_low_risk,
            |100..120|:  #mild_at_risk,
            |121|:      #moderate_risk
            ------------------------------
        ;

    systolic_BP: Quantity
        currency = 10 min,
        ranges["mm#Hg"] =
            ------------------------
            |<90|:  #critical_risk,
            |90|:  #normal_risk
            ------------------------
        ;

    |
    | Minimum documented within last 8 hrs
    |
    lowest_SpO2: Quantity
        currency = 8 hr,
        ranges["%"] =
            ----------------------------
            |93|:      #mild_low_risk,
            |89..92|:   #moderate_risk,
            |88|:      #severe_risk
            ----------------------------
        ;

    respiratory_rate: Quantity
        currency = 2 min
        ranges["/min"] =
            -----------------------------
            | 22|:      #mild_low_risk,
            |23 .. 28|:  #moderate_risk,
            | 29|:      #severe_risk
            -----------------------------
        ;

    O2_flow_rate: Quantity
        currency = 2 min,
        ranges["L/min"] =
            --------------------------
            |0|:      #mild_low_risk,
            |1..2|:   #mild_at_risk,
            |3..4|:   #moderate_risk,
            |5|:     #severe_risk
            --------------------------
        ;

    |
    | Reference SpO2 for exertional test: a 1-minute sit-to-stand
    | test can be performed within the patients room.
    | With this, they sit and stand as many as they can over the
    | course of 1 minute.
    | * A 3% drop in pulse oximeter reading is considered a positive test
    |
    SpO2_exertion_reference: Quantity
        currency = 5 min
        ;

    |
    | Post exertion SpO2
    |
    SpO2_exertion_post: Quantity
        currency = 5 min
        ;

    has_altered_LOC: Boolean
        currency = 5 min
        ;

    has_hemoptysis: Boolean
        currency = 5 min
        ;

    has_persistent_dyspnea: Boolean
        currency = 5 min
        ;

rules -- Main

    heart_rate_score: Integer
        Result := case heart_rate in
            =====================
            *:                0
            =====================
        ;

    systolic_BP_score: Integer
        Result := case systolic_BP in
            =====================
            *:                0
            =====================
        ;

    SpO2_score: Integer
        Result := case lowest_SpO2 in
            =====================
            #mild_low_risk:  0,
            ---------------------
            #moderate_risk:  2,
            ---------------------
            #severe_risk:    5,
            ---------------------
            *:                0
            =====================
        ;

    respiratory_rate_score: Integer
        Result := case respiratory_rate in
            =====================
            #mild_low_risk:  0,
            ---------------------
            #mild_at_risk:   1,
            ---------------------
            #moderate_risk:  2,
            ---------------------
            *:                0
            =====================
        ;

    O2_flow_rate_score: Integer
        Result := case O2_flow_rate in
            =====================
            #mild_low_risk,
            #mild_at_risk:   0,
            ---------------------
            #moderate_risk:  4,
            ---------------------
            #severe_risk:    5,
            ---------------------
            *:                0
            =====================
        ;

    |
    | Compute the qCSI score from vital signs sub-scores
    |
    qCSI_score: Integer
        Result := heart_rate_score +
                systolic_BP_score +
                SpO2_score +
                respiratory_rate_score +
                O2_flow_rate_score
        ;

    |
    | ACEP step 2 assessment
    |
    qCSI_risk: Terminology_code
        Result := case qCSI_score in
            ============================
            0:          #mild_low_risk,
            ----------------------------
            |1..2|:     #mild_at_risk,
            ----------------------------
            |3..5|:     #moderate_risk,
            ----------------------------
            |6..8|:     #severe_risk,
            ----------------------------
            | 9|:     #critical_risk
            ============================
        ;

    |
    | Count demographic related risk factors
    |
    risk_factors_demographic_count: Integer
        Result.add (
            ------------------------------------
            BASIC.sex = #male          ? 1 : 0,
            BASIC.age > 60              ? 1 : 0,
            BASIC.race = #black_race   ? 1 : 0
            ------------------------------------
        );

    |
    | Count medical / history related risk factors
    |
    risk_factors_medical_count: Integer
        Result.add (
            --------------------------------------
            has_cardiovascular_disease    ? 1 : 0,
            has cerebrovascular_disease   ? 1 : 0,
            has_COPD                      ? 1 : 0,
            is_type_2_diabetic            ? 1 : 0,
            has_hypertension              ? 1 : 0,
            has_malignancy                ? 1 : 0,
            BMI.bmi > 30                  ? 1 : 0,
            has_renal_disease             ? 1 : 0
            --------------------------------------
        );

    |
    | Total pre-existing risk factors count
    |
    risk_factors_count: Integer
        Result := risk_factors_demographic_count +
                  risk_factors_medical_count
        ;

    |
    | ACEP step 3 assessment
    | NB: must be assessed in highest -> lowest order
    |
    symptoms_related_risk: Terminology_code
        Result := choice of
            ====================================================
            has_altered_LOC:                    #critical_risk,
            ----------------------------------------------------
            has_hemoptysis:                     #severe_risk,
            ----------------------------------------------------
            has_persistent_dyspnea or
            is_LT_care_resident:                #moderate_risk,
            ----------------------------------------------------
            risk_factors_count  {| 2|}:     #mild_at_risk,
            ----------------------------------------------------
            risk_factors_count  {|0..1|}:     #mild_low_risk
            ====================================================
        ;

    |
    | Discharge home rule based on various criteria
    |
    can_discharge: Boolean
        Result :=
            qCSI_risk = #mild_low_risk and
            symptoms_related_risk = #mild_low_risk and
            exertional_SpO2_drop = #normal and
            TO BE COMPLETED
        ;

    |
    | Generate a % drop in SpO2 over 1 min sit/stand exertion test;
    | NB: A fall in SpO2 generates a +ve result value.
    |
    exertional_SpO2_drop: Quantity
        Result := (SpO2_exertion_reference - SpO2_exertion_post)/SpO2_exertion_reference * 100
        ;

    exertional_SpO2_result: Terminology_code
        Result := case exertional_SpO2_drop in
            ========================
            |< 3%|:   #normal,
            ------------------------
            | 3%|:  #mild_at_risk
            ========================
        ;

definitions -- Terminology

    terminology = {
        term_definitions: {
            "en" : {
                "qCSI_score" : {
                    text: "..."
                },
                "qCSI_risk" : {
                    text: "..."
                },
                "risk_factors_demographic_count" : {
                    text: "..."
                },
                "risk_factors_medical_count" : {
                    text: "..."
                },
                "risk_factors_count" : {
                    text: "..."
                },
                "symptoms_related_risk" : {
                    text: "..."
                },
                "exertional_SpO2_drop" : {
                    text: "..."
                },
                "exertional_SpO2_result" : {
                    text: "..."
                }
            }
        }
    }
    ;

9. CHA2DS2-VASc

9.1. Work Plan

9.2. Decision Logic Module

This DLM is a direct translation of the Cambio CHA2DS2-VASc.v1 GDL2 guideline.

dlm CHA2DS2_VASc.v0.5.0

definitions -- Descriptive

    language = {
            original_language: [ISO_639-1::en]
        }
        ;

    description = {
            lifecycle_state: "unmanaged",
            original_author: {
                name:           "Thomas Beale",
                email:          "models@cambiocds.com",
                organisation:   "Cambio Healthcare Systems <https://www.cambiogroup.com>",
                date:           "2016-12-16"
            },
            details: {
                "en" : {
                    language: [ISO_639-1::en],
                    purpose: "To record an individual's CHA2DS2-VASc score parameters and total score.",
                    use:     "Use for stroke risk stratification in patients with atrial fibrillation.
                             CHA2DS2-VASc is an acronym, with each factor contributing points to the
                                total score:
                                - Congestive heart failure 1p
                                - Hypertension 1p
                                - Age ≥75 years 2p
                                - Diabetes1p
                                - Stroke 2p
                                - Vascular disease 1p
                                - Age 65–74 years 1p
                                - Sex category 1p for female"
                }
            },
            copyright:  "© 2021 openEHR Foundation",
            licence:    "Creative Commons CC-BY <https://creativecommons.org/licenses/by/3.0/>",
            ip_acknowledgements: {
                "ClinRisk" : "This content developed from original publication of
                    © 2017 ClinRisk Ltd., see https://qrisk.org",
                "QRISK" : "QRISK® is a registered trademark of the University of Nottingham and EMIS"
            },
            references: [
                "Lip GY, Nieuwlaat R, Pisters R, Lane DA, Crijns HJ. Refining clinical risk
                    stratification for predicting stroke and thromboembolism in atrial
                    fibrillation using a novel risk factor-based approach: the euro heart survey
                    on atrial fibrillation. Chest. 2010 Feb;137(2):263-72.",

                "Camm a J, Kirchhof P, Lip GYH, Schotten U, Savelieva I, Ernst S, et al.
                    Guidelines for the management of atrial fibrillation: the Task Force for
                    the Management of Atrial Fibrillation of the European Society of Cardiology
                    (ESC). Eur Heart J. 2010 Oct;31(19):2369–429.",

                "Lip GY, Frison L, Halperin JL, Lane DA. Identifying patients at high risk
                    for stroke despite anticoagulation: a comparison of contemporary stroke risk
                    stratification schemes in an anticoagulated atrial fibrillation cohort.
                    Stroke. 2010 Dec;41(12):2731-8.",

                "Friberg L, Rosenqvist M, Lip GY. Evaluation of risk stratification schemes
                    for ischaemic stroke and bleeding in 182 678 patients with atrial
                    fibrillation: the Swedish Atrial Fibrillation cohort study.
                    Eur Heart J. 2012 Jun;33(12):1500-10."
            ]
        }
        ;

use
    BASIC: Basic_patient_data

input -- Historical state

    has_congestive_heart_failure: Boolean
        ;

    has_hypertension: Boolean
        ;

    |
    | Has recently had or currently has a stroke, TIA or thromboembolism
    |
    has_stroke_TIA_thromboembolism: Boolean
        ;

    has_diabetes: Boolean
        ;

    has_vascular_disease: Boolean
        ;

rules -- Main

    |
    | Convert sex to binary gender;
    | treat indeterminate sex as female
    |
    gender: Terminology_code «sexes»,
        Result := case BASIC.sex in
            =====================
            #male:     #male,
            ---------------------
            *:          #female
            =====================
        ;

    age_score: Integer
        Result := case BASIC.age_in_years in
            ================
            |<65|:       0,
            ----------------
            |65..74|:    1,
            ----------------
            |75|:       2
            ================
        ;

    CHA2DS2_VASc_score: Integer
        Result.add (
            ---------------------------------------------
            BASIC.gender = #male                ? 1 : 0,
            age_score,
            has_congestive_heart_failure         ? 1 : 0,
            has_hypertension                     ? 1 : 0,
            has_stroke_TIA_thromboembolism       ? 2 : 0,
            has_vascular_disease                 ? 1 : 0,
            has_diabetes                         ? 1 : 0
            ---------------------------------------------
        )
        ;

rules -- Output

    |
    | The maximum score is 9 and the result is interpreted as;
    | 0 - low risk
    | 1 - intermediate risk
    | 2 or more - high risk
    |
    risk_assessment: Terminology_code «risks»
        Result := case CHA2DS2_VASc_score in
            =============================
            0:       #low_risk,
            1:       #intermediate_risk,
            |2|:   #high_risk
            =============================
        ;

    |
    | Further interpretation in accordance with #4
    |
    annual_stroke_risk: Real
        Result := case CHA2DS2_VASc_score in
            ==============
            0:       0.0%,
            1:       0.6%,
            2:       2.2%,
            3:       3.2%,
            4:       4.8%,
            5:       7.2%,
            6:       9.7%,
            7:      11.2%,
            8:      10.8%,
            9:      12.2%
            ==============
        ;

    |
    | Further interpretation in accordance with #4
    |
    annual_stroke_TIA_thromboembolism_risk: Real
        Result := case CHA2DS2_VASc_score in
            ==============
            0:       0.0%,
            1:       0.9%,
            2:       2.9%,
            3:       4.6%,
            4:       6.7%,
            5:      10.0%,
            6:      13.6%,
            7:      15.7%,
            8:      15.2%,
            9:      17.4%
            ==============
        ;

definitions -- Terminology

    terminology = {
        term_definitions: {
            "en" : {
                "date_of_birth" : {
                    text: "Date of birth",
                    provenance: "GDL2" : ["gt0009"]
                },
                "age_in_years" : {
                    text: "Age (years)",
                    provenance: "GDL2" : ["gt0010"]
                },
                "age_category" : {
                    text: "Age category",
                    provenance: "GDL2" : ["gt0017"]
                },
                "gender" : {
                    text: "Gender",
                    provenance: "GDL2" : ["gt0009", "gt0016"]
                },
                "has_congestive_heart_failure" : {
                    text: "xxx",
                    provenance: "GDL2" : ["gt0011", "gt0018"]
                },
                "has_hypertension" : {
                    text: "xxx",
                    provenance: "GDL2" : ["gt0012", "gt0019"]
                },
                "has_diabetes" : {
                    text: "Diabetes",
                    provenance: "GDL2" : ["gt0015", "gt0022"]
                },
                "has_stroke_TIA_thromboembolism" : {
                    text: "Stroke/TIA/Thromboembolism",
                    provenance: "GDL2" : ["gt0013", "gt0020"]
                },
                "has_vascular_disease" : {
                    text: "Vascular disease",
                    provenance: "GDL2" : ["gt0014", "gt0021"]
                },
                "male" : {
                    text: "Male gender",
                    provenance: "GDL2" : ["gt0035"]
                },
                "female" : {
                    text: "Female gender",
                    provenance: "GDL2" : ["gt0025"]
                },
                "CHA2DS2_VASc_score" : {
                    text: "CHA2DS2VASc score",
                    provenance: "GDL2" : ["gt0011"]
                },
                "risk_assessment" : {
                    text: "Risk assessment",
                    provenance: "GDL2" : ["gt0005"]
                },
                "annual_stroke_risk" : {
                    text: "Annual stroke risk",
                    provenance: "GDL2" : ["gt0006"]
                },
                "annual_stroke_TIA_thromboembolism_risk" : {
                    text: "Annual risk of stroke/TIA/thromboembolism",
                    provenance: "GDL2" : ["gt0011"]
                },
                "low_risk" : {
                    text: "Low risk"
                },
                "intermediate_risk" : {
                    text: "Intermediate risk"
                },
                "high_risk" : {
                    text: "High risk"
                }
            }
        },
        value_sets: {
            "genders" : {
                id: "genders",
                members: ["male", "female"]
            },
            "risks" : {
                id: "risks",
                members: ["low_risk", "intermediate_risk", "high_risk"]
            }
        }
    }
    ;

9.3. Bindings

The following defines the logical bindings of DLM variables to back-end data.

--
-- Demographic items: AQL query
--
SELECT
    OBS/data#at0001/events#at0002/data#at0003/items#at0004 AS date_of_birth,
    OBS/data#at0001/events#at0002/data#at0003/items#at0008 AS sex
    C/context/start_time AS time
FROM
    EHR e[ehr_id/value=$ehrUid]
        CONTAINS COMPOSITION C
        CONTAINS OBSERVATION OBS[openEHR-EHR-OBSERVATION.basic_demographic.v1]
ORDER BY
    time DESC


--
-- CHA2DS2-VASc input items
--
SELECT
    OBS/data#at0002/events#at0003/data#at0001/items#at0026 AS has_congestive_heart_failure,
    OBS/data#at0002/events#at0003/data#at0001/items#at0029 AS has_hypertension,
    OBS/data#at0002/events#at0003/data#at0001/items#at0039 AS has_stroke_TIA_thromboembolism,
    OBS/data#at0002/events#at0003/data#at0001/items#at0046 AS has_vascular_disease,
    OBS/data#at0002/events#at0003/data#at0001/items#at0032 AS has_diabetes,
    C/context/start_time AS time
FROM
    EHR e[ehr_id/value=$ehrUid]
        CONTAINS COMPOSITION C
        CONTAINS OBSERVATION OBS[openEHR-EHR-OBSERVATION.chadsvasc_score.v1]
ORDER BY
    time DESC

10. qRisk3-2017

This stroke/heart attack risk calculator was developed in the UK by University of Nottingham and EMIS (a major GP EMR supplier). An online calculator is visible here. The algorithm is published as a PHP program. See also this article.

What we can show here is how to represent the algorithm in a way that clinicians can directly understand, and indeed, could develop and maintain, given appropriate tools.

10.1. Decision Logic Module

This DLM is a fairly literal rendering of the algorithm at the above link, with a cleaner representation of the scale factors, and a bit of vector math.

dlm qRisk3_2017.v0.5.0

definitions -- Descriptive

    language = {
            original_language: [ISO_639-1::en]
        }
        ;

    description = {
            lifecycle_state: "unmanaged",
            original_author: {
                name:           "Thomas Beale",
                email:          "thomas.beale@openEHR.org",
                organisation:   "openEHR International <http://www.openEHR.org>",
                date:           "2021-01-10"
            },
            details: {
                "en" : {
                    language: [ISO_639-1::en],
                    purpose: "To record an individual's QRISK3 score."
                }
            },
            copyright:  "© 2021 openEHR Foundation",
            licence:    "Creative Commons CC-BY <https://creativecommons.org/licenses/by/3.0/>",
            ip_acknowledgements: {
                "ClinRisk" : "This content developed from original publication of
                    © 2017 ClinRisk Ltd., see https://qrisk.org",
                "QRISK" : "QRISK® is a registered trademark of the University of Nottingham and EMIS"
            }
        }
        ;

use
    BASIC: Basic_patient_data.v0.5.0
    BMI: Body_mass_index.v0.5.0

definitions -- Reference

    Ethnicity_risk_factors = {
            #female: {
                #white_or_not_stated:  0.280403143329954250,
                #indian:               0.562989941420753980,
                #pakistani:            0.295900008511165160,
                #bangladeshi:          0.072785379877982545,
                #other_asian:         -0.170721355088573170,
                #black_caribbean:     -0.393710433148749710,
                #black_african:       -0.326324952835302720,
                #other_ethnic_group:  -0.171270568832417840
            },
            #male: {
                #white_or_not_stated:  0.277192487603082790,
                #indian:               0.474463607149312680,
                #pakistani:            0.529617299196893710,
                #bangladeshi:          0.035100159186299017,
                #other_asian:         -0.358078996693279190,
                #black_caribbean:     -0.400564852321651400,
                #black_african:       -0.415227928898301730,
                #other_ethnic_group:  -0.263213481347499670
            },
        }
        ;

    Smoking_risk_factors = {
            #female: {
                #non_smoker:           0,
                #ex_smoker:            0.133868337865462620,
                #light_smoker:         0.562008580124385370,
                #moderate_smoker:      0.667495933775025470,
                #heavy_smoker:         0.849481776448308470
            },
            #male: {
                #non_smoker:           0,
                #ex_smoker:            0.191282228633889830,
                #light_smoker:         0.552415881926455520,
                #moderate_smoker:      0.638350530275060720,
                #heavy_smoker:         0.789838198818580190
            }
        }
        ;

    Age_1_stats = {
            #female: {
                #centre:   0.053274843841791,
                #scale:   -8.138810924772618800
            },
            #male: {
                #centre:   0.053274843841791,
                #scale:   -17.839781666005575000
            }
        }
        ;

    Age_2_stats = {
            #female: {
                #centre:   4.332503318786621,
                #scale:    0.797333766896990980
            },
            #male: {
                #centre:   77.284080505371094,
                #scale:    0.0022964880605765492
            }
        }
        ;

    BMI_1_stats = {
            #female: {
                #centre:   0.154946178197861,
                #scale:    0.292360922754600520
            },
            #male: {
                #centre:   0.149176135659218,
                #scale:    2.456277666053635800
            }
        }
        ;

    BMI_2_stats = {
            #female: {
                #centre:   0.144462317228317,
                #scale:   -4.151330021383766500
            },
            #male: {
                #centre:   0.141913309693336,
                #scale:   -8.301112231471135400
            }
        }
        ;

    Rheumatoid_arthritis_stats = {
            #female: {
                #centre:   3.476326465606690,
                #scale:    0.153380358208025540
            },
            #male: {
                #centre:   4.300998687744141,
                #scale:    0.173401968563271110
            }
        }
        ;

    Systolic_BP_stats = {
            #female: {
                #centre:   123.130012512207030,
                #scale:    0.0131314884071034240
            },
            #male: {
                #centre:   128.571578979492190,
                #scale:    0.0129101265425533050
            }
        }
        ;

    Systolic_BP_std_dev_stats = {
            #female: {
                #centre:   9.002537727355957,
                #scale:    0.0078894541014586095
            },
            #male: {
                #centre:   8.756621360778809,
                #scale:    0.0129101265425533050
            }
        }
        ;

    Townsend_stats = {
            #female: {
                #centre:   0.392308831214905,
                #scale:    0.0772237905885901080
            },
            #male: {
                #centre:   0.526304900646210,
                #scale:    0.0332682012772872950
            }
        }
        ;

    Risk_factor_scales = {
            #female: {
                #has_atrial_fibrillation:              1.59233549692696630,
                #atypical_antipsychotic_medication:    0.252376420701155570,
                #on_corticosteroids:                   0.595207253046018510,
                #has_impotence:                        0,
                #has_migraines:                        0.3012672608703450,
                #has_rheumatoid_arthritis:             0.213648034351819420,
                #has_chronic_kidney_disease:           0.651945694938458330,
                #has_severe_mental_illness:            0.125553080588201780,
                #has_systemic_lupus:                   0.758809386542676930,
                #on_hypertension_treatment:            0.509315936834230040,
                #has_family_history_CV_disease:        0.454453190208962130
            },
            #male: {
                #has_atrial_fibrillation:              0.882092369280546570,
                #atypical_antipsychotic_medication:    0.130468798551735130,
                #on_corticosteroids:                   0.454853997504455430,
                #has_impotence:                        0.222518590867053830,
                #has_migraines:                        0.255841780741599130,
                #has_rheumatoid_arthritis:             0.209706580139565670,
                #has_chronic_kidney_disease:           0.718532612882743840,
                #has_severe_mental_illness:            0.121330398820471640,
                #has_systemic_lupus:                   0.440157217445752200,
                #on_hypertension_treatment:            0.516598710826954740,
                #has_family_history_CV_disease:        0.540554690093901560
            }
        }
        ;

    Diabetes_scales:
            #female: {
                #no_diabetes:      0,
                #type1_diabetes:   1.72679775105373470,
                #type2_diabetes:   1.06887732446154680
            }
            #male: {
                #no_diabetes:      0,
                #type1_diabetes:   1.234342552167517500
                #type2_diabetes:   0.859420714309322210
        }
        ;

    Interaction_scales = {
            #female: {
                 #age_1:   {
                    #has_atrial_fibrillation:     19.9380348895465610,
                    #on_corticosteroids:          -0.9840804523593628100000000,
                    #has_impotence:                0,
                    #has_migraines:                1.7634979587872999000000000,
                    #has_chronic_kidney_disease:  -3.5874047731694114000000000,
                    #has_systemic_lupus:          19.6903037386382920000000000,
                    #on_hypertension_treatment:   11.8728097339218120000000000,
                    #bmi_1:                       23.8026234121417420000000000,
                    #bmi_2:                      -71.1849476920870070000000000,
                    #family_history_CV_disease:    0.9946780794043512700000000,
                    #systolic_BP:                  0.0341318423386154850000000,
                    #townsend:                    -1.0301180802035639000000000
                },
                #age_2:   {
                    #has_atrial_fibrillation:     -0.0761826510111625050000000,
                    #on_corticosteroids:          -0.1200536494674247200000000,
                    #has_impotence:                0,
                    #has_migraines:               -0.0655869178986998590000000,
                    #has_chronic_kidney_disease:  -0.2268887308644250700000000,
                    #has_systemic_lupus:           0.0773479496790162730000000,
                    #on_hypertension_treatment:    0.0009685782358817443600000,
                    #bmi_1:                        0.5236995893366442900000000,
                    #bmi_2:                        0.0457441901223237590000000,
                    #family_history_CV_disease:   -0.0768850516984230380000000,
                    #systolic_BP:                 -0.0015082501423272358000000,
                    #townsend:                    -0.0315934146749623290000000
                }
            },
            #male: {
                 #age_1:   {
                    #has_atrial_fibrillation:      3.4896675530623207000000000,
                    #on_corticosteroids:           1.1708133653489108000000000,
                    #has_impotence:               -1.5064009857454310000000000,
                    #has_migraines:                2.3491159871402441000000000,
                    #has_chronic_kidney_disease:  -0.5065671632722369400000000,
                    #on_hypertension_treatment:    6.5114581098532671000000000,
                    #bmi_1:                       31.0049529560338860000000000,
                    #bmi_2:                     -111.2915718439164300000000000,
                    #family_history_CV_disease:    2.7808628508531887000000000,
                    #systolic_BP:                  0.0188585244698658530000000,
                    #townsend:                    -0.1007554870063731000000000
                },
                #age_2:   {
                    #has_atrial_fibrillation:     -0.0003499560834063604900000,
                    #on_corticosteroids:          -0.0002496045095297166000000,
                    #has_impotence:               -0.0011058218441227373000000,
                    #has_migraines:                0.0001989644604147863100000,
                    #has_chronic_kidney_disease:  -0.0018325930166498813000000,
                    #on_hypertension_treatment:    0.0006383805310416501300000,
                    #bmi_1:                        0.0050380102356322029000000,
                    #bmi_2:                       -0.0130744830025243190000000,
                    #family_history_CV_disease:   -0.0002479180990739603700000,
                    #systolic_BP:                 -0.0000127187419158845700000,
                    #townsend:                    -0.0000932996423232728880000
                }
            }
        }
        ;

    Snoking_interaction_scales = {
            #female: {
                 #age_1:   {
                    #non_smoker:                   0,
                    #ex_smoker:                   -4.70571617858518910,
                    #light_smoker:                -2.74303834035733370,
                    #moderate_smoker:             -0.866080888293921820,
                    #heavy_smoker:                 0.902415623697106480
                },
                #age_2:   {
                    #non_smoker:                   0,
                    #ex_smoker:                   -0.0755892446431930260000000,
                    #light_smoker:                -0.1195119287486707400000000,
                    #moderate_smoker:             -0.1036630639757192300000000,
                    #heavy_smoker:                -0.1399185359171838900000000
                }
            },
            #male: {
                 #age_1:   {
                    #non_smoker:                   0,
                    #ex_smoker:                   -0.2101113393351634600000000,
                    #light_smoker:                 0.7526867644750319100000000,
                    #moderate_smoker:              0.9931588755640579100000000,
                    #heavy_smoker:                 2.1331163414389076000000000
                },
                #age_2:   {
                    #non_smoker:                   0,
                    #ex_smoker:                   -0.0004985487027532612100000,
                    #light_smoker:                -0.0007987563331738541400000,
                    #moderate_smoker:             -0.0008370618426625129600000,
                    #heavy_smoker:                -0.0007840031915563728900000
                }
            }
        }
        ;

    Diabetes_interaction_scales = {
            #female: {
                 #age_1:   {
                    #no_diabetes:                  0,
                    #type1_diabetes:              -1.2444332714320747000000000,
                    #type2_diabetes:               6.8652342000009599000000000
                },
                #age_2:   {
                    #no_diabetes:                  0,
                    #type1_diabetes:              -0.2872406462448894900000000,
                    #type2_diabetes:              -0.0971122525906954890000000
                }
            },
            #male: {
                 #age_1:   {
                    #no_diabetes:                  0,
                    #type1_diabetes:               5.3379864878006531000000000,
                    #type2_diabetes:               3.6461817406221311000000000
                },
                #age_2:   {
                    #no_diabetes:                  0,
                    #type1_diabetes:               0.0006409780808752897000000,
                    #type2_diabetes:              -0.0002469569558886831500000
                }
            }
        }
        ;

input -- Administrative

    |
    | Ethnicity for qRisk3:
    |   #white_or_not_stated
    |   #indian
    |   #pakistani
    |   #bangladeshi
    |   #other_asian
    |   #black_caribbean
    |   #black_african
    |   #other_ethnic_group
    |
    qRisk3_ethnicity: Terminology_code «qrisk_ethnicities»,
        ;

    townsend: Real
        ;

input -- Historical state

    |
    | Smoking status:
    |   #non_smoker
    |   #ex_smoker
    |   #light_smoker
    |   #moderate_smoker
    |   #heavy_smoker
    |
    smoking_status: Terminology_code «smoking_status»,
        ;

    |
    | Diabetes:
    |   #no_diabetes
    |   #type1_diabetes
    |   #type2_diabetes
    |
    diabetes_status: Terminology_code «diabetes_status»,
        ;

    |
    | Angina or heart attack in a 1st degree relative < 60
    |
    family_history_CV_disease: Boolean
        ;

    |
    | Chronic kidney disease (stage 3, 4 or 5)
    |
    has_chronic_kidney_disease: Boolean
        ;

    has_atrial_fibrillation: Boolean
        ;

    on_hypertension_treatment: Boolean
        ;

    has_migraines: Boolean
        ;

    has_rheumatoid_arthritis: Boolean
        ;

    |
    | Has or being treated for erectile dysfunction
    | (female -> False)
    |
    has_impotence: Boolean

    |
    | Has Systemic lupus erythematosus (SLE)
    |
    has_systemic_lupus: Boolean
        ;

    |
    | Severe mental illness (this includes schizophrenia,
    | bipolar disorder and moderate/severe depression)
    |
    has_severe_mental_illness: Boolean
        ;

    on_atypical_antipsychotic_medication: Boolean
        ;

    on_corticosteroids: Boolean
        ;

input -- Tracking state

    total_cholesterol_HDL_ratio: Real
        ;

    |
    | Systolic BP in #mmHg, at least 2, max 10 samples
    |
    systolic_BP_history: Array<Real>[2..10]
        ;

rules -- Main

    systolic_BP_std_deviation: Real
        Result := {Statistical_evaluator}.std_dev (systolic_BP_history)
        ;

    |
    | Applying the fractional polynomial transforms
    | (which includes scaling)
    |

    age_1_centred: Real
        Result := (BASIC.age_in_years/10) ^ 0.5  - Age_1_stats[BASIC.sex]#centre
        ;

    age_1_score: Real
        Result := age_1_centred * Age_1_stats[BASIC.sex]#scale
        ;

    age_2_centred: Real
        Result := BASIC.age_in_years/10 - Age_2_stats[BASIC.sex]#centre
        ;

    age_2_score: Real
        Result := age_2_centred * Age_2_stats[BASIC.sex]#scale
        ;

    BMI_scaled: Real
        Result := BMI.BMI/10
        ;

    BMI_1_centred: Real
        Result := BMI_scaled ^ 0.5 - BMI_1_stats[BASIC.sex]#centre
        ;

    BMI_1_score: Real
        Result := BMI_1_centred * BMI_1_stats[BASIC.sex]#scale
        ;

    BMI_2_centred: Real
        Result := BMI_scaled ^ 0.5 * {math}.ln (BMI_scaled) - BMI_2_stats[BASIC.sex]#centre
        ;

    BMI_2_score: Real
        Result := BMI_2_centred * BMI_2_stats[BASIC.sex]#scale
        ;

    rheumatoid_arthritis_score: Real
        Result := (has_rheumatoid_arthritis.as_integer - Rheumatoid_arthritis_stats[BASIC.sex]#centre)
                    * Rheumatoid_arthritis_stats[BASIC.sex]#scale
        ;

    systolic_BP: Real
        Result := systolic_BP_history.last
        ;

    systolic_BP_score: Real
        Result := (systolic_BP - Systolic_BP_stats[BASIC.sex]#centre)
                    * Systolic_BP_stats[BASIC.sex]#scale
        ;

    systolic_BP_std_dev_score: Real
        Result := (systolic_BP_std_deviation - Systolic_BP_std_dev_stats[BASIC.sex]#centre)
                    * Systolic_BP_std_dev_stats[BASIC.sex]#scale
        ;

    townsend_score: Real
        Result := (townsend_score - Townsend_stats[BASIC.sex]#centre)
                    * Townsend_stats[BASIC.sex]#scale
        ;

    |
    | TODO: Unclear what this is from published algorithm
    |
    survivor_factor: Real
        ;

    |
    | Compute quantitative & classified part of score
    |
    raw_score_1: Real
        Result := add (
            Ethnicity_risk_factors[BASIC.sex, qRisk3_ethnicity],
            Smoking_risk_factors[BASIC.sex, smoking_status],
            age_1_score,
            age_2_score,
            BMI_1_score,
            BMI_2_score,
            rheumatoid_arthritis_score,
            systolic_BP_score,
            systolic_BP_std_dev_score,
            townsend_score_score,
            Diabetes_scales[BASIC.sex, diabetes_status]
        )
        ;

    |
    | Compute boolean part of score; use vector
    | in order to copmpute dot product with scales
    |
    boolean_risks: Vector<Real>,
        Result := [
            has_atrial_fibrillation.as_integer,
            on_atypical_antipsychotic_medication.as_integer,
            on_corticosteroids.as_integer,
            has_impotence.as_integer,
            has_migraines.as_integer,
            has_rheumatoid_arthritis.as_integer,
            has_chronic_kidney_disease.as_integer,
            has_severe_mental_illness.as_integer,
            has_systemic_lupus.as_integer,
            on_hypertension_treatment.as_integer,
            family_history_CV_disease.as_integer
        ]
        ;

    raw_score_2: Real
        Result := boolean_risks . Risk_factor_scales[BASIC.sex]
        ;

    |
    | Compute interaction part of score; use vector
    | in order to copmpute dot product with scales
    |
    interaction_risks: Vector<Real>,
        Result := [
            has_atrial_fibrillation.as_integer,
            on_corticosteroids.as_integer,
            has_impotence.as_integer,
            has_migraines.as_integer,
            has_chronic_kidney_disease.as_integer,
            has_systemic_lupus.as_integer,
            on_hypertension_treatment.as_integer,
            BMI_1_centred,
            BMI_2_centred,
            family_history_CV_disease.as_integer,
            systolic_BP,
            townsend
        ]
        ;

    raw_score_3: Real
        Result := add (
            age_1_centred * Smoking_interaction_scales[BASIC.sex, #age_1, smoking_status],
            age_1_centred * Diabetes_interaction_scales[BASIC.sex, #age_1, diabetes_status],

            age_1_centred * interaction_risks . Interaction_scales[BASIC.sex, #age_1],

            age_2_centred * Smoking_interaction_scales[BASIC.sex, #age_2, smoking_status],
            age_2_centred * Diabetes_interaction_scales[BASIC.sex, #age_2, diabetes_status],

            age_2_centred * interaction_risks . Interaction_scales[BASIC.sex, #age_2]
        )
        ;

    raw_score: Real
        Result = raw_score_1 + raw_score_2 + raw_score_3
        ;

rules -- Output

    qRisk3_score: Real
        Result := 100.0 * (1 - survivor_factor ^ exp (raw_score))
        ;

definitions -- Terminology

    terminology = {
        term_definitions: {
            "en" : {
                "qRisk_score" : {
                    text: "QRISK2 score"
                },
                "non_smoker" : {
                    text: "Non-smoker"
                },
                "no_diabetes" : {
                    text: "Non-diabetic"
                },
                "total_cholesterol_HDL_ratio" : {
                    text: "Total cholesterol : HDL ratio"
                },
                "TODO: rest of terminology" : {
                    text: "TODO: rest of terminology"
                }
            }
        }

        value_sets: {
            "diabetes_status" : {
                id: "diabetes_status",
                members: ["no_diabetes", "type1_diabetes", "type2_diabetes"]
            },
            "smoking status": {
                id: "status",
                members: ["non_smoker", "ex_smoker", "light_smoker",
                    "moderate_smoker", "heavy_smoker"]
            }
        }
    }
    ;

11. National Early Warning Score (NEWS) 2

This CPG was developed from the Royal College of Physicians (RCP) NEWS2 guideline (2017).

11.1. Work Plan

The work plan part of NEWS2 is mainly based on the clinical response part of the guideline, reproduced below.

NEWS2 clinical response
Figure 7. NEWS2 clinical response

TODO: Work Plan

11.2. Decision Logic Module

The decision logic part of NEWS2 is mainly based on the NEWS2 score and triggers parts of the guideline, reproduced below.

NEWS2 score
Figure 8. NEWS2 score
NEWS2 thresholds triggers
Figure 9. NEWS2 thresholds and triggers
dlm NEWS2.v0.5.0

definitions -- Descriptive

    language = {
            original_language: [ISO_639-1::en]
        }
        ;

    description = {
            lifecycle_state: "unmanaged",
            original_author: {
                name:           "Thomas Beale",
                email:          "thomas.beale@openEHR.org",
                organisation:   "openEHR Internaitonal <https://www.openEHR.org>",
                date:           "2021-03-01"
            },
            details: {
                "en" : {
                    language: [ISO_639-1::en],
                    purpose: "We recommend that the NEWS is used to improve the following:
                                  i the assessment of acute-illness severity
                                 ii the detection of clinical deterioration
                                iii the initiation of a timely and competent clinical response.",
                    use:     "NEWS2 should be used to standardise the assessment of acute-illness severity
                              when patients present acutely to hospital and in prehospital assessment,
                              ie by the ambulance services.
                              NEWS should also be used in emergency departments and as a surveillance system
                              for all patients in hospitals, to track their clinical condition, alert the
                              clinical team to any clinical deterioration and trigger a timely clinical
                              response.",
                    misuse:  "NEWS should not be used in children (ie aged <16 years) or in women who are
                             pregnant, because the physiological response to acute illness can be modified
                             in children and by pregnancy. The NEWS may be unreliable in patients with
                             spinal cord injury (especially tetraplegia or high-level paraplegia),
                             owing to functional disturbances of the autonomic nervous system.
                             Use with caution."
                }
            },
            copyright:  "© 2021 openEHR Foundation",
            licence:    "Creative Commons CC-BY <https://creativecommons.org/licenses/by/3.0/>",
            ip_acknowledgements: {
                "RCP" : "Reproduced from: Royal College of Physicians. National Early Warning Score (NEWS) 2:
                        Standardising the assessment of acute-illness severity in the NHS. Updated report of
                        a working party. London. © Royal College of Physicians 2017.
                        See https://www.rcplondon.ac.uk/projects/outputs/national-early-warning-score-news-2"
            },
            references: [
                "xxxx."
            ]
        }
        ;

use
    BASIC: Basic_patient_data

input -- Historic State

    |
    | True if subject has a normal target SpO2, e.g. not in hypercapnic
    | respiratory failure or similar condition
    |
    has_normal_target_oxygen_sat: Boolean

input -- Tracked State

    pulse: Count
        currency = 1 hr
        ;

    |
    | Systolic BP (mmHg)
    |
    systolic_BP: Real
        currency = 1 hr
        ;

    |
    | Oxygen saturation %
    |
    SpO2: Real
        currency = 1 hr
        ;

    respiratory_rate: Integer
        currency = 1 hr
        ;

    |
    | Core temperature in deg C
    |
    temperature: Real
        currency = 1 hr
        ;

    |
    | #air | #oxygen
    |
    gases: Terminology_code «gases»
        currency = 1 hr
        ;

    |
    | #alert: normally alert
    | #CVPU: new confusion
    |
    conscious_state: Terminology_code «conscious_state»
        currency = 1 hr
        ;

rules -- Main

    respiratory_rate_score: Integer
        Result := case respiratory_rate in
            ==============
            |8|:       3,
            --------------
            |9..11|:    1,
            --------------
            |12..20|:   0,
            --------------
            |21..24|:   2,
            --------------
            |25|:      3
            ==============
        ;

    |
    | Scale 1 is used with most patients, except those with a lowered target SpO2,
    | for whom the scale 2 form of scoring should be used.
    |
    SpO2_score_1: Integer
        Result := case SpO2 in
            ==============
            |91|:      3,
            --------------
            |92..93|:   2,
            --------------
            |94..95|:   1,
            --------------
            |96|:      0
            ==============
        ;

    |
    | Scale 2 is used only for patients with oxygen saturation (SpO2)
    | target range of 8892%, such as patients with hypercapnic
    | respiratory failure (e.g. due to COPD). This score is partly
    | conditional on which gases are being administered.
    |
    SpO2_score_2: Integer
        Result := choice of
            ============================================
            SpO2  92:  case SpO2 in
                ==============
                |83|:      3,
                --------------
                |84..85|:   2,
                --------------
                |86..87|:   1,
                --------------
                |88..92|:   0
                ==============
                ;,
            --------------------------------------------
            SpO2  93 and gases = #air:
                0,
            --------------------------------------------
            SpO2  93 and gases = #oxygen: case SpO2 in
                ==============
                |93..94|:   1,
                --------------
                |95..96|:   2,
                --------------
                |97|:      3
                ==============
                ;
            ============================================
        ;

    SpO2_score: Integer
        Result := has_normal_target_oxygen_sat ? SpO2_score_1 : SpO2_score_2
        ;

    gases_score: Integer
        Result := case gases in
            ==============
            #air:     0,
            --------------
            #oxygen:  2
            ==============
        ;

    systolic_BP_score: Integer
        Result := case systolic_BP in
            ================
            |90|:        3,
            ----------------
            |91..100|:    2,
            ----------------
            |101..110|:   1,
            ----------------
            |111..219|:   0,
            ----------------
            |220|:       3
            ================
        ;

    pulse_score: Integer
        Result := case pulse in
            ================
            |40|:        3,
            ----------------
            |41..50|:     1,
            ----------------
            |51..90|:     0,
            ----------------
            |91..110|:    1,
            ----------------
            |111..130|:   2,
            ----------------
            |131|:       3
            ================
        ;

    temperature_score: Integer
        Result := case temperature in
            =================
            |35.0|:       3,
            -----------------
            |35.1..36.0|:  1,
            -----------------
            |36.1..38.0|:  0,
            -----------------
            |38.1..39.0|:  1,
            -----------------
            |39.1|:       2
            =================
        ;

rules -- Output

    |
    | Generate NEWS2 score, taking into account variation in target O2 saturation,
    | for which two SpO2 scoring scales are used
    |
    NEWS2_score: Integer
        Result.add (
            ------------------
            respiratory_score,
            SpO2_score,
            gases_score,
            systolic_BP_score,
            pulse_score,
            temperature_score
            ------------------
        )
        ;

    |
    | Has a score of 3 in any individual parameter
    |
    has_red_score: Boolean
        Result :=
            respiratory_score = 3 or
            SpO2_score = 3 or
            gases_score = 3 or
            systolic_BP_score = 3 or
            pulse_score = 3 or
            temperature_score = 3
        ;

    |
    | Generate a clinical risk classification
    |
    clinical_risk: Terminology_code «NEWS2_clinical_risk»
        Result := choice of
            ========================================
            NEWS2_score in |0..4|:  #low,
            ----------------------------------------
            has_red_score:          #low_to_medium,
            ----------------------------------------
            NEWS2_score in |5..6|:  #medium,
            ----------------------------------------
            NEWS2_score 7:         #high
            ========================================
        ;

    |
    | Convert score to a clinical response band
    | NB: tese band names are not explicit in the published NEWS2
    |
    clinical_response_band: Terminology_code «NEWS2_clinical_response_band»
        Result := choice of
            =======================================
            NEWS2_score = 0:        #NEWS2_band_1,
            ---------------------------------------
            NEWS2_score in |1..4|:  #NEWS2_band_2,
            ---------------------------------------
            has_red_score:          #NEWS2_band_3,
            ---------------------------------------
            NEWS2_score in |5..6|:  #NEWS2_band_4,
            ---------------------------------------
            NEWS2_score in |7|:    #NEWS2_band_5
            =======================================
        ;

    |
    | Generate a monitoring classification
    |
    clinical_monitoring: Terminology_code «NEWS2_clinical_monitoring»
        Result := case clinical_response_band in
            ====================================================
            #NEWS2_band_1:  #minimum_12_hourly_monitoring,
            ----------------------------------------------------
            #NEWS2_band_2:  #minimum_4_to_6_hourly_monitoring,
            ----------------------------------------------------
            #NEWS2_band_3,
            #NEWS2_band_4:  #minimum_1_hourly_monitoring,
            ----------------------------------------------------
            #NEWS2_band_5:  #continuous_monitoring
            ====================================================
        ;

definitions -- Terminology

    terminology = {
        term_definitions: {
            "en" : {
                "pulse" : {
                    text: "Pulse"
                },
                "systolic_BP" : {
                    text: "systolic blood pressure in mmHg"
                },
                "SpO2" : {
                    text: "Oxygen saturation"
                },
                "respiratory_rate" : {
                    text: "Respiratory rate"
                },
                "temperature" : {
                    text: "Core temperature"
                },
                "gases" : {
                    text: "Gases being adminsitered to subject"
                },

                "pulse_score" : {
                    text: "Pulse component of NEWS2 score"
                },
                "systolic_BP_score" : {
                    text: "systolic blood pressure component of NEWS2 score"
                },
                "SpO2_score" : {
                    text: "Oxygen saturation component of NEWS2 score"
                },
                "respiratory_rate_score" : {
                    text: "Respiratory rate component of NEWS2 score"
                },
                "gases_score" : {
                    text: "Gases component of NEWS2 score"
                },
                "temperature_score" : {
                    text: "Temperature component of NEWS2 score"
                },

                "NEWS2_score" : {
                    text: "NEWS2 score"
                },

                "oxygen" : {
                    text: "subject on positive-pressure oxygen"
                },
                "air" : {
                    text: "subject on positive-pressure air"
                },
                "alert" : {
                    text: "Subject is alert"
                },
                "CVPU" : {
                    text: "New confusion (C) or no response to voice (V), pain (P) or is unresponsive (U)"
                },

                "low" : {
                    text: "low risk"
                },
                "low_to_medium" : {
                    text: "low_to_medium risk"
                },
                "medium" : {
                    text: "medium risk"
                },
                "high" : {
                    text: "high risk"
                },

                "minimum_12_hourly_monitoring" : {
                    text: "minimum 12 hourly monitoring"
                },
                "minimum_4_to_6_hourly_monitoring" : {
                    text: "minimum 4-6 hourly monitoring"
                },
                "minimum_1_hourly_monitoring" : {
                    text: "minimum 1 hourly monitoring"
                },
                "continuous_monitoring" : {
                    text: "continuous monitoring"
                }

            }
        },
        value_sets: {
            "conscious_state" : {
                id: "conscious_state",
                members: ["alert", "CVPU"]
            },
            "gases" : {
                id: "gases",
                members: ["air", "oxygen"]
            },
            "NEWS2_clinical_risk" : {
                id: "NEWS2_clinical_risk",
                members: ["low", "low_to_medium", "medium", "high"]
            },
            "NEWS2_clinical_monitoring": {
                id: "NEWS2_clinical_monitoring",
                members: ["minimum_12_hourly_monitoring", "minimum_4_to_6_hourly_monitoring",
                           "minimum_1_hourly_monitoring", "continuous_monitoring"]
            },
            "NEWS2_clinical_response_band": {
                id: "NEWS2_clinical_response_band",
                members: ["NEWS2_band_1", "NEWS2_band_2", "NEWS2_band_3", "NEWS2_band_4", "NEWS2_band_5"]
            }
        }
    }
    ;

11.3. Bindings

The following defines the logical bindings of DLM variables to back-end data.

--
-- Demographic items: AQL query
--
SELECT
    OBS/data#at0001/events#at0002/data#at0003/items#at0004 AS date_of_birth,
    OBS/data#at0001/events#at0002/data#at0003/items#at0008 AS sex
    C/context/start_time AS time
FROM
    EHR e[ehr_id/value=$ehrUid]
        CONTAINS COMPOSITION C
        CONTAINS OBSERVATION OBS[openEHR-EHR-OBSERVATION.basic_demographic.v1]
ORDER BY
    time DESC


--
-- CHA2DS2-VASc input items
--
SELECT
    OBS/data#at0002/events#at0003/data#at0001/items#at0026 AS has_congestive_heart_failure,
    OBS/data#at0002/events#at0003/data#at0001/items#at0029 AS has_hypertension,
    OBS/data#at0002/events#at0003/data#at0001/items#at0039 AS has_stroke_TIA_thromboembolism,
    OBS/data#at0002/events#at0003/data#at0001/items#at0046 AS has_vascular_disease,
    OBS/data#at0002/events#at0003/data#at0001/items#at0032 AS has_diabetes,
    C/context/start_time AS time
FROM
    EHR e[ehr_id/value=$ehrUid]
        CONTAINS COMPOSITION C
        CONTAINS OBSERVATION OBS[openEHR-EHR-OBSERVATION.chadsvasc_score.v1]
ORDER BY
    time DESC

12. Common Decision Logic Modules

12.1. BASIC: Demographics

dlm BASIC.v0.5.0

definitions -- Descriptive

    language = {
        original_language: [ISO_639-1::en]
    }
    ;

    description = {
        lifecycle_state: "unmanaged",
        original_author: {
            name:           "Thomas Beale",
            email:          "thomas.beale@openEHR.org",
            organisation:   "openEHR Foundation <http://www.openEHR.org>",
            date:           "2021-01-10"
        },
        details: {
            "en" : {
                language: [ISO_639-1::en],
                purpose: "To access common demographic state."
            }
        }
    }
    ;

input -- Administrative

    date_of_birth: Date
        ;

    |
    | sex: #male | #female | #indeterminate
    |
    sex: Terminology_code «sexes»,
        ;

    |
    | race
    |
    race: Terminology_code «races»,
        ;

    |
    | Ethnicity:
    |   #white_or_not_stated
    |   #indian
    |   #pakistani
    |   #bangladeshi
    |   #other_asian
    |   #black_caribbean
    |   #black_african
    |   #other_ethnic_group
    |
    ethnicity: Terminology_code «ethnicities»,
        ;

rules -- Main

    |
    | age in years
    |
    age_in_years: Integer
        Result := (current_date - date_of_birth).as_years
        ;

definitions -- Terminology

    terminology = {
        term_definitions: {
            "en" : {
                "date_of_birth" : {
                    text: "Date of birth"
                },
                "age" : {
                    text: "Age"
                },
                "age_in_years" : {
                    text: "Age in years"
                },
                "sex" : {
                    text: "Sex"
                },
                "male" : {
                    text: "Male sex"
                },
                "female" : {
                    text: "Female sex"
                },
            },
        },
        value_sets: {
            "sexes" : {
                id: "sexes",
                members: ["male", "female", "indeterminate"]
            },
            "ethnicities" : {
                id: "ethnicities",
                members: ["white",
                    "indian", "pakistani", "bangladeshi",
                    "other_asian", "black_caribbean",
                    "black_african", "other_ethnic_group"
                ]
            },
            "races" : {
                id: "races",
                members: ["caucasian", "asian", "black", "other"]
            }
        }
    }

12.2. BSA: Body Surface Area

dlm Body_surface_area.v0.5.0

definitions -- Descriptive

    language = {
        original_language: [ISO_639-1::en]
    }
    ;

    description = {
        lifecycle_state: "unmanaged",
        original_author: {
            name:           "Thomas Beale",
            email:          "thomas.beale@openEHR.org",
            organisation:   "openEHR Foundation <http://www.openEHR.org>",
            date:           "2021-01-10"
        },
        details: {
            "en" : {
                language: [ISO_639-1::en],
                purpose:  "Body surface area.",
                use:      "Used to calculate dosage e.g. for chemotherapy and other systemic medications."
            }
        }
    }
    ;

input -- State

    |
    | Weight as recorded in local system
    |
    weight: Quantity
        currency = 30d
        ;

    |
    | Height as recorded in local system
    |
    height: Quantity
        currency = 5y
        ;

rules -- Main

    |
    | Weight in kg
    |
    weight_in_kg: Real
        Result := choice of
            =====================================================
            weight.units = "kg":    weight.magnitude,
            -----------------------------------------------------
            weight.units = "lb":    weight.magnitude / 2.2,
            -----------------------------------------------------
            *:                      {Quantity_converter}.
                                    convert_value (weight.value,
                                        from: weight.units,
                                        to: "kg",
                                        UCUM.#mass)
            =====================================================
        ;

    |
    | Height in cm
    |
    height_in_cm: Real
        Result := choice of
            ====================================================
            height.units = "cm":    height.magnitude,
            ----------------------------------------------------
            height.units = "m":     height.magnitude * 100,
            ----------------------------------------------------
            *:                      {Quantity_converter}.
                                    convert_value (height.value,
                                        from: height.units,
                                        to: "cm",
                                        UCUM.#length)
            =====================================================
        ;

rules -- Output

    |
    | Body surface area
    |
    BSA: Real
        Result := {math}.sqrt (weight_in_kg * height_in_cm / 3600)
        ;

definitions -- Terminology

    terminology = {
        term_definitions: {
            "en" : {
                "bsa" : {
                    text: "Body surface area"
                },
                "weight" : {
                    text: "Body weight, in whatever units are in local use"
                },
                "height" : {
                    text: "Body height, in whatever units are in local use"
                },
                "weight_in_kg" : {
                    text: "Body weight in kg"
                },
                "height_in_cm" : {
                    text: "Body height in cm"
                }
            }
        }
    }
    ;

12.3. BMI: Body Mass Index

dlm Body_mass_index.v0.5.0

definitions -- Descriptive

    language = {
        original_language: [ISO_639-1::en]
    }
    ;

    description = {
        lifecycle_state: "unmanaged",
        original_author: {
            name:           "Thomas Beale",
            email:          "thomas.beale@openEHR.org",
            organisation:   "openEHR Foundation <http://www.openEHR.org>",
            date:           "2021-01-10"
        },
        details: {
            "en" : {
                language: [ISO_639-1::en],
                purpose:  "Body mass index.",
                use:      "Used as a rough surrogate for determining whether a
                          person has in the normal weight range for their height."
            }
        }
    }
    ;

input -- State

    |
    | Weight as recorded in local system
    |
    weight: Quantity
        currency = 30d
        ;

    |
    | Height as recorded in local system
    |
    height: Quantity
        currency = 5y
        ;

rules -- Main

    |
    | Weight in kg, converted as necessary from subject weight
    |
    weight_in_kg: Real
        Result := choice of
            ====================================================
            weight.units = "kg":    weight.magnitude,
            ----------------------------------------------------
            weight.units = "lb":    weight.magnitude / 2.2,
            ----------------------------------------------------
            *:                      {Quantity_converter}.
                                    convert_value (weight.value,
                                        from: weight.units,
                                        to: "kg",
                                        UCUM.#mass)
            ====================================================
        ;

    |
    | Height in m, converted as necessary from subject height
    |
    height_in_m: Real
        Result := choice of
            =====================================================
            height.units = "m":     height.magnitude,
            -----------------------------------------------------
            height.units = "cm":    height.magnitude / 100,
            -----------------------------------------------------
            *:                      {Quantity_converter}.
                                    convert_value (height.value,
                                        from: height.units,
                                        to: "m",
                                        UCUM.#length)
            =====================================================
        ;

rules -- Output

    |
    | Body mass index
    |
    BMI: Real
        Result := weight_in_kg / height_in_m ^ 2
        ;

definitions -- Terminology

    terminology = {
        term_definitions: {
            "en" : {
                "bmi" : {
                    text: "Body mass index"
                },
                "weight" : {
                    text: "Body weight, in whatever units are in local use"
                },
                "height" : {
                    text: "Body height, in whatever units are in local use"
                },
                "weight_in_kg" : {
                    text: "Body weight in kg"
                },
                "height_in_m" : {
                    text: "Body height in m"
                }
            }
        }
    }
    ;