Introduction
Over the last few years of using archetypes and templates in various contexts, including in Australia, the UK NHS, and various provider sites, some subtle problems have emerged, many to do with items within container (i.e. multiply-valued) attributes in the openEHR Reference Model (RM). Most of the attributes in the openEHR RM are of this type, in common with other models used in health informatics (i.e. in a general sense, most such models are some kind of tree structure). Another area of possible ambiguity is the 'slot' concept, which it appears has not been clearly enough defined. This page aims to elucidate the requirements, current difficulties, workarounds, and possible long-term solutions.
Thanks to the numerous people from the community, including people working within the UK NHS and Dutch modelling efforts. It has taken quite some time to gather sufficiently clear explanations of numerous problems and requirements so as to create something resembling a comprehensive analysis.
Choice in Single Attributes
Requirement
The first requirement we consider is actually the notion of 'alternatives' within single-valued attributes, which is already built in to the Archetype Definition Language (ADL). This says that at any single-valued attribute, multiple object constraints can be stated, with the meaning that each such constraint is an alternative, i.e. the data at runtime can be matched to any on of the constraints. Here is the example from section 5.3.2 of the ADL specification:
No Format |
---|
items cardinality matches \{*\} matches
ELEMENT[at0004] matches { -- speed limit
value matches {
DV_QUANTITY[at0022] matches { -- miles per hour
magnitude matches {|0..55|}
property matches {"velocity"}
units matches {"mph"}
}
DV_QUANTITY[at0023] matches { -- km per hour
magnitude matches {|0..100|}
property matches {"velocity"}
units matches {"km/h"}
}
}
}
}
|
...
So far, this requirement appears to correspond to a current need.
Tooling
The current archetype tools in use are less clear with respect to single-valued attribute alternatives. The Ocean Archetype Editor (AE) supports the capability via a 'choice' node, but because it does not work the same way under multiple-valued attributes, it can be confusing for users.
Choice in Container Attributes
Requirements
When it comes to mutliply-valued attributes, things are more complicated. ADL provides the ability to define multiple members of a multiply-valued attribute, each defining a possible constraint that could be used to control data. Because we are talking about a container attribute, data could be created conforming to more than one, and possibly all, of the object children of such an attribute defined in an archetype. Consider for example the following:
No Format |
---|
EVALUATION[at0000] matches { -- Problem
data matches {
ITEM_TREE[at0001] matches { -- structure
items cardinality matches {0..*; ordered} matches {
ELEMENT[at0002] occurrences matches {1} matches { -- Problem
value matches {
DV_TEXT matches \{*\}
}
}
ELEMENT[at0003] occurrences matches {0..1} matches { -- Date of initial onset
value matches {
DV_DATE matches {
value matches {yyyy-??-??}
}
}
}
ELEMENT[at0004] occurrences matches {0..1} matches {...} -- Age at initial onset
ELEMENT[at0005] occurrences matches {0..1} matches {...} -- Severity
ELEMENT[at0009] occurrences matches {0..1} matches {...} -- Clinical description
ELEMENT[at0010] occurrences matches {0..1} matches {...} -- Date clinically recognised
CLUSTER[at0011] occurrences matches {0..*} matches {...} -- Location
-- etc
}
}
}
|
...
As far as it goes, this is fine, and serves the purposes of many archetypes, where the requirement is simply to state the possible node types in a container. However some other needs have arisen over the course of the last couple of years' modelling.
Choice on a node in a container
The first is the need to be able to define an archetype so that one (or it may be more) of the items in some container consist of a choice of distinct items. For example, if a list of 8 object constraints in an ITEM_TREE.items list like the one were defined, it may be that for item 4 we actually want to define more than one possibility, only one of which can be chosen. Consider the following structure of data relating to a clinical investigation:
...
In this approach, the following kind of archetype structure would be defined:
No Format |
---|
definition
EVALUATION[at0000] matches { -- Investigation report
data matches {
ITEM_TREE[at0001] matches { -- Tree
items cardinality matches {0..*; unordered} matches {
ELEMENT[at0002] occurrences matches {1} matches {...} -- Investigation type
ELEMENT[at0003] occurrences matches {0..1} matches {...} -- Investigation reason
ELEMENT[at0004] occurrences matches {0..1} matches { -- Methodology as a Text description
value matches {
DV_TEXT matches \{*\}
}
}
ELEMENT[at0005] occurrences matches {0..1} matches { -- Methodology as a Coded list
value matches {
DV_CODED_TEXT matches {
defining_code matches {
[local::
at0020, -- method A
at0021] -- method B
}
}
}
}
CLUSTER[at0006] occurrences matches {0..1} matches { -- Methodology as a Structured description
items cardinality matches {0..*; unordered} matches {
allow_archetype ITEM[at0007] occurrences matches {0..*} matches { -- Item
include
archetype_id/value matches {/.*/}
}
CLUSTER[at0008] occurrences matches {0..1} matches { -- Details
items cardinality matches {0..*; unordered} matches {
ELEMENT[at0009] occurrences matches {0..1} matches { -- Route
value matches {
DV_TEXT matches \{*\}
}
}
ELEMENT[at0010] occurrences matches {0..1} matches { -- Site
value matches {
DV_TEXT matches \{*\}
}
}
}
}
}
}
ELEMENT[at0011] occurrences matches {0..1} matches {...} -- (some other details)
CLUSTER[at0012] occurrences matches {0..1} matches {...} -- (some other details)
}
}
}
}
rules
exists /data/items[at0004] xor exists /data/items[at0005] xor exists /data/items[at0006]
|
...
This approach has been used by modellers in the NHS and elsewhere, and looks like the following:
No Format |
---|
EVALUATION[at0000] matches { -- Investigation report
data matches {
ITEM_TREE[at0001] matches { -- Tree
items cardinality matches {0..*; unordered} matches {
ELEMENT[at0002] occurrences matches {1} matches {...} -- Investigation type
ELEMENT[at0003] occurrences matches {0..1} matches {...} -- Investigation reason
CLUSTER [at0004] occurrences matches {1} matches { -- Methodology -- NOTE NEW CLUSTER NODE
items cardinality matches {1} matches { -- NOTE CARDINALITY OF 1
ELEMENT[at0005] occurrences matches {0..1} matches {...} -- as a Text description
ELEMENT[at0006] occurrences matches {0..1} matches {...} -- as a Coded list
CLUSTER[at0007] occurrences matches {0..1} matches {...} -- as a Structured description
}
}
ELEMENT[at0011] occurrences matches {0..1} matches {...} -- (some other details)
CLUSTER[at0012] occurrences matches {0..1} matches {...} -- (some other details)
}
}
}
}
|
...
It is potentially debatable whether the left hand structure of data is any worse than the right hand one in terms of viewing / comprehensibility. It should be remembered that the extra CLUSTER has its cardinality set to 0.1, and so it not acting as a proper container. In a theoretical modelling sense, we have introduced a problem with the CLUSTER approach (which can also be effected using SECTIONs at higher levels in the hierarchy) in that now the method for dealing with 'choice' under a multiply-valued attribute is different from that under a single-valued attribute. However, the main thing we need to be aware of with respect to this solution is how it affects code generation, particularly for GUI building. If the extra-CLUSTER method is used, an extra grouping element will appear in any generate GUI, which may not be desirable.
Solutions
We need to keep in mind the difference between the following things:
...
- use the extra-CLUSTER approach (extra-SECTION in the level above ENTRY), and modify tools to use this behind the scenes to implement the logical 'choice' concept;
- optionally a modification could be made to ADL to add a new construct to be used in place of 'cardinality matches {0..1}', such as 'selector' or similar. This would ease the mapping to tools.
- but otherwise, no changes would be made to ADL. The main changes would be in tooling.
- add a more complex construct to ADL / AOM that supports a 'choice of subgroup' idea, as shown in the following example.
No Format |
---|
EVALUATION[at0000] matches { -- Investigation report
data matches {
ITEM_TREE[at0001] matches { -- Tree
items cardinality matches {0..*; unordered} matches {
ELEMENT[at0002] occurrences matches {1} matches {...} -- Investigation type
ELEMENT[at0003] occurrences matches {0..1} matches {...} -- Investigation reason
ITEM[at0005] group cardinality matches {0..1} matches { -- Methodology ************** NEW GROUP CONSTRUCT
ELEMENT[at0006] occurrences matches {0..1} matches {...} -- Methodology as a Text description
ELEMENTat0007 occurrences matches {0..1} matches {...} -- Methodology as a Coded list
CLUSTER[at0008] occurrences matches {0..1} matches {...} -- Methodology as a Structured description
}
ELEMENT[at0011] occurrences matches {0..1} matches {...} -- (some other details)
CLUSTERat0012 occurrences matches {0..1} matches {...} -- (some other details)
}
}
}
}
|
...
Now, an alternative, slightly simplified form of the above does away with the object typing, and treats 'group' as a kind of inline constraint statement, e.g.:
No Format |
---|
EVALUATION[at0000] matches { -- Investigation report
data matches {
ITEM_TREE[at0001] matches { -- Tree
items cardinality matches {0..*; unordered} matches {
ELEMENT[at0002] occurrences matches {1} matches {...} -- Investigation type
ELEMENT[at0003] occurrences matches {0..1} matches {...} -- Investigation reason
group cardinality matches {0..1} matches { -- Methodology ************** NEW GROUP CONSTRUCT
ELEMENT[at0006] occurrences matches {0..1} matches {...} -- Methodology as a Text description
ELEMENTat0007 occurrences matches {0..1} matches {...} -- Methodology as a Coded list
CLUSTER[at0008] occurrences matches {0..1} matches {...} -- Methodology as a Structured description
}
ELEMENT[at0011] occurrences matches {0..1} matches {...} -- (some other details)
CLUSTERat0012 occurrences matches {0..1} matches {...} -- (some other details)
}
}
}
}
|
...
So far we can control the membership of a given group. However, another basic need is to allow repetition of the group as a whole. To achieve this, we can add an occurrences constraint, as follows:
Code Block |
---|
EVALUATION[at0000] matches { -- Investigation report
data matches {
ITEM_TREE[at0001] matches { -- Tree
items cardinality matches {0..*; unordered} matches {
ELEMENT[at0002] occurrences matches {1} matches {...} -- Investigation type
ELEMENT[at0003] occurrences matches {0..1} matches {...} -- Investigation reason
group cardinality matches {0..1} occurrences matches {0..*} matches { -- Methodology ************** NEW GROUP CONSTRUCT
ELEMENT[at0006] occurrences matches {0..1} matches {...} -- Methodology as a Text description
ELEMENTat0007 occurrences matches {0..1} matches {...} -- Methodology as a Coded list
CLUSTER[at0008] occurrences matches {0..1} matches {...} -- Methodology as a Structured description
}
ELEMENT[at0011] occurrences matches {0..1} matches {...} -- (some other details)
CLUSTERat0012 occurrences matches {0..1} matches {...} -- (some other details)
}
}
}
}
|
...
A third question to consider is: do we allow 'group' statements to be nested, as per the following example:
No Format |
---|
ITEM_TREE[at0001] matches { -- Tree
items cardinality matches {0..*; unordered} matches {
ELEMENT[at0002] occurrences matches {1} matches {...} -- Investigation type
ELEMENT[at0003] occurrences matches {0..1} matches {...} -- Investigation reason
group cardinality matches {2} matches { -- pick any 2 of below
ELEMENT[at0006] occurrences matches {0..1} matches {...}
ELEMENTat0007 occurrences matches {0..1} matches {...}
CLUSTER[at0008] occurrences matches {0..1} matches {...}
group cardinality matches {1} matches { -- must include at least one of these
ELEMENT[at0009] occurrences matches {0..1} matches {...}
CLUSTER[at00010] occurrences matches {0..1} matches {...}
}
}
ELEMENT[at0011] occurrences matches {0..1} matches {...} -- (some other details)
CLUSTER[at0012] occurrences matches {0..1} matches {...} -- (some other details)
}
}
}
}
|
...
With respect to the AOM, the above proposal would require a group construct, which has not yet been designed. This solution would be more complex in terms of ADL / AOM, but would produce the correct outcome in the data, that is to say, no extra 'junk' objects. It would also require some work in editing tools to visualise the construct as a 'choice' construct in a way comprehensible to clinical model authors.
Archetype Slots, Fillers, and ordering
Another problem with (un)ordered lists of multiple items within a container attribute relates to archetype slots. An archetype slot is an object node that defines possible archetypes that may be used, rather than defining further constraints inline. The following example shows a typical use of slots.
No Format |
---|
SECTION[at0000] matches { -- SOAP
items cardinality matches {0..*; unordered} matches {
SECTION[at0001] occurrences matches {0..1} matches { -- S
items cardinality matches {0..*; unordered} matches {
allow_archetype OBSERVATION[at0006] occurrences matches {0..1} matches { -- Subjective observations
include
archetype_id/value matches {/.*/}
}
allow_archetype SECTION[at0007] occurrences matches {0..1} matches { -- Subjective sections
include
archetype_id/value matches {/.*/}
}
}
}
....
}
|
...
The slot constraints needed to define this are as follows:
No Format |
---|
SECTION[at0001] occurrences matches {0..1} matches { -- S
items cardinality matches {0..*; ordered} matches {
allow_archetype EVALUATION[at0006] occurrences matches \{*\} matches { -- Problem
include
archetype_id/value matches {/openEHR-EHR-EVALUATION\.problem\.v*/}
}
allow_archetype EVALUATION[at0007] occurrences matches \{*\} matches { -- Diagnosis
include
archetype_id/value matches {/openEHR-EHR-EVALUATION\.problem-diagnosis\.v*/}
}
allow_archetype EVALUATION[at0008] occurrences matches {1} matches { -- Plan
include
archetype_id/value matches {/openEHR-EHR-EVALUATION\.plan\.v*/}
}
allow_archetype INSTRUCTION[at0009] occurrences matches \{*\} matches { -- INtervention
include
archetype_id/value matches {/openEHR-EHR-INSTRUCTION\.plan\.v*/}
}
}
|
The above says that the SECTION.items attribute is an ordered list, and that its contents include multiple EVALUATION objects representing problem, diagnosis and plan, and also multiple INSTRUCTION objects representing interventions. The problem is now apparent. Each slot definition is set of possibilities, but we do not necessarily want to follow the slot ordering for the ordering of the archetypes chosen to fill the slots. This means we need to understand what the 'ordered' constraint actually means in this context: does it mean that the slots define order? Regardless, they do not give us a way to impose any internal structure on the list. We could use the group construct above to help. We could for example define the following:
No Format |
---|
SECTION[at0001] occurrences matches {0..1} matches { -- Subjective
items cardinality matches {0..*; ordered} matches {
group cardinality matches {0..1} occurrences matches {0..*} matches { -- sub-group of any number of problems & diagnoses
allow_archetype EVALUATION[at0006] matches { -- Problem
include
archetype_id/value matches {/openEHR-EHR-EVALUATION\.problem\.v*/}
}
allow_archetype EVALUATION[at0007] matches { -- Diagnosis
include
archetype_id/value matches {/openEHR-EHR-EVALUATION\.problem-diagnosis\.v*/}
}
}
allow_archetype EVALUATION[at0008] occurrences matches {1} matches { -- Plan
include
archetype_id/value matches {/openEHR-EHR-EVALUATION\.plan\.v*/}
}
allow_archetype INSTRUCTION[at0009] occurrences matches \{*\} matches { -- INtervention
include
archetype_id/value matches {/openEHR-EHR-INSTRUCTION\.plan\.v*/}
}
}
|
Now the above has the desired result in data: a group of any number of problems & diagnoses, followed by a plan, followed by one or more Interventions.
Semantics of 'group'
Based on the above, the current preference is to define the syntax of 'group' as a pure inline constraint addition to ADL, i.e. not as a pseudo-object block. Nesting would be allowed. Group statements should be viewed as the equivalent of special invariant statements that control choice of sub-groups of nodes within larger lists. A group block would have the following syntax:
No Format |
---|
group_block ::= 'group' 'matches' cardinality_constraint occurrences_constraint '{' ( object_block )+ '}'
cardinality_constraint ::= '{' n [ ';' uniqueness_constraint ] [ ';' ordering_constraint ] '}' | '{' n '..' m [ ';' uniqueness_constraint ] '}'
occurrences_constraint ::= '{' n '}' | '{' n '..' m '}'
uniqueness_constraint ::= 'unique'
ordering_constraint ::= 'ordered' | 'unordered'
|
...
- group cardinality matches {1} -- must match 1
- group cardinality matches {0..1} -- optionally match one node from the following group
- group cardinality matches {0..3} occurrences matches {*}-- optionally match up to 3 nodes from the following group, allowing repeats
- group cardinality matches {2..3} occurrences matches {*} -- match between 2 and 3 nodes from the following group, allowing repeats
- group cardinality matches {3; unique} -- match exactly 3 unique nodes from the following group (i.e. 2 objects in data cannot match one node in the group)
- group cardinality matches {} occurrences matches {} -- match any number of nodes from the following group, including repeats
Nesting
Where nested group statements occur, the main requirement is that the multiplicity intervals are compatible.
TBC
Specialisation
Overrides made in a specialised archetype to a part of a parent archetype containing a specialisation must obey the general rules of archetype specialisation: the specialised archetype cannot violate the constraints in the parent. This leads to the following rules:
- a group statement cannot be removed in a child archetype (note that this prevents child archetypes imposing alternative sub-groups);
- the multiplicity interval of a group statement can only be redefined to an interval the same as or contained within the multiplicity interval of the same statement in the parent;
- a group 'unique' constraint in the parent cannot be removed in the child, but the child can add a 'unique' constraint where none existed.
Semantics of Ordering
Ordering is considered to apply to a data objects that conform to object constraint nodes defined in a container in an archetype.