Skip to content

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 measurement

But 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
    enddo

Full 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 FOR loops