- Created by Peter Scott, last modified on Aug 28, 2024
Overview
We will move on to write two new GELLO modules. In the first we will do a simple result that returns a text message for flagging an asthmatic patient receiving too many "reliever" metered aerosol puffers in a space of time and suggesting additional 'preventer' therapy. The second will make use of the Past history class in the VMR in the diagnosis of a unilateral red eye.
Asthma example
The time has come to use a larger data file. Save the following as thirdTest.xml . Note we are adding flesh to the bones of this patient's EHR/VMR and now we have two illnesses and some medications. [The VMR allows both a problem list and a past history list. We will stick with Past History for now but we could equally be populating the problem list if we preferred.]
<?xml version="1.0" encoding="UTF-8"?>
<singlePatient xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./iso-21090-datatypes.xsd">
<patient>
<patientID
root="1.2.36.174030967"
extension="1234567892"
reliability="VRF"
scope="OBJ"/>
<patientName>
<part type="GIV" value="Alice" />
<part type="GIV" value="A." />
<part type="FAM" value="Someone" />
</patientName>
<dob value="19550621"/>
<gender code="248152002"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Female" />
</gender>
<ssn value="987-65-4320"/>
<address use="WP">
<part type="AL" value="1050 W Wishard Blvd" />
<part type="CTY" value="Indianapolis" />
<part type="STA" value="IN" />
<part type="ZIP" value="46240" />
</address>
</patient>
<allergies>
<allergenType code="373873005"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "pharmaceutical / biologic product" />
</allergenType>
<allergenCode code="111088007"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "latex (product)" />
</allergenCode>
<allergySeverity code="24484000"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "severe" />
</allergySeverity>
<allergyReaction code="39579001"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "anaphylaxis" />
</allergyReaction>
<identificationDate value="1980"/>
</allergies>
<allergies>
<allergenType code="373873005"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "pharmaceutical / biologic product" />
</allergenType>
<allergenCode code="27658006"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Amoxicillin" />
</allergenCode>
<allergySeverity code="24484000"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "severe" />
</allergySeverity>
<allergyReaction code="39579001"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "anaphylaxis" />
</allergyReaction>
<identificationDate value="1980"/>
</allergies>
<historyOfPastIllness>
<pastIllness code="302914006"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Barrett's esophagus" />
</pastIllness>
<temporalContext code="410587003"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Past - specified" />
</temporalContext>
<illnessDates>
<!--IVL_TS -->
<low value="2000" />
</illnessDates>
<notesOnIllness></notesOnIllness>
</historyOfPastIllness>
<historyOfPastIllness>
<pastIllness code="195967001"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Asthma" />
</pastIllness>
<temporalContext code="410587003"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Past - specified" />
</temporalContext>
<illnessDates>
<!--IVL_TS -->
<low value="2005" />
</illnessDates>
<notesOnIllness></notesOnIllness>
</historyOfPastIllness>
<medications>
<currentMedications>
<!--1-->
<medicationCode code="317334001"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Esomeprazole 40mg tablet" />
<translation code="606731"
codeSystem="2.16.840.1.113883.6.88"
codeSystemName="RxNorm">
<displayName value = "Esomeprazole 40 MG Delayed Release Oral Capsule [Nexium]" />
</translation>
</medicationCode>
<dosingSig code="229797004"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Once daily" />
</dosingSig>
<requestedGiveRate></requestedGiveRate><!--PQ eg 100mls an hour-->
<medicationStartDate value="20160128" />
<medicationStopdate> </medicationStopdate>
<totalDailyDose> </totalDailyDose>
<reasonForCessation> </reasonForCessation>
<indication code="302914006"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Barrett's esophagus" />
</indication>
<replacedBy> </replacedBy>
</currentMedications>
<!--2-->
<currentMedications>
<medicationCode code="376928006"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Albuterol 90mcg/inh aerosol" />
<translation code="801905"
codeSystem="2.16.840.1.113883.6.88"
codeSystemName="RxNorm">
<displayName value = "60 ACTUAT Albuterol 0.09 MG/ACTUAT Metered Dose Inhaler [Ventolin]" />
</translation>
</medicationCode>
<dosingSig code="25761000"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "As required" />
</dosingSig>
<medicationStartDate value="20160426" />
</currentMedications>
<!--3-->
<currentMedications>
<medicationCode code="376928006"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Albuterol 90mcg/inh aerosol" />
<translation code="801905"
codeSystem="2.16.840.1.113883.6.88"
codeSystemName="RxNorm">
<displayName value = "60 ACTUAT Albuterol 0.09 MG/ACTUAT Metered Dose Inhaler [Ventolin]" />
</translation>
</medicationCode>
<dosingSig code="25761000"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "As required" />
</dosingSig>
<medicationStartDate value="20160502" />
</currentMedications>
<!--4-->
<currentMedications>
<medicationCode code="376928006"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Albuterol 90mcg/inh aerosol" />
<translation code="801905"
codeSystem="2.16.840.1.113883.6.88"
codeSystemName="RxNorm">
<displayName value = "60 ACTUAT Albuterol 0.09 MG/ACTUAT Metered Dose Inhaler [Ventolin]" />
</translation>
</medicationCode>
<dosingSig code="25761000"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "As required" />
</dosingSig>
<medicationStartDate value="20160516" />
</currentMedications>
</medications>
</singlePatient>
Load this data into the editor as outlined in previous tutorials. Notice the new data we have added.
Start as usual:
Context HL7_v2_VMR_V1::SinglePatient
Does the patient have asthma?:
Let Asthma:CD = factory.CD_SNOMED('195967001', 'Asthma')
Let hasAsthma: Boolean = historyOfPastIllness -> exists(pastIllness.implies(Asthma).value)
[Note these two lines are subtly different to previous examples but work just as well - there is more than one way to do things - can you spot the differences?]
Look for albuterol ('reliever' puffer) scripts:
Let albuterol90_SCT:CD = factory.CD_SNOMED_CT('376928006')
Let allAbuterolScripts = medications.currentMedications->select(medicationCode.implies(albuterol90_SCT).value)
Get the medication start dates for these scripts:
Let allAlbuterolMAScriptdates: Sequence(TS) = allAbuterolScripts
->select(medicationCode.implies(albuterol90_SCT).value).medicationStartDate
Get last two dates:
Let mostRecentAlbuterolDate: TS = allAlbuterolMAScriptdates->last()
Let penultimateAlbuterolDate: TS = If mostRecentAlbuterolDate.oclIsDefined() then
allAlbuterolMAScriptdates.excluding(mostRecentAlbuterolDate)->last()
else null
endif
Get the time between them:
Let timeGap:PQ = mostRecentAlbuterolDate - penultimateAlbuterolDate
Let timeGapInDays: PQ = timeGap.convert('d')
Run the final expression that returns the message if any:
If timeGapInDays.oclIsDefined() then
If timeGapInDays < factory.PQ(21,'d') then 'Patient may be relying excessively on a reliever puffer, suggest consider addition of a preventer medication'
else ''
endif
else ''
endif
The red eye
Now let’s consider an example whereby something in the patient’s past history can assist in the diagnosis of a new problem. A common problem for clinicians is that of the unilateral (one sided) red eye. As ever in medicine, often it is a simple issue such as irritation or the early phases of a virus infection such as adenovirus; but occasionally it’s a serious disorder such as acute iritis, which can cause vision loss if not picked up. Let’s add some data to thirdTest.xml and then do the worked example.
Add the following in between </patient> and <allergies>, should be about line 28 (line 56 if your file has become double spaced), save:
<historyOfPresentingComplaint>
<chiefComplaint code="75705005"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "red eye" />
</chiefComplaint>
<dateOfOnset value ="20160601" />
<notes value = " Presents with very painful unilateral red eye and decreased vision. " ></notes>
</historyOfPresentingComplaint>
And add this section to a space made just above <medications> and save:
</historyOfPastIllness>
<historyOfPastIllness>
<pastIllness code="64766004"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "ulcerative colitis" />
</pastIllness>
<temporalContext code="410587003"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED-CT">
<displayName value = "Past - specified" />
</temporalContext>
<illnessDates>
<!--IVL_TS -->
<low value="2008" />
</illnessDates>
<notesOnIllness></notesOnIllness>
</historyOfPastIllness>
Iritis is sometimes associated with other diseases including but not limited to lupus, psoriatic arthritis, ankylosing spondylitis, sarcoidosis, inflammatory bowel disease, rheumatoid arthritis, toxoplasmosis, histoplasmosis, tuberculosis, syphilis and the presence of the HLAB27 antigen. So let’s write some code that looks for these and in the presence of a red eye flags a warning. The result of this GELLO code will be a Tuple that includes a weighting on the importance of the warning message.
Here’s the code:
Context HL7_v2_VMR_V1::SinglePatient
Let hasPastIllnessOfAssociatedIllnessOfIritis: Boolean =
historyOfPastIllness->exists(pastIllness.implies(factory.CD_SNOMED('200936003', 'lupus')).value or
pastIllness.implies(factory.CD_SNOMED('156370009', 'psoriatic arthritis')).value or
pastIllness.implies(factory.CD_SNOMED('9014002', 'psoriasis')).value or
pastIllness.implies(factory.CD_SNOMED('9631008', 'ankylosing spondylitis')).value or
pastIllness.implies(factory.CD_SNOMED('31541009', 'sarcoidosis')).value or
pastIllness.implies(factory.CD_SNOMED('64766004', 'ulcerative colitis')).value or
pastIllness.implies(factory.CD_SNOMED('34000006', 'crohns disease')).value or
pastIllness.implies(factory.CD_SNOMED('69896004', 'rheumatoid arthritis')).value or
pastIllness.implies(factory.CD_SNOMED('712680005', 'Human leukocyte antigen B27 test positive')).value or
pastIllness.implies(factory.CD_SNOMED('187192000', 'toxoplasmosis')).value or
pastIllness.implies(factory.CD_SNOMED('12962009', 'histoplasmosis')).value or
pastIllness.implies(factory.CD_SNOMED('56717001', 'tuberculosis')).value or
pastIllness.implies(factory.CD_SNOMED('76272004', 'syphilus')).value or
pastIllness.implies(factory.CD_SNOMED('4740000', 'shingles')).value)
Let presentingComplaintIsRedEyeOrSimilar : Boolean =
historyOfPresentingComplaint.chiefComplaint.implies(factory.CD_SNOMED('75705005', 'red eye')).value
-- there are a few more choices in snomed ct, so keep going
or historyOfPresentingComplaint.chiefComplaint.implies(factory.CD_SNOMED('703630003', 'red eye')).value
or historyOfPresentingComplaint.chiefComplaint.implies(factory.CD_SNOMED('78370002', 'scleritis')).value
or historyOfPresentingComplaint.chiefComplaint.implies(factory.CD_SNOMED('128473001', 'uveitis')).value
Let text: String = If presentingComplaintIsRedEyeOrSimilar and hasPastIllnessOfAssociatedIllnessOfIritis
then 'past Illness history and presenting complaint suggests acute iritis. Consider urgent ophthalmological review.'
else ''
endif
Let result = Tuple {warningImportance = 'high',
warningUrgency = 'urgent',
splashText = text
}
result
Now remember this example is simply that - an example, it would need more refinement and many committee meetings with clinicians to get it right - for example the shingles would need to be current or recent- and we could get at that by the illness dates. We won't touch the topic of laterality of the concept in this tutorial either!
But the point of this second example is to illustrate the potential power of a suite of hundreds of installed GELLO expressions, quietly running in the background and then triggering a warning or a message when conditions are ripe.
That's the end of this tutorial.
- No labels