Appearance
Troponin Alert
This guide walks through an Arden Syntax MLM designed to detect elevated troponin levels from laboratory observations and raise alerts of varying severity.
Troponin is a key biomarker for heart muscle injury, high levels can indicate a heart attack (myocardial infarction). This MLM automates the detection process, classifies the result, and recommends the appropriate next step.
The classification can be one of the following:
- High severity: ≥ 0.40 ng/mL
- Medium severity: 0.05– 0.39 ng/mL
- Low severity: < 0.05 ng/mL
And we want to add extra recommendations if symptoms are less than 3 hours old.
Objects
First we define some objects in our data slot. In Arden Syntax, objects are structured data containers that can hold multiple related values (like a whole observation, a patient and a condition).
arden-syntax
data:
// Define an object for holding related observation, patient & condition
ValidationSet := object [observation, patient, condition];
validation_set := new ValidationSet WITH [
observation := observation1,
patient := patient1,
condition := condition1
];ValidationSet := object [...] defines the blueprint of the object, in our case three separate values combined into one set.
new ValidationSet WITH [...] creates a new object according to that blueprint and WITH clause assigns actual values to each field at creation time.
READ
Now that we have our objects, we want to actually fill them with data. But where do we get that data from? First, we want to get all observations we currently have in our database. To query them we can use the READ instruction. We can do exactly that by just executing only the highlighted row in the example below.
arden-syntax
data:
observations := read as Observation
where it.code.coding.system = "http://snomed.info/sct"
and it.code.coding.code = "313616005"; // Serum troponin I measurementBut these would be way too many. We only want Troponin measurement observations, not every possible Observation in the system. To do that, we add a where clause, this works a bit like a SQL WHERE filter: it it refers to a single potential result from the query. We check properties of it (in this case, the code.coding.system and code.coding.code) against known FHIR standard values. Here, http://snomed.info/sct identifies SNOMED CT as the coding system, and 313616005 is the SNOMED code for "Serum troponin I measurement"
You can combine conditions with logical connectives like and, or, and not, see the Connectives Reference for some more.
TIP
There is also a way to read from non-standardized sources, you can learn about that in the Data Exchange references.
New Concepts
Before we tackle the full example, there are two more handy Arden Syntax features worth knowing, they’ll make the code shorter and easier to read.
List Operators
Arden gives you built-in operators to handle lists without extra fuss. For example, the add operator takes a value and a list, then appends the value to the end. No need to manually resize or index, it just works.
Object-based for Loops
Normally, you might loop with an index variable i and manually fetch each element. But Arden lets you loop directly over objects in a list, which keeps your code clean and avoids juggling counters:
arden-syntax
logic:
validation_sets := add validation_set to validation_sets;
for observation in observations do
// work with an observation directly
enddoFull MLM
Now that we got all necessary components together, you can take a look at the full fleshed MLM here. As a reminder, we wanted a MLM that automates what would otherwise be a manual review of lab reports addressing issues with troponin levels of some patients. There are comments throughout the code to guide you:
arden-syntax
maintenance:
title: Alert - Elevated Troponin;;
mlmname: ALERT_ElevatedTroponin;;
arden: Version 3;;
version: 1.0;;
institution: Medexter Healthcare;;
author: Knowledge Engineering Team;;
specialist: Knowledge Engineering Team;;
date: 2024-01-09;;
validation: production;;
library:
purpose: Look for elevated troponin levels in new tests and raise an alert if one is found;;
explanation: Levels below 0.39 ng/ml are considered non-relevant, 0.39 to 0.40 cause a concern and anything above 0.40 causes an alert;;
keywords: alert, troponin, heart attack;;
citations: ;;
links: ;;
knowledge:
type: data_driven;;
data:
// Define an object for holding related observation, patient & condition
ValidationSet := object [observation, patient, condition];
// Define an object for raising alerts
Alert := object [reason, recommendation, severity];
// Retrieve the latest troponin observations
observations := read as Observation
where it.code.coding.system = "http://snomed.info/sct"
and it.code.coding.code = "313616005";
// For each of these observations, collect the patient and heart attack
// condition, if one is present
validation_sets := ();
for observation in observations do
patient_id := observation.subject.reference;
// Retrieve the associated patient
patient := read as latest Patient where it.id = patient_id;
// Retrieve the associated condition, if there is one
condition := read as latest Condition
where it.code.coding.system = "http://snomed.info/sct"
and it.code.coding.code = "22298006"; // Heart attack
// Assemble into a validation set
validation_set := new ValidationSet WITH [
observation := observation,
patient := patient,
condition := condition
];
validation_sets := add validation_set to validation_sets;
enddo;
;;
priority: 50;;
evoke: ;;
logic:
alerts := ();
for validation_set in validation_sets do
observation := validation_set.observation;
patient := validation_set.patient;
condition := validation_set.condition;
// Extract the troponin measurement from the observation
troponin := observation.valueQuantity.value;
// If the value is severe, raise an alert
if troponin >= 0.4 then
reason := "Troponin value of patient " || patient.name[1].family ||
" at " || troponin || " ng/mL is severely elevated (>= 0.40)";
recommendation := "Treat according to red pathway.";
severity := "high";
else
// If the value is not immediate cause for concern, rate whether
// it is slightly elevated
if troponin < 0.4 and troponin >= 0.05 then
reason := "Troponin value of patient " || patient.name[1].family ||
" at " || troponin || " ng/mL is slightly elevated (0.05 - 0.39)";
recommendation := "Perform treatment according to yellow pathway.";
severity := "medium";
else
reason := "Troponin value of patient " || patient.name[1].family ||
" at " || troponin || " ng/mL is within normal range (< 0.05)";
recommendation := "No immediate intervention is required.";
severity := "low";
endif;
// Check if the heart attack symptoms are less than 3 hours old
// and if yes, recommend a re-test at that time
retest_time := 3 hours after condition.onsetDateTime;
if observation.effectiveDateTime is before retest_time then
recommendation := recommendation || " Re-test at " || retest_time;
endif;
endif;
// Add the alert and possible retest recommendation to the output
alert := new Alert with [
reason := reason,
recommendation := recommendation,
severity := severity
];
alerts := add alert to alerts;
enddo;
conclude true;
;;
action:
return alerts;
;;
urgency: 50;;
resources:
default: en;;
language: en;;
end:Summing up, we now know about:
- Objects in Arden Syntax
- Some list operators and where to find more
- Object-based
FORloops