openEHR logo

Decision Language specification

Issuer: openEHR Specification Program

Release: PROC latest

Status: DEVELOPMENT

Revision: [latest_issue]

Date: [latest_issue_date]

Keywords: expressions, rules, guidelines

openEHR components
© 2020 - 2020 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, Implementer Completed

PROC Release 2.0.0 (unreleased)

0.6.0

SPECPROC-41. Add Decision Language specification.

T Beale

27 Sep 2020

Acknowledgements

Primary Author

  • Thomas Beale, Ars Semantica; openEHR Foundation Management Board.

1. Preface

1.1. Purpose

This document specifies the openEHR Decision Language, in both abstract syntax form and as a related model. The latter defines the semantics of a first order predicate style logic that can be used to write Decision Logic Modules (DLMs) containing rule-sets that may be used standalone or with a Process / Plan oriented system such as openEHR Task Planning.

The intended audience includes:

  • Standards bodies producing health informatics standards;

  • Academic groups using openEHR;

  • Solution vendors.

Prerequisite documents for reading this document include:

Related documents 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/decision_language.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.

1.5. Conformance

Conformance of a data or software artifact to an openEHR specification is determined by a formal test of that artifact against the relevant openEHR Implementation Technology Specification(s) (ITSs), such as an IDL interface or an XML-schema. Since ITSs are formal derivations from underlying models, ITS conformance indicates model conformance.

2. Overview

The openEHR Decision Language (DL) and model defines a formalism for expressing decision logic and rules used by process-oriented healthcare information systems, active forms and so on. Decision logic usually sits within a larger environment of plans, guidelines and data sources such as the EHR, as described in the openEHR Process and Planning Overview. The primary encapsulation of DL is within a Decision Logic Module (DLM).

Within the openEHR ecosystem, Task Plans and GDL3 guidelines both require a way of expressing rules and declaring input variables. Guidelines additionally need a way of declaring output variables. These needs are achieved with the flexible use of a single kind of multi-section module called a decision logic module (DLM).

The Decision Language is a high-level language in which modules containing the following elements may be written:

  • reference data: domain constants;

  • input variables: data items representing external variables relating to the subject (i.e. patient);

  • conditions: Boolean-returning domain-specified criteria;

  • rules: domain-specified rules structures based on condition/action structures, which may return any type;

  • rule-sets: related sets of rules in various forms, including decision tables;

  • outputs: computed results of rule invocations, including logic trace information;

All symbolic elements, including constants, variables and rules may be treated as codes for which a translation terminology is supplied, enabling a DLM to be translated and presented in any natural language.

2.1. Requirements

The requirements of openEHR Decision Language fall into a number of categories, described below.

TBD: this section only very rough for now.

2.1.1. Caller Interaction

  • the ability to capture the reasoning chain for presentation to a caller as a justification;

  • the ability to provide a decision and its possible outcomes, with the current recommendation indicated;

2.1.2. Representation

2.1.3. Binding to Data Context

  • bindings that connect variables to external data sources;

2.1.4. Type System

  • an ability to use externally defined information models that supply types that may be used in DL statements.

2.2. Execution Model

TBD:

3. DLM Syntax

The openEHR Decision Language (DL) is primarily used to write Decision Logic Modules (DLMs). A DLM has the following structure.

dlm <form> <identifier>

[language
    <lang and translations meta-data, as for archetypes>]

[description
    <descriptive meta-data>]

[use_model
    <reference model ids; defaults to openEHR Foundation & Base types>]

[use
    <local identifier>: <dlm identifier>
    <local identifier>: <dlm identifier>]

[preconditions
    <conditions that act as pre-conditions for this module>]

[reference
    <constant definitions>]

input
    <subject variable declarations>

rules
    <conditions and rules expressed as EL functions>

[output
    <output variable declarations>]

[terminology
    <symbol definitions in archetype format>]

[bindings
    <local bindings of symbols to data set paths>]

Many of the sections are optional and are only used in specific forms of DLM, indicated by the <form> on the first line.

The language, description and terminology sections (which are identical in form to the same-named sections in openEHR archetypes) can be omitted for DLMs in development for which no descriptive meta-data or terminology is needed.

3.1. Identifiers

All identifiers in a DLM are strings with no whitespace. If the terminology section is present, these identifiers are included with linguistic definitions and translations, in the same way as archetypes. This approach enables the symbolic variables such as is_type1_diabetic to be used in rules, and to have a full, formal, multi-lingual definition, such as the following:

terminology
    term_definitions = <
        ["en"] = <
            ["resting_heart_rate"] = <
                text = <"heart rate at rest">
                description = <"...">
            >
            ...
            ["SpO2"] = <
                text = <"Oxygen saturation">
                description = <"...">
            >
        >
    >

3.2. Identification Section

The identification section takes the form dlm <form> <identifier>, where:

  • <form>: flavour of DLM artefact, with value ruleset | guideline;

  • <identifier>: identifier, in the format <concept>.vN.N.N where vN.N.N represents a numeric version of the logical form major.minor.patch, and whose values over time obey the Semver.org rules.

The following shows the identification line for a guideline:

dlm guideline chadvasc2.v1.0.5

A reference to a DLM may be effected by quoting the whole identifier, or a form with the minor and / or patch parts of the version missing. Either of these forms identify the most recent matching DLm available. For example, the reference NHS-chops14.v4 identifies whatever the most recent minor version of the v4 major version of the NHS-chops DLM is locally available.

3.3. Language and Description Sections

The language and description sections are the same as for openEHR archetypes, and are formally defined by the openEHR Resource specification. The following provides an example.

language
    original_language = <[ISO_639-1::en]>

description
    lifecycle_state = <"stable">
    original_author = <
        ["name"] = <"Rong Chen">
        ["date"] = <"2020-03-22">
    >
    details = <
        ["en"] = <
            language = <[ISO_639-1::en]>
            purpose = <"Simple cardiology guideline">
        >
    >

3.4. Use_model Section

The optional use_model section enables a DLM to specify a model that defines the type system for the DLM. The identifier of the model must be resolvable to a BMM model, i.e. a model for which an openEHR Basic Meta-Model file is available. This might be a well-known model such as the openEHR Reference Model (BMM form), or a custom model created for local use. The model identifier must include a version matching part, with at least the major version present. The following example specifies the use of the openEHR RM in the latest 1.1 version available.

use_model
    openEHR-RM.v1.1

The types defined in all 'used' models become available to the DLM for use in declarations. If no model is specified, the openEHR Base and Foundation types are assumed.

3.5. Use Section

A DLM can use other DLMs, by declaring each DLM with an identifier in the use section. The identifier must include a version-matching part. The following example declares the identifier BSA as a convenient local label to refer to the latest version of the DLM Body_surface_area.v1.

use
    BSA: Body_surface_area.v1

3.6. Preconditions Section

The preconditions section is used to state logical conditions that must evaluate to true for the DLM to be used for the subject. Any Boolean-typed identifier may be used from the input, condition or rules sections, or any Boolean-returning logical expression referencing any identifiers declared in the DLM. A typical preconditions section is shown below:

preconditions
    is_pregnant

3.7. Reference Section

The reference section of a DLM contains what might be thought of constant definitions, i.e. identifiers declared with fixed values. The following illustrates.

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

3.8. Input Section

The input section contains declarations of all tracked subject variables used by a DLM. At a minimum, a subject variable declaration states the symbolic name and type of the variable in the manner typical of a typed programming language, as exemplified by the following:

input
    heart_rate: Quantity

Although a subject variable declaration appears to declare a simple property of a type such as a Quantity, in fact it creates an instance of a special proxy object described below in Section 4, that provides access to snapshot values of the variable over time, as well as other smart facilities including null-value detection and range conversion, described in the sections below.

3.8.1. Subject Variable Naming

The naming of a subject variable is important, and should reflect its intended domain meaning with respect to the guideline or plan which it formalises. Thus, a cardiology guideline might use a variable systolic_bp to mean 'current instantaneous systolic blood pressure' and a variable target_systolic_bp to mean a target pressure for the patient to aim for over the course of hypertension treatment. However a guideline that refers to different systolic blood pressures, e.g. historical, average and current might use variables such as actual_systolic_bp, 24h_average_systolic_bp etc.

The naming is important in another way. Generally a subject variable should reflect a fact or assertion about the subject in reality rather than a purely epistemic view relating to an information system. For example a variable is_type1_diabetic is intended to reflect the patient’s real diabetic status, not just the knowledge of the local hospital EMR system of whether the patient is diabetic. Such variables may be termed 'ontic' i.e. reflecting the real world, rather than reflecting states of knowledge of some information source. The reason for using ontic variables is to allow DLM authors to define rules in terms of true clinical reality based on reliable previously established facts, rather than continually having to compensate for missing or unreliable knowledge within a guideline.

Epistemic variables may of course be defined, e.g. the variable has_diabetes_diagnosis directly reflects the idea that the presence of a diagnosis of a condition is distinct from the true fact of having the condition. These are typically used when the purpose of the guideline is to establish the presence or otherwise of the condition named in such variables.

3.8.2. Unavailable (null) Values

One of the facilities created by a declaration of the form identifier: Type are subordinate predicate functions to detect if a value is available for the variable, i.e. if it is not logically null (i.e. void). Lack of a value is caused either by the true absence of the data in back-end systems (e.g. there really is no recent blood pressure available) or a technical failure to either query the appropriate system, or to connect to a system that does in fact contain the data of interest.

It should be noted that within the overall conceptual model of Process-based computing in openEHR, that the common problem of a failure to locate a data item in back-end systems causing a live user to be asked to supply it is assumed to be addressed outside the DLM itself. This means that the simple lack of a value, say a recent vital sign, in back-end systems does not need to be compensated for by logic (including null checks) in a DLM itself - it will already have been done in the Subject Proxy service. Consequently, if a variable value is unavailable, this already takes into account attempts to obtain a value from a user.

The general case is that any subject variable might not have a value available for it, or at least a sufficiently current value (see next section for the concept of 'currency') at the moment of a particular rule invocation (remembering that the same rule might be invoked repeatedly over time). This means that the simple (primary variable) reference systolic_blood_pressure may in fact return a null value. If rules containing primary variable references such as systolic_blood_pressure are written under a non-null assumption, a null value will cause an exception of type no available value, and the original rule invocation will fail.

In most cases this is likely to be the preferred style of rule expression, since it makes rules simpler and clearer. However, in some cases, it may be known a priori that certain variables are only sometimes likely to be available, and if so, they are used, but if not, no exception is generated. This may be achieved by calling the subordinate predicate is_available as a guard on the direct access, as follows.

rules

    is_hypertensive:
        Result := systolic_blood_pressure.is_available and then systolic_blood_pressure.in_range([high]) or  ...

In the above, the semi-strict Boolean operator ensures the second reference to systolic_blood_pressure will only be evaluated if systolic_blood_pressure.is_available returns True.

3.8.3. Currency

The declaration may include a number of other elements. Firstly, since each such variable represents a fact about the subject in the real world, such as a patient heart-rate or diagnosis, rather than just being a local variable, the declaration may state a currency, in terms of a temporal duration. This specifies how recent the value obtained from the external world (the 'sample') must be to be valid from the point of view of the DLM. Currency may be understood as the converse of 'staleness', that is, a variable sample that must be say 1 hour or less old is understood as stale after 1 hour.

The use of the currency modifier establishes that a subject variable is a time-related sample of some kind (instantaneous, average, minimum, etc) of a real-world time-varying continuant quality (e.g. blood pressure) of an independent continuant entity (usually a person).

Since the various physiological and disease process that occur in a human body have significantly differing temporal rhythms, currency will vary widely for different subject variables, as per the following examples.

input
    |
    | DOB never changes, no currency needed
    |
    date_of_birth: Date

    |
    | weight changes over a period of days
    |
    weight: Quantity
        currency = 3 days

    |
    | assuming an adult subject, height constant
    |
    height: Quantity

    |
    | blood glucose changes within minutes in response to food
    |
    blood_glucose: Quantity
        currency = 15 min

    |
    | Heart-rate may change quickly
    |
    heart_rate: Quantity
        currency = 5 sec

Variables for which no currency is stated may be understood as having the currency equal to the age of the subject.

3.8.4. Time-window

Another aspect of a subject variable that can be specified is termed time-window, meaning an interval of real world time within which the state or event that the variable represents occurred. For example, assume the variable previous_history_of_eclampsia declared in an obstetric DLM is intended to represent 'eclampsia experienced by the subject in any previous pregnancy (i.e. not the current pregnancy)'. Another guideline might define a variable no_cancer_last_5y to mean that no recurrence of the cancer addressed by the DLM had occurred within the last 5 years.

Formally, time window is specified in the form of an interval of negative durations with respect to the current point in time, i.e. of the form |-T1 .. -T2|, e.g. |-P3Y .. -P1Y|, meaning 'the period from 3 years ago to 1 year ago'. A single-sided interval such as |> -P30d| ('since 30 days ago') may also be used.

Since the actual duration of a time-window may be subject- and/or context-specific, a symbolic variable may also be used, whose value is supplied by the execution context. For example, the variables tw_current_episode and tw_historical could be used to represent respectively:

  • the interval of the current admission, i.e. date/time of admission until now;

  • the interval of historical time up until the start of the current episode of condition.

Time window can be included in a subject variable declaration as follows:

input
    has_previous_history_of_eclampsia: Boolean
        time_window = tw_historical

    has_pregnancy_related_hypertension: Boolean
        time_window = tw_current_episode

Time window is typically used to ensure that for a kind of event, condition or other characteristic that may occur multiply in the subject lifetime, only occurrences from a particular period are included or excluded. For example, the following declarations ensure that the variable staging and has_metastases refer to the staging and metastases of the current eposide of cancer, not some previous one.

input

    staging: Terminology_term «ann_arbor_staging»
        time_window = tw_current_episode

    has_metastases: Boolean
        time_window = tw_current_episode

In general, if currency is specified, time_window is not.

TBD: determine if there is a meaning for both together.

3.8.5. Variable Ranges

A ubiquitous need within clinical guidelines and rules is to be able to refer to a continuous variable such as vital signs and most lab test values as being in a designated range. Such ranges may be the usual ones published e.g. the normal and high ranges for lipids in a cholesterol test for adults, or ranges defined by the DLM.

TBD: for now ranges have to be declared locally

The ranges for a subject variable may be declared in the following way:

input
    systolic_blood_pressure: Quantity
        currency = 1 min
        ranges =
            [critical_high]:  |>= 180 mm[Hg]|,
            [very_high]:      |>  140 mm[Hg]|,
            [high]:           |>  120 mm[Hg]|,
            [normal]:         |>90 mm[Hg] .. <= 120 mm[Hg]|,
            [low]:            |<=  90 mm[Hg]|,
            [critical_low]:   |<=  50 mm[Hg]|;

The formal type of the ranges property is Hash <Terminology_code, Interval <T>>, where T is the declared type of the subject variable. Thus, in the above, the entry [very_high], |> 140 mm[Hg]| defines a [key, value] pair whose value is of type Interval <Quantity>.

Note that the ranges are defined to be overlapping, such that [high] refers to any value higher than 120, while [very_high] refers to any value over 140.

The above declaration allows the use of the predefined in_range function, which returns the most precise range in which the value falls, in rule expressions as follows:

    Result :=
        choice in {
            ========================================================
            systolic_blood_pressure
                .in_range ([critical_high]):           [emergency],
            --------------------------------------------------------
            systolic_blood_pressure
                .in_range ({[high], [very_high]}):     [high_risk],
            --------------------------------------------------------
            *:                                         [monitor]
            ========================================================
        }

Sometimes there are multiple ranges, usually due to alternative units systems. This is handled by the use of a discriminator. The following shows an example.

input
    PaO2_FiO2_ratio: Quantity
        currency = 1 min
        ranges =
            [SI]:
                [normal]:         |400 mm[Hg]|,
                [low]:            |300 mm[Hg] .. 399 mm[Hg]|,
                [very_low]:       |200 mm[Hg] .. 299 mm[Hg]|,
                [extremely_low]:  |100 mm[Hg] .. 199 mm[Hg]|,
                [critical_low]:   |<100 mm[Hg]|;

            [metric]:
                [normal]:         |53 kPa|,
                [low]:            |39.9 kPa .. 53 kPa|,
                [very_low]:       |26.6 kPa .. 39.8 kPa|,
                [extremely_low]:  |13.3 kPa .. 26.5 kPa|,
                [critical_low]:   |<13.3 kPa|;

3.9. Rules Section

The DLM rules section is the section of primary importance, since it contains the rules for which a DLM is created. DLm rules are formally expressed as functions in the openEHR Expression Language, based on the openEHR BMM.

This section may be typically divided into two or more groups for authoring convenience. The first group may be used for simple Boolean-returning 0-order functions that represent 'named conditions', for use in the primary rules. The Boolean type may be omitted, since all conditions have this as their formal type. The following is an example.

rules -- Conditions

    her2_positive:
        Result := her2_expression = [positive]

    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
            non_class_I_heart_failure

The primary rules may be included in a separate rules group, consisting of 0-order functions returning any type. EL structures of any complexity may be used. The following provides an example.

rules -- Main

    hypertension_risk: Terminology_term
        Result :=
            choice in {
                ===========================================================
                has_pre_eclampsia or
                has_eclampsia:                      [obstetric_emergency],
                -----------------------------------------------------------
                previous_obstetric_hypertension or
                previous_pre_eclampsia or
                previous_eclampsia or
                has_pregnancy_hypertension:         [refer_high_risk_care],
                -----------------------------------------------------------
                *:                                  [normal_obstetric_care]
                ===========================================================
            }

    gestational_diabetes_risk: Boolean
        Result :=
            bmi.in_range ([high]) or
            previous_macrosomic_baby or
            previous_gestational_diabetes or
            family_history_of_diabetes or
            race_related_diabetes_risk

3.10. Output Section

TBD:

3.11. Terminology Section

The terminology section of a DLM serves the same purpose as the terminology section in an openEHR archetype, which is to provide multi-lingual definitions of all codes used in the artefact. Unlike archetypes, the codes in a DLM may be freely named, since they act as names of all symbolic entities referenced elsewhere in the DLM, including rules (i.e. functions), subject variables and constants. A typical DLM terminology section is shown below.

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">
            >
        >
    >

3.12. Bindings Section

TBD:

4. DLM Model

4.1. Overview

The structure of the proc.decision_language packages is shown below.

PROC decision language packages
Figure 1. proc.decision_language Package strucure

The packages are described below.

4.2. Decision Logic Module Package

The module structure of a Decision Logic Module is formally represented by a class model consisting of minimal extensions to the BMM class (i.e. BMM_CLASS) concept. A DLM is thus understood as a special kind of module expressible as a constrained form of class definition, such that only certain types of features are allowed. It also has additions for documentary meta-data and terminology provided by the AUTHORED_RESOURCE class from the openEHR BASE component.

The meta-model is shown below, with the meta-class DECISION_LOGIC_MODULE being the root entity.

PROC decision language.dlm
Figure 2. proc.decision_language.dlm Package

Within this model, the various DLM sections are modelled as specialisations of the BMM meta-class BMM_FEATURE_GROUP, so as to restrict the kind of features they may define. These are described in the following sub-sections.

4.2.1. Pre-conditions Section

The DLM preconditions section is formally represented as a feature group called 'preconditions' whose members are limited to being a single BMM_FUNCTION containing the Boolean expression that appears in that section. The expression may reference only rules and input variables.

4.2.2. Reference Section

The DLM reference section is formally represented as a feature group called 'reference' whose members are limited to BMM constants.

4.2.3. Input Section

The DLM input section is formally represented as a feature group called 'input' whose members are limited to BMM constants of a specific concrete type TRACKED_VARIABLE<T> and descendants, supplied by the proc.decision_language.concrete package.

4.2.4. Rules Section

The DLM rules section is formally represented as a feature group called 'rules' whose members are limited to BMM functions. A specific meta-type DLM_RULE is used in case extensions to the standard BMM_FUNCTION are required.

4.2.5. Class Descriptions

4.2.5.1. DECISION_LOGIC_MODULE Class

Class

DECISION_LOGIC_MODULE

Description

Specialised kind of class that represents a Decision Logic Module (DLM).

Inherit

AUTHORED_RESOURCE, BMM_SIMPLE_CLASS

Attributes

Signature

Meaning

0..1

definitions: List<BMM_CONSTANT>

Constant definitions needed by module.

Functions

Signature

Meaning

0..1

create_bmm_class

Generate a BMM_CLASS structure whose feature groups correspond to the formal sections of a DLM, instantiated using the DLM_XXX_SECTION classes.

4.2.5.2. DLM_REFERENCE_SECTION Class

Class

DLM_REFERENCE_SECTION

Description

Specialised feature group used in DLM to represent the reference section.

Inherit

BMM_FEATURE_GROUP

Attributes

Signature

Meaning

1..1
(redefined)

name: String
{default = "reference"}

Name of this feature group; defaults to 'reference'.

0..1
(redefined)

features: List<BMM_CONSTANT>

Set of features in this group.

4.2.5.3. DLM_INPUT_SECTION Class

Class

DLM_INPUT_SECTION

Description

Specialised feature group used in DLM to represent the input section. Contains only SUBJECT_TRACKED_VARIABLE members.

Inherit

BMM_FEATURE_GROUP

Attributes

Signature

Meaning

1..1
(redefined)

name: String
{default = "input"}

Name of this feature group; defaults to 'input'.

0..1
(redefined)

features: List<BMM_CONSTANT>

Set of features in this group.

4.2.5.4. DLM_RULES_SECTION Class

Class

DLM_RULES_SECTION

Description

Specialised feature group used in DLM to represent the rules section. Contains only DLM_RULE members.

Inherit

BMM_FEATURE_GROUP

Attributes

Signature

Meaning

1..1
(redefined)

name: String
{default = "rules"}

Name of this feature group; defaults to 'rules'.

0..1
(redefined)

features: List<DLM_RULE>

Set of features in this group.

4.2.5.5. DLM_RULE Class

Class

DLM_RULE

Description

Specialised form of BMM_FUNCTION that acts as a DLM rule.

Inherit

BMM_FUNCTION

4.3. DLM Concrete Model

In order to supply a few of the key constructs of a DLM, a concrete model is provided with specific types that express the needed semantics. The main types required relate to input variables. The DLM concrete model UML is shown below.

PROC decision language.concrete
Figure 3. proc.decision_language.concrete Package

4.3.1. Input Variables

The variable definitions found in the input section of a DLM are designed to facilitate both intuitive DLM authoring and tracking of values over time from real data sources, typically health records, devices and so on. The generic class TRACKED_VARIABLE<T> and descendants provide a representation of an external variable with a symbolic name, e.g. is_diabetic, heart_rate, etc and values, tracked over time. The generic type parameter is substituted with types used for representing atomic data values, including primitive types such as String, Integer etc, as well as types like Terminology_code, Quantity etc, as available in the models (type definitions) used by a DLM.

The history attribute represents variable value samples over time, for variables with currency defined, while the features is_available and unavailable_reason provide a way for missing data to be checked for.

The class TRACKED_QUANTITATIVE_VARIABLE<T> adds the range facility described earlier in Section 3.8.5.

Variable declarations in DL syntax, as described in the language section above are in fact instantiations of the TRACKED_VARIABLE<T> or a descendant, potentially with constructor paramaters supplied. Consider the following declaration, shown earlier:

    systolic_blood_pressure: Quantity
        currency = 1 min
        ranges =
            [critical_high]:  |>= 180 mm[Hg]|,
            [very_high]:      |>  140 mm[Hg]|,
            [high]:           |>  120 mm[Hg]|,
            [normal]:         |>90 mm[Hg] .. <= 120 mm[Hg]|,
            [low]:            |<=  90 mm[Hg]|,
            [critical_low]:   |<=  50 mm[Hg]|;

If we were to rewrite this in a more standard programming language, it might look like the following object instantiation, preceded by setup code (the syntax 'Type_name (args)' is used to represent an object creation using a constructor call in each case):

// build the ranges Map
ranges: Map <Terminology_code, Interval<Quantity> ();
ranges.put (Terminology_code("critical_high"), Interval<Quantity>(180 mm[Hg], Void);
    ...
ranges.put (Terminology_code("critical_low"), Interval<Quantity>(Void, 50 mm[Hg]);

// instantiate the tracked variable object
systolic_blood_pressure: TRACKED_QUANTITATIVE_VARIABLE<Quantity> (
    "systolic_blood_pressure",   // name
    PT1M,                        // currency
    ranges                       // ranges
);

It will be appreciated that this is substantially more complex, and also arcane to a domain specialist. In the above, the part between the parentheses in the lower declaration corresponds to a call to a constructor of type TRACKED_QUANTITATIVE_VARIABLE with the signature (name: String, currency: Iso8601_duration, ranges: Map<Terminology_code, Interval<T>). From a formal point of view, such an instantiation creates an instance that will remain for the life of the DLM’s execution, in other words, a computed constant value. It is thus a meta-instance of the BMM meta-type BMM_CONSTANT, as shown in the DLM model above.

Each input variable declaration creates an object similar to the above, which may then be used during the execution of the DLM by calls made from the functions in the rules section. The simplest possible 'bare' reference of the variable name alone, i.e. systolic_blood_pressure in the example above, makes use of the default delegate feature of the BMM (BMM_FUNCTION) to invoke the value() function, avoiding the need to write systolic_blood_pressure.value(). However, all the features defined on TRACKED_VARIABLE and its descendants are indeed available for use in DLM code if needed. Thus, systolic_blood_pressure.in_range([high]) is a normal call on the systolic_blood_pressure instance of TRACKED_QUANTITATIVE_VARIABLE<Quantity>.

TO BE CONTINUED

4.3.2. Class Descriptions

4.3.2.1. TRACKED_VARIABLE Class

Class

TRACKED_VARIABLE<T>

Description

Abstraction representing a 'tracked' real-world variable representing a quality of a subject, e.g. patient systolic blood pressure, diabetic status, date of birth etc, whose value is sampled and potentially tracked over time.

The generic parameter is a model type from an accessible model.

Attributes

Signature

Meaning

1..1

name: String

0..1

currency: Iso8601_duration

If set, maximum age of a real-world snapshot of this variable’s value.

0..1

history: Hash<String,VALUE_SNAPSHOT>

Local history of values.

0..1

max_history: Iso8601_duration

0..1

time_window: Interval<Iso8601_date_time>

Functions

Signature

Meaning

0..1

value (): T

Retrieve latest value, or null if none.

1..1

value_at_time (
a_time: Iso8601_date_time[1]
): T

Return the value from history that was available at time time.

1..1

is_available (): Boolean

Return True if there is a value in history whose time is within the duration of currency of the current moment.

0..1

unavailable_reason (): String

If is_available is False, potentially provide a reason.

1..1

is_tracking (): Boolean

Return true if tracking (i.e. snapshotting) is occurring, i.e. if currency is set. False indicates that a single sample is sufficient.

4.3.2.2. VALUE_SNAPSHOT Class

Class

VALUE_SNAPSHOT<T>

Description

Attributes

Signature

Meaning

0..1

value: T

1..1

time: Iso8601_date_time

0..1

unavailable_reason: String

4.3.2.3. TRACKED_QUANTITATIVE_VARIABLE Class

Class

TRACKED_QUANTITATIVE_VARIABLE<T>

Description

Specialised property that represents a 'tracked variable' within the DLM input section. A tracked variable is used to record snapshots of an external variable such as a subject blood pressure.

Inherit

TRACKED_VARIABLE

Attributes

Signature

Meaning

0..1

range_groups: Hash<String,RANGE_GROUP>

Range definitions, organised as groups, each one exhaustively covering the value space.

Functions

Signature

Meaning

1..1

in_range (
a_range: Terminology_code[1]
): Boolean

Determine if the last read value of the variable is in the named range within the default group. Use when there is only one range group.

1..1

range (): Terminology_code

Return the name of the range from the default range group within which the last read value of the variable resides. Use when there is only one range group.

1..1

range_definition (
a_range: Terminology_code[1]
): Interval<T>

Return the interval of the named range within the default range group. Use when there is only one range group.

1..1

in_group_range (
range_group: Terminology_code[1],
a_range: Terminology_code[1]
): Boolean

Form of in_range() to use when there is more than one range group.

1..1

group_range (
range_group: Terminology_code[1]
): Terminology_code

Form of range() to use when there is more than one range group.

1..1

group_range_definition (
range_group: Terminology_code[1],
a_range: Terminology_code[1]
): Interval<T>

Form of range_def() to use when there is more than one range group.

4.3.2.4. RANGE_GROUP Class

Class

RANGE_GROUP<T>

Description

Structure representing a set of range definitions covering the value space of the variable.

Attributes

Signature

Meaning

0..1

ranges: Hash<String,RANGE_DEF>

Map of variable range definitions within this group.

1..1

name: Terminology_code

Name of this range group, e.g. "metric", "SI" etc.

4.3.2.5. RANGE_DEF Class

Class

RANGE_DEF<T>

Description

Definition of a range of a tracked variable in terms of an Interval of the variable type.

Attributes

Signature

Meaning

1..1

name: Terminology_code

Name of this range.

1..1

interval: Interval<T>

Interval specification for the range.

References