Skip to content

Commit

Permalink
CQL development updates (#14)
Browse files Browse the repository at this point in the history
* 13-18 done. 14 needs some more work based off of bryn's comments. 17 is not in DAK. (#34)

* WSG-76 Added Elements.cql files and updated Libraries (#35)

Co-authored-by: Patric Prado <pprado@caa.columbia.edu>
  • Loading branch information
pmanko and Pprado23 authored Jul 22, 2024
1 parent 4995b51 commit a2b0687
Show file tree
Hide file tree
Showing 22 changed files with 29,637 additions and 44 deletions.
230 changes: 225 additions & 5 deletions input/cql/HIVCommon.cql
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ using FHIR version '4.0.1'

include FHIRHelpers version '4.0.1'
include WHOCommon called WCom
include FHIRCommon called FC
//include FHIRCommon called FC
include HIVConcepts called HC
include HIVConceptsCustom called HCC

parameter "Measurement Period" Interval<Date> default Interval[@2020-01-01, @2020-12-31]
parameter "Measurement Date" Date default @2020-01-01

context Patient

Expand Down Expand Up @@ -123,12 +124,58 @@ define "Needle Syringe Dispensed":
and O.value ~ HC."People who inject drugs - HIV.B.DE54"
where DUS.status = 'completed'

define PWID_person:
[Observation: HC."Key population member* - HIV.E.DE113"] O
where O.status in { 'final', 'amended', 'corrected' }
define PWID_person:
[Observation: HC."Key population member* - HIV.E.DE113"] O
where O.status in { 'final', 'amended', 'corrected' }
and exists(O.category OC where OC ~ HCC."social-history")
and O.value ~ HC."People who inject drugs - HIV.B.DE54"

define "OAMT_initiated":
exists(
[EpisodeOfCare] EOC
where exists(EOC.type T where T ~ HC."OAMT")
and (exists (
EOC.statusHistory H
where H.period starts after start of "Measurement Period"
and H.period starts before end of "Measurement Period"
)
or (
EOC.period starts after start of "Measurement Period"
and EOC.period starts before end of "Measurement Period"
)
)
)

define "OAMT_retained":
exists(
[EpisodeOfCare] EOC
where exists(EOC.type T where T ~ HC."OAMT")
and (exists (
EOC.statusHistory H
where H.period starts after start of "Measurement Period"
and H.period starts before end of "Measurement Period"
and H.period ends after (end of "Measurement Period" + 6 months)
)
or (
EOC.period starts after start of "Measurement Period"
and EOC.period starts before end of "Measurement Period"
and (EOC.period ends after (end of "Measurement Period" + 6 months)
or end of EOC.period is null)
)
)
)

define "methadone_prescribed":
[MedicationRequest] MR
where MR.status = 'completed'
and MR.intent = 'order'
and MR.medication ~ HCC."methadone"

define "buprenorphine_prescribed":
[MedicationRequest] MR
where MR.status = 'completed'
and MR.intent = 'order'
and MR.medication ~ HCC."buprenorphine"

define "Patient Deceased before end of Measurement Period":
case
Expand Down Expand Up @@ -237,6 +284,13 @@ define "By Administrative Gender Stratifier":
else HC."Other - HIV.A.DE23"
end

define "HIV Status":
case
when exists("HIV Positive Condition" C where C.onset before end of "Measurement Period") then HC."HIV-positive - HIV.B.DE116"
when not exists("HIV Positive Condition" C where C.onset before end of "Measurement Period") and exists("HIV Negative Observation" O where O.issued before end of "Measurement Period") then HC."HIV-negative - HIV.B.DE117"
else HC."Unknown - HIV.B.DE118"
end

/*
* Key populations (men who have sex with men, people living in prisons and other closed settings, people who inject drugs, sex workers, trans and gender diverse people)
*/
Expand Down Expand Up @@ -579,4 +633,170 @@ define function "Prescription Relevant Period"(prescription FHIR.MedicationReque
date from prescription.authoredOn,
date from prescription.authoredOn + System.Quantity{ value: GetDurationInDays(prescription.dispenseRequest.expectedSupplyDuration), unit: 'days' }
]
else null
else null

//System.Integer
define function ToDaily(frequency System.Integer, period System.Quantity):
case period.unit
when 'h' then frequency * (24.0 / period.value)
when 'min' then frequency * (24.0 / period.value) * 60
when 's' then frequency * (24.0 / period.value) * 60 * 60
when 'd' then frequency * (24.0 / period.value) / 24
when 'wk' then frequency * (24.0 / period.value) / (24 * 7)
when 'mo' then frequency * (24.0 / period.value) / (24 * 30) /* assuming 30 days in month */
when 'a' then frequency * (24.0 / period.value) / (24 * 365) /* assuming 365 days in year */
when 'hour' then frequency * (24.0 / period.value)
when 'minute' then frequency * (24.0 / period.value) * 60
when 'second' then frequency * (24.0 / period.value) * 60 * 60
when 'day' then frequency * (24.0 / period.value) / 24
when 'week' then frequency * (24.0 / period.value) / (24 * 7)
when 'month' then frequency * (24.0 / period.value) / (24 * 30) /* assuming 30 days in month */
when 'year' then frequency * (24.0 / period.value) / (24 * 365) /* assuming 365 days in year */
when 'hours' then frequency * (24.0 / period.value)
when 'minutes' then frequency * (24.0 / period.value) * 60
when 'seconds' then frequency * (24.0 / period.value) * 60 * 60
when 'days' then frequency * (24.0 / period.value) / 24
when 'weeks' then frequency * (24.0 / period.value) / (24 * 7)
when 'months' then frequency * (24.0 / period.value) / (24 * 30) /* assuming 30 days in month */
when 'years' then frequency * (24.0 / period.value) / (24 * 365) /* assuming 365 days in year */
else null
end

define function "HasEnd"(period Interval<DateTime> ):
not (end of period is null
or end of period = maximum DateTime
)

define function MedicationRequestPeriod(Request "MedicationRequest"):
Request R
let
dosage: singleton from R.dosageInstruction,
doseAndRate: singleton from dosage.doseAndRate,
doseRange: doseAndRate.dose as Range,
doseQuantity: doseAndRate.dose as SimpleQuantity,
dose: Coalesce(end of doseRange, doseQuantity),
timing: dosage.timing,
frequency: Coalesce(timing.repeat.frequencyMax, timing.repeat.frequency),
period: System.Quantity { value: timing.repeat.period, unit: timing.repeat.periodUnit.value },
dosesPerDay: Coalesce(ToDaily(FHIRHelpers.ToInteger(frequency), period), Count(timing.repeat.timeOfDay), 1.0),
boundsPeriod: timing.repeat.bounds as Period,
daysSupply: R.dispenseRequest.expectedSupplyDuration,
quantity: R.dispenseRequest.quantity,
refills: Coalesce(R.dispenseRequest.numberOfRepeatsAllowed, 0),
startDate:
Coalesce(
start of boundsPeriod,
start of R.dispenseRequest.validityPeriod,
R.authoredOn
)
return
if HasEnd(boundsPeriod) then
Interval[startDate, end of boundsPeriod]
else
(
Coalesce(daysSupply, quantity / (dose * dosesPerDay))
* (1 + refills)
) durationInDays
return Interval[startDate, startDate + durationInDays]


define function "DosesPerDay"(frequency Code):
/*Calculates the cumulative dose per day for each prescription*/
case
when frequency ~ HCC."Once daily (qualifier value)" then 1.0
when frequency ~ HCC."Twice a day (qualifier value)" then 2.0
when frequency ~ HCC."Three times daily (qualifier value)" then 3.0
when frequency ~ HCC."Four times daily (qualifier value)" then 4.0
when frequency ~ HCC."Every twenty four hours (qualifier value)" then 1.0
when frequency ~ HCC."Every twelve hours (qualifier value)" then 2.0
when frequency ~ HCC."Every thirty six hours (qualifier value)" then 0.67
when frequency ~ HCC."Every eight hours (qualifier value)" then 3.0
when frequency ~ HCC."Every four hours (qualifier value)" then 6.0
when frequency ~ HCC."Every six hours (qualifier value)" then 4.0
when frequency ~ HCC."Every seventy two hours (qualifier value)" then 0.34
when frequency ~ HCC."Every forty eight hours (qualifier value)" then 0.5
when frequency ~ HCC."Every eight to twelve hours (qualifier value)" then 2.0
when frequency ~ HCC."Every six to eight hours (qualifier value)" then 3.0
when frequency ~ HCC."Every three to four hours (qualifier value)" then 6.0
when frequency ~ HCC."Every three to six hours (qualifier value)" then 4.0
when frequency ~ HCC."Every two to four hours (qualifier value)" then 6.0
when frequency ~ HCC."One to four times a day (qualifier value)" then 4.0
when frequency ~ HCC."One to three times a day (qualifier value)" then 3.0
when frequency ~ HCC."One to two times a day (qualifier value)" then 2.0
else null
end

//define function "GetMedicationDailyDose"(dosage Quantity, dosesPerDay Decimal):
//dosage * Quantity { value: dosesPerDay, unit: '/d' }


define "methadone_prescribed at date":
[MedicationRequest] MR
where MR.status = 'completed'
and MR.intent = 'order'
and MR.medication ~ HCC."methadone"
//and "GetMedicationDailyDose"(MR.dosageInstruction, "DosesPerDay"(singleton from MR.dosageInstruction.timing.repeat.frequencyMax)) >= 60 'mg/d'
and MedicationRequestPeriod(MR) starts before "Measurement Date"
and MedicationRequestPeriod(MR) ends after "Measurement Date"

define "VMMC_done":
[Procedure] P
where P.status = 'completed'
and P.code ~ HC."Voluntary medical male circumcision VMMC"

define "VMMC_adverse_event":
[AdverseEvent] AE
with [Procedure] P
such that AE.suspectEntity.instance.references(P) and P.status = 'completed'
and P.code ~ HC."Voluntary medical male circumcision VMMC"
and P.performed after start of "Measurement Period"
and P.performed before end of "Measurement Period"
and AE.date <= (P.performed + 30 days)
and AE.date >= (P.performed)
where AE.actuality = 'actual'

define "VMMC_adverse_event_type":
case
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Abnormal pain") then HC."Abnormal pain"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Anaesthesia-related effects") then HC."Anaesthesia-related effects"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Damage to the penis") then HC."Damage to the penis"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Difficulty urinating") then HC."Difficulty urinating"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Excessive bleeding") then HC."Excessive bleeding"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Excessive skin removal") then HC."Excessive skin removal"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Excessive swelling") then HC."Excessive swelling"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Haematoma") then HC."Haematoma"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Infection") then HC."Infection"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Injury to glans") then HC."Injury to glans"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Scar or disfigurement") then HC."Scar or disfigurement"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Sharps injury to personnel") then HC."Sharps injury to personnel"
when exists("VMMC_adverse_event" AE where AE.event ~ HC."Wound disruption") then HC."Wound disruption"
else HC."Other - HIV.B.DE222"
end

define "VMMC_adverse_event_Intraoperative":
[AdverseEvent] AE
with [Procedure] P
such that AE.suspectEntity.instance.references(P) and P.status = 'completed'
and P.code ~ HC."Voluntary medical male circumcision VMMC"
and P.performed after start of "Measurement Period"
and P.performed before end of "Measurement Period"
and AE.date = P.performed
where AE.actuality = 'actual'

define "VMMC_adverse_event_Postoperative":
[AdverseEvent] AE
with [Procedure] P
such that AE.suspectEntity.instance.references(P) and P.status = 'completed'
and P.code ~ HC."Voluntary medical male circumcision VMMC"
and P.performed after start of "Measurement Period"
and P.performed before end of "Measurement Period"
and AE.date <= (P.performed + 30 days)
and AE.date > (P.performed)
where AE.actuality = 'actual'

define "VMMC_adverse_event_timing":
case
when exists(VMMC_adverse_event_Intraoperative) then HC."Intraoperative"
when exists(VMMC_adverse_event_Postoperative) then HC."Postoperative"
else null
end
2 changes: 2 additions & 0 deletions input/cql/HIVConcepts.cql
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ valueset "HCV medicine type Choices": 'http://smart.who.int/hiv/ValueSet/HIV.D.D
valueset "HIV clinical stage - HIV.D.DE186 Choices": 'http://smart.who.int/hiv/ValueSet/HIV.D.DE186'
valueset "Reason ART stopped - HIV.D.DE217 Choices": 'http://smart.who.int/hiv/ValueSet/HIV.D.DE217'
valueset "Treatment failure Choices": 'http://smart.who.int/hiv/ValueSet/HIV.D.DE225'
valueset "Risk factors, comorbidities and coinfections signs and symptoms Choices": 'http://smart.who.int/hiv/ValueSet/HIV.D.DE259'
valueset "WHO HIV clinical stage condition or symptom - HIV.D.DE289 Choices": 'http://smart.who.int/hiv/ValueSet/HIV.D.DE289'
valueset "Time to start ART Choices": 'http://smart.who.int/hiv/ValueSet/HIV.D.DE383'
valueset "Reason for HIV viral load test Choices": 'http://smart.who.int/hiv/ValueSet/HIV.D.DE391'
Expand Down Expand Up @@ -572,6 +573,7 @@ code "Treatment failure": 'HIV.D.DE225' from "HIVConcepts" display 'Treatment fa
code "Clinical failure": 'HIV.D.DE226' from "HIVConcepts" display 'Clinical failure'
code "Immunological failure": 'HIV.D.DE227' from "HIVConcepts" display 'Immunological failure'
code "Virological failure": 'HIV.D.DE228' from "HIVConcepts" display 'Virological failure'
code "Risk factors, comorbidities and coinfections signs and symptoms": 'HIV.D.DE259' from "HIVConcepts" display 'Risk factors, comorbidities and coinfections signs and symptoms'
code "Presumptive TB - HIV.D.DE282": 'HIV.D.DE282' from "HIVConcepts" display 'Presumptive TB'
code "WHO HIV clinical stage condition or symptom - HIV.D.DE289": 'HIV.D.DE289' from "HIVConcepts" display 'WHO HIV clinical stage condition or symptom'
code "Asymptomatic": 'HIV.D.DE290' from "HIVConcepts" display 'Asymptomatic'
Expand Down
34 changes: 34 additions & 0 deletions input/cql/HIVConceptsCustom.cql
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ codesystem "ConditionClinicalStatusCodes": 'http://terminology.hl7.org/CodeSyste
codesystem "ObservationCategoryCodes": 'http://terminology.hl7.org/CodeSystem/observation-category'
codesystem "missing concepts": 'missing concepts'
codesystem "Devicestatement-status": 'http://hl7.org/fhir/ValueSet/device-statement-status'
codesystem "SNOMEDCT:2018-03": 'urn:oid:2.16.840.1.113883.6.96' version 'urn:hl7:version:2018-03'
codesystem "SNOMEDCT": 'urn:oid:2.16.840.1.113883.6.96'
codesystem "AdverseEventSeverity": 'http://hl7.org/fhir/ValueSet/adverse-event-severity'

code "encounter-diagnosis": 'encounter-diagnosis' from "ConditionCategoryCodes" display 'Encounter Diagnosis'

Expand All @@ -22,6 +25,37 @@ code "social-history": 'social-history' from "ObservationCategoryCodes" display
//Device statement status
code "completed": 'completed' from "Devicestatement-status"

//adverse event severity
code "mild": 'mild' from "AdverseEventSeverity"
code "moderate": 'moderate' from "AdverseEventSeverity"
code "severe": 'severe' from "AdverseEventSeverity"

//frequency
code "Every eight hours (qualifier value)": '307469008' from "SNOMEDCT:2018-03" display 'Every eight hours (qualifier value)'
code "Every eight to twelve hours (qualifier value)": '396140003' from "SNOMEDCT" display 'Every eight to twelve hours (qualifier value)'
code "Every forty eight hours (qualifier value)": '396131002' from "SNOMEDCT:2018-03" display 'Every forty eight hours (qualifier value)'
code "Every four hours (qualifier value)": '225756002' from "SNOMEDCT" display 'Every four hours (qualifier value)'
code "Every seventy two hours (qualifier value)": '396143001' from "SNOMEDCT:2018-03" display 'Every seventy two hours (qualifier value)'
code "Every six hours (qualifier value)": '307468000' from "SNOMEDCT:2018-03" display 'Every six hours (qualifier value)'
code "Every six to eight hours (qualifier value)": '396139000' from "SNOMEDCT" display 'Every six to eight hours (qualifier value)'
code "Every thirty six hours (qualifier value)": '396126004' from "SNOMEDCT:2018-03" display 'Every thirty six hours (qualifier value)'
code "Every three to four hours (qualifier value)": '225754004' from "SNOMEDCT" display 'Every three to four hours (qualifier value)'
code "Every three to six hours (qualifier value)": '396127008' from "SNOMEDCT" display 'Every three to six hours (qualifier value)'
code "Every twelve hours (qualifier value)": '307470009' from "SNOMEDCT:2018-03" display 'Every twelve hours (qualifier value)'
code "Every twenty four hours (qualifier value)": '396125000' from "SNOMEDCT:2018-03" display 'Every twenty four hours (qualifier value)'
code "Every two to four hours (qualifier value)": '225752000' from "SNOMEDCT" display 'Every two to four hours (qualifier value)'
code "Four times daily (qualifier value)": '307439001' from "SNOMEDCT:2018-03" display 'Four times daily (qualifier value)'
code "Once daily (qualifier value)": '229797004' from "SNOMEDCT:2018-03" display 'Once daily (qualifier value)'
code "One to four times a day (qualifier value)": '396109005' from "SNOMEDCT" display 'One to four times a day (qualifier value)'
code "One to three times a day (qualifier value)": '396108002' from "SNOMEDCT" display 'One to three times a day (qualifier value)'
code "One to two times a day (qualifier value)": '396107007' from "SNOMEDCT" display 'One to two times a day (qualifier value)'
code "Three times daily (qualifier value)": '229798009' from "SNOMEDCT:2018-03" display 'Three times daily (qualifier value)'
code "Twice a day (qualifier value)": '229799001' from "SNOMEDCT:2018-03" display 'Twice a day (qualifier value)'
code "Two to four times a day (qualifier value)": '396111001' from "SNOMEDCT" display 'Two to four times a day (qualifier value)'


//not currently provided
code "needle-syringe": 'needle syringe' from "missing concepts"
code "methadone": 'methadone' from "missing concepts"
code "buprenorphine": 'buprenorphine' from "missing concepts"

Loading

0 comments on commit a2b0687

Please sign in to comment.