Most laboratory results in haematology, biochemistry, immunology and virology are expressed as single analytes or as panels. Microbiology and histopathology (anatomic pathology) reports have a different structure and are modelled differently, and are described elsewhere.
With the release of the laboratory Test series of archetype to Team Review, it was felt useful to provide guidance on the use of these archetypes, as, based on implementation experience, a very different approach is now suggested for handling laboratory tests.
Laboratory Report : The overall report as received from the laboratory, generally a COMPOSITION, which will contain one or more ’Laboratory Tests’.
Laboratory Test: The container OBSERVATION which contains details of the ordered laboratory investigation and overall conclusions. Examples: “Urea and Electrolytes”, “Full blood count”, “Glucose”, “Prostate Cancer Histopathology”
Laboratory Result (Analyte): An individual result with a value. e.g. Hb, White cell count, Urea, Sodium, Glucose. A Lab Test may include only a single analyte or multiple analytes, often as part of a formal ‘Laboratory panel’.
Each Laboratory Result will have a name e.g. “Hb” and a Value e.g. “12.2g/dl”. The Name is generally coded, preferably with an external reference terminology like SNOMED CT, NPU or LOINC but local laboratory codes or controlled vocabularies are commonly used.
Laboratory Panel: A grouping of laboratory analytes, that generally reflect a grouped Test request, often aligned to the output of an automatic group analysis device. The exact make-up of a ‘laboratory panel’ varies between labs and lab analysers. i.e. The analytes included in a “Full blood Count”, whilst broadly similar, are not consistent across analysers.
Where an individual analyte is requested the Test Name and the Result Name may be identical.
Laboratory tests need to modelled in two quite different ways…
1. Message-driven contexts
Laboratory results are most commonly imported automatically via a structured message such as HL7v2, though other national messaging standards exist. The message structures can be quite variable and identification of the lab test and lab analytes make use of terminology. The exact structure of the incoming data is highly variable, and will depend on laboratory policy, variability of adherence to national standards, the exact lab analyser device used.
In essence the modeller is at the mercy of the laboratory message, and the target models have to be able to cope with inconsistent structures and coding.
2. UI-driven contexts
In some circumstances, the modeller is asked to construct a dataset which replicates one or more laboratory tests to underpin data-entry screens, or perhaps to pull data from a specific device. In these cases the optimal structure and optimal coding of test and analyte names will be known, and can be specified in the models.
In some systems, both contexts will be required and he challenge is to find an approach that allows consistent querying and retrieval.
In previous modelling efforts, a generic OBSERVATION lab_test archetype was often specialised to represent common individual ‘lab analytes’ or ‘lab panels’ such as ‘Lipid Profiles’, ‘Full Blood count’. Whilst this can work well for specific UI-driven contexts, it is much less helpful in messaging-driven contexts.
The variable nature of laboratory messaging and, in particular, the variable content of lab panels, makes it difficult for technical teams to map such messages to archetypes where the analyte pattern is strongly modelled.
Ian McNicoll to check the following.
This approach produces the 2 variant hierarchy of lab result data for biochemistry and haematology. The first is a pattern where a Lab test result Observation directly contains one or more analytes, each of which is a Cluster.
The second is a structure in which the Test Findings are a panel, e.g:
More generally, a free mixture of Panels and single Analytes could be used.
PROBLEM: querying paths are different if one pattern is not consistently used for the same kinds of analyte. E.g. if serum sodium and serum potassium are imported from a message feed and included under a panel by one implementation, but directly by another, and both implementations feed data to the same health record, there will be a problem querying, unless the CONTAINS operator is used.
In the following:
(Ack: Former user (Deleted) from Core Consulting, Brasilia)
Leucogram (Panel) (analyte)Leucocytes - 5.800/mm3 (analyte)Linfocytes 19% 1.102/mm3 (analyte)Eosinophiles 1% 58/mm3 |
Results in absolute and relative values. The relative representation is not mandatory. In this example, leucocytes are only reported as absolute values, since they are the parameter for the relative calculation of the other analytes in white cell count.
This implies an analyte archetype structure like the following:
-- ADL2 syntax CLUSTER[id9] matches { items matches { ELEMENT[id2.1] matches { -- absolute value value matches { DV_QUANTITY[id0.1] matches { normal_range matches { DV_INTERVAL<DV_QUANTITY>[id0.2] } other_reference_ranges matches { REFERENCE_RANGE<DV_QUANTITY>[id0.3] } } } } ELEMENT[id2.2] matches { -- relative value value matches { DV_QUANTITY[id0.4] matches { units matches {"%"} normal_range matches { DV_INTERVAL<DV_QUANTITY>[id0.5] } other_reference_ranges matches { REFERENCE_RANGE<DV_QUANTITY>[id0.6] } } } } } } |
(Ack: Former user (Deleted) from Core Consulting, Brasilia)
Some labs report results for the same analyte in 2 different units for better interpretation, e.g. (nmol/L; pg/mL) (mg/dL; mmol/L), resulting in two distinct values for the same analyte. At the same time, labs may adopt different units for the same exam.
(Ack: Former user (Deleted) from Core Consulting, Brasilia)
Antibiogram (Panel) (analyte) Amoxicillin > 2 mcg/mL Sensible (analyte) Sulfadiazine > 64 mcg/mL Resistant (analyte) Cefalexine > 0,5 mcg/mL Sensible |
This example illustrates scenarios in which some labs may use only one data type, whereas others may report the same result in two different ways.
This implies an analyte archetype structure like the following:
-- ADL2 syntax CLUSTER[id9] matches { items matches { ELEMENT[id2.1] matches { -- quantity value matches { DV_QUANTITY[id0.1] matches { normal_range matches { DV_INTERVAL<DV_QUANTITY>[id0.2] } other_reference_ranges matches { REFERENCE_RANGE<DV_QUANTITY>[id0.3] } } } } ELEMENT[id2.2] matches { -- text value value matches { DV_TEXT[id0.4] } } } } |
(Ack: Former user (Deleted) from Core Consulting, Brasilia)
Blood culture (panel) Streptococcus pneumoniae > 100.000 CFU/mL |
This is specifically related to microbiology results, how to deal with analyte elements when the result of the exam is the analyte itself, being a DATA_VALUE for the Result data element? There is no specific analyte being searched (in most cases) in this scenario. How to query?
This is an example of two DATA_VALUEs for the same exam.
(Ack: Former user (Deleted) from Core Consulting, Brasilia)
Urianalysis (panel) (val) (reference) (analyte)Glucose +++ Absent |
This implies a DV_ORDINAL for the value but a code/text for the normal_range and reference_ranges. This could be simulated by using DV_ORDINAL for both, i.e. something like this:
-- ADL2 syntax CLUSTER[id9] matches { items matches { ELEMENT[id2.1] matches { -- quantity value matches { DV_ORDINAL[id0.1] matches { normal_range matches { DV_INTERVAL<DV_ORDINAL>[id0.2] } other_reference_ranges matches { REFERENCE_RANGE<DV_ORDINAL>[id0.3] } } } } } } |
(Ack: Former user (Deleted) from Core Consulting, Brasilia)
In the following, Lab1 is reporting bilirubin as an ordinal with a code or text reference range, while lab 2 is reporting using two codes.
Lab1 Urianalysis (panel) Result Reference range (analyte)Bilirubin +++ Absent Lab2 Urianalysis (panel) Result Reference range (analyte)Bilirubin Moderate Absent |
Result format may vary depending on the analysis result. In urine strips testing, lab interpretation may present results as texts, scales or quantities, in different units. For example, protein analysis may result in "negative", "traces", "++" or "30 mg/dL". All this DATA-VALUES must be allowed in the result element. Not all results are automatic. Some are manual testings
Issue: how to register reference ranges for DV_TEXT, DV_ORDINAL results? Reference ranges often expands the "Normal"/"High" ranges, such as interpretation of clinical risks: cardiovascular risks, diabetes risk. Others may be interpreted as evidence for bacterial infection or viral infection depending on the result value (eg, for C-RP exams). There are examples that includes value ranges for specific interpretations, as: Negative: < 1,6 UI/mL; Indeterminate: 1,60 - 2,0 UI/mL; Positive: >= 3,00 UI/mL.
An example of a template left generic to receive a variety of individual analytes or laboratory panels via a laboratory message can be found at http://openehr.org/ckm/#showTemplate_1013.26.185
An example of a template constructed to represent a lipid profile for use to underpin data-entry or where the exact incoming lipid profile panel is known and consistent, is at http://openehr.org/ckm/#showTemplate_1013.26.69
This example of openEHR data in ‘Structured json’ format, shows how laboratory test names, laboratory result names and values appear in openEHR data. The data format and paths should be identical regardless of whether a UI-driven or message-driven template approach is used.
{ "laboratory_test#1": [ { "test_name": [ { "|code": "51990-0", "|value": "Basic metabolic panel- Blood", "|terminology": "SNOMED-CT" } ], "test_status": [ { "|code": "at0038", "|value": "Final", "|terminology": "local" } ], "test_status_timestamp": [ "2015-04-22T00:11:02.518+02:00" ], "laboratory_test_panel": [ { "laboratory_result#1": [ { "result_value": [ { "_name": [ { "|value": "Urea", "|code": "14937-7", "|terminology": "LOINC" } ], "|magnitude": 7.8, "|unit": "mmol/l", "_normal_range": [ { "lower": [ { "|unit": "mmol/l", "|magnitude": 2.5 } ], "upper": [ { "|unit": "mmol/l", "|magnitude": 6.6 } ] } ] }, ], "comment": [ "may be technical artefact" ] }, ], "laboratory_result#2": [ { "result_value": [ { "_name": [ { "|value": "Creatinine", "|code": "14682-9", "|terminology": "LOINC" } ], "|magnitude": 123, "|unit": "mmol/l", "_normal_range": [ { "lower": [ { "|unit": "mmol/l", "|magnitude": 80 } ], "upper": [ { "|unit": "mmol/l", "|magnitude": 110 } ] } ] } ] }, ], "conclusion": [ "Very rapidly deteriorating renal function" ], } ], "laboratory_test#2": [ { "test_name": [ { "|code": "15074-8", "|value": "Glucose", "|terminology": "LOINC" } ], "test_status": [ { "|code": "at0038", "|value": "Final", "|terminology": "local" } ], "test_status_timestamp": [ "2015-04-22T00:11:02.518+02:00" ], "laboratory_test_panel": [ { "laboratory_result": [ { "result_value": [ { "_name": [ { "|value": "Glucose", "|code": "15074-8", "|terminology": "LOINC" } ], "|magnitude": 4.2, "|unit": "mmol/l", "_normal_range": [ { "lower": [ { "|unit": "mmol/l", "|magnitude": 1.3 } ], "upper": [ { "|unit": "mmol/l", "|magnitude": 6.6 } ] } ] } ] } ], "comment": [ "may be technical artefact" ] } ], "conclusion": [ "Normal for age" ] } ] } |