Library Name |
Name |
SupplementalDataElements |
SDE Sex |
|
define "SDE Sex":
case
when Patient.gender = 'male' then Code { code: 'M', system: 'http://hl7.org/fhir/v3/AdministrativeGender', display: 'Male' }
when Patient.gender = 'female' then Code { code: 'F', system: 'http://hl7.org/fhir/v3/AdministrativeGender', display: 'Female' }
else null
end
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
SDE Sex |
|
define "SDE Sex":
SDE."SDE Sex"
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Qualifying Systolic Blood Pressure Reading |
|
define "Qualifying Systolic Blood Pressure Reading":
( ( ["observation-bp"] ).isObservationBP ( ) ) BloodPressure
where ( not ( ( BloodPressure.encounter.getEncounter ( ) ).class.code in { 'EMER', 'IMP', 'ACUTE', 'NONAC', 'PRENC', 'SS' } ) )
and BloodPressure.effective.latest ( ) during day of "Measurement Period"
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Qualifying Diastolic Blood Pressure Reading |
|
define "Qualifying Diastolic Blood Pressure Reading":
( ( ["observation-bp"] ).isObservationBP ( ) ) BloodPressure
where ( not ( ( BloodPressure.encounter.getEncounter ( ) ).class.code in { 'EMER', 'IMP', 'ACUTE', 'NONAC', 'PRENC', 'SS' } ) )
and BloodPressure.effective.latest ( ) during day of "Measurement Period"
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Blood Pressure Days |
|
define "Blood Pressure Days":
( "Qualifying Diastolic Blood Pressure Reading" DBPExam
return date from DBPExam.effective.latest ( )
)
intersect ( "Qualifying Systolic Blood Pressure Reading" SBPExam
return date from SBPExam.effective.latest ( )
)
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Most Recent Blood Pressure Day |
|
define "Most Recent Blood Pressure Day":
Last("Blood Pressure Days" BPDays
sort asc
)
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Lowest Systolic Reading on Most Recent Blood Pressure Day |
|
define "Lowest Systolic Reading on Most Recent Blood Pressure Day":
First("Qualifying Systolic Blood Pressure Reading" SBPReading
where SBPReading.effective.latest() same day as "Most Recent Blood Pressure Day"
return singleton from(SBPReading.component SBPComponent
where SBPComponent.code ~ "Systolic blood pressure"
return SBPComponent.value as Quantity
)
sort asc
)
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Has Systolic Blood Pressure Less Than 140 |
|
define "Has Systolic Blood Pressure Less Than 140":
"Lowest Systolic Reading on Most Recent Blood Pressure Day" < 140 'mm[Hg]'
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Lowest Diastolic Reading on Most Recent Blood Pressure Day |
|
define "Lowest Diastolic Reading on Most Recent Blood Pressure Day":
First("Qualifying Diastolic Blood Pressure Reading" DBPReading
where DBPReading.effective.latest() same day as "Most Recent Blood Pressure Day"
return singleton from(DBPReading.component DBPComponent
where DBPComponent.code ~ "Diastolic blood pressure"
return DBPComponent.value as Quantity
)
sort asc
)
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Has Diastolic Blood Pressure Less Than 90 |
|
define "Has Diastolic Blood Pressure Less Than 90":
"Lowest Diastolic Reading on Most Recent Blood Pressure Day" < 90 'mm[Hg]'
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Numerator |
|
define "Numerator":
"Has Systolic Blood Pressure Less Than 140"
and "Has Diastolic Blood Pressure Less Than 90"
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Essential Hypertension Diagnosis |
|
define "Essential Hypertension Diagnosis":
( [Condition: "Essential Hypertension"] ) Hypertension
where Hypertension.prevalenceInterval ( ) overlaps Interval[start of "Measurement Period", start of "Measurement Period" + 6 months )
|
Library Name |
Name |
AdultOutpatientEncounters |
Qualifying Encounters |
|
define "Qualifying Encounters":
( ( [Encounter: "Office Visit"]
union [Encounter: "Annual Wellness Visit"]
union [Encounter: "Preventive Care Services Established Office Visit, 18 and Up"]
union [Encounter: "Preventive Care Services Initial Office Visit, 18 and Up"]
union [Encounter: "Home Healthcare Services"]
union [Encounter: "Online Assessments"]
union [Encounter: "Telephone Visits"] ).isEncounterPerformed() ) ValidEncounter
where ValidEncounter.period.toInterval() during day of "Measurement Period"
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Initial Population |
|
define "Initial Population":
AgeInYearsAt(date from
end of "Measurement Period"
) in Interval[18, 85]
and exists "Essential Hypertension Diagnosis"
and exists AdultOutpatientEncounters."Qualifying Encounters"
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Denominator |
|
define "Denominator":
"Initial Population"
|
Library Name |
Name |
SupplementalDataElements |
SDE Payer |
|
define "SDE Payer":
[Coverage: type in "Payer Type"] Payer
return {
code: Payer.type,
period: Payer.period
}
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
SDE Payer |
|
define "SDE Payer":
SDE."SDE Payer"
|
Library Name |
Name |
SupplementalDataElements |
SDE Ethnicity |
|
define "SDE Ethnicity":
Patient.ethnicity E
return Tuple {
codes: { E.ombCategory } union E.detailed,
display: E.text
}
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
SDE Ethnicity |
|
define "SDE Ethnicity":
SDE."SDE Ethnicity"
|
Library Name |
Name |
Hospice |
Has Hospice Services |
|
define "Has Hospice Services":
exists ((([Encounter: "Encounter Inpatient"]).isEncounterPerformed()) InpatientEncounter
where (InpatientEncounter.hospitalization.dischargeDisposition ~ "Discharge to home for hospice care (procedure)"
or InpatientEncounter.hospitalization.dischargeDisposition ~ "Discharge to healthcare facility for hospice care (procedure)"
)
and InpatientEncounter.period.toInterval() ends during day of "Measurement Period"
)
or exists ((([Encounter: "Hospice Encounter"]).isEncounterPerformed()) HospiceEncounter
where HospiceEncounter.period.toInterval() overlaps day of "Measurement Period"
)
or exists ((([Observation: "Hospice care [Minimum Data Set]"]).isAssessmentPerformed()) HospiceAssessment
where HospiceAssessment.value ~ "Yes (qualifier value)"
and HospiceAssessment.effective.toInterval() overlaps day of "Measurement Period"
)
or exists ((([ServiceRequest: "Hospice Care Ambulatory"]).isInterventionOrder()) HospiceOrder
where HospiceOrder.authoredOn.toInterval() during day of "Measurement Period"
)
or exists ((([Procedure: "Hospice Care Ambulatory"]).isInterventionPerformed()) HospicePerformed
where HospicePerformed.performed.toInterval() overlaps day of "Measurement Period"
)
or exists (([Condition: "Hospice Diagnosis"]) HospiceCareDiagnosis
where HospiceCareDiagnosis.prevalenceInterval() overlaps day of "Measurement Period"
)
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Pregnancy or Renal Diagnosis |
|
define "Pregnancy or Renal Diagnosis":
( [Condition: "Pregnancy"]
union [Condition: "End Stage Renal Disease"]
union [Condition: "Kidney Transplant Recipient"]
union [Condition: "Chronic Kidney Disease, Stage 5"] ) PregnancyESRDDiagnosis
where PregnancyESRDDiagnosis.prevalenceInterval ( ) overlaps "Measurement Period"
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
End Stage Renal Disease Procedures |
|
define "End Stage Renal Disease Procedures":
( ( [Procedure: "Kidney Transplant"]
union [Procedure: "Dialysis Services"]
).isProcedurePerformed ( ) ) ESRDProcedure
where ESRDProcedure.performed.toInterval ( ) ends on or before end of "Measurement Period"
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
End Stage Renal Disease Encounter |
|
define "End Stage Renal Disease Encounter":
( ( [Encounter: "ESRD Monthly Outpatient Services"] ).isEncounterPerformed ( ) ) ESRDEncounter
where ESRDEncounter.period.toInterval ( ) starts on or before end of "Measurement Period"
|
Library Name |
Name |
AdvancedIllnessandFrailty |
Has Criteria Indicating Frailty |
|
define "Has Criteria Indicating Frailty":
exists ( (([DeviceRequest: "Frailty Device"]).isDeviceOrder()) FrailtyDeviceOrder
where FrailtyDeviceOrder.doNotPerform() is not true
and FrailtyDeviceOrder.authoredOn.toInterval() during day of "Measurement Period"
)
or exists ( (([Observation: "Medical equipment used"]).isAssessmentPerformed()) EquipmentUsed
where EquipmentUsed.value as Concept in "Frailty Device"
and EquipmentUsed.effective.toInterval() ends during day of "Measurement Period"
)
or exists ( ([Condition: "Frailty Diagnosis"]) FrailtyDiagnosis
where FrailtyDiagnosis.prevalenceInterval() overlaps day of "Measurement Period"
)
or exists ( (([Encounter: "Frailty Encounter"]).isEncounterPerformed()) FrailtyEncounter
where FrailtyEncounter.period.toInterval() overlaps day of "Measurement Period"
)
or exists ( (([Observation: "Frailty Symptom"]).isSymptom()) FrailtySymptom
where FrailtySymptom.effective.toInterval() overlaps day of "Measurement Period"
)
|
Library Name |
Name |
AdvancedIllnessandFrailty |
Outpatient Encounters with Advanced Illness |
|
define "Outpatient Encounters with Advanced Illness":
(( [Encounter: "Outpatient"]
union [Encounter: "Observation"]
union [Encounter: "Emergency Department Evaluation and Management Visit"]
union [Encounter: "Nonacute Inpatient"] ).isEncounterPerformed()) OutpatientEncounter
where exists ((OutpatientEncounter.encounterDiagnosis()) Diagnosis where Diagnosis.code in "Advanced Illness")
and OutpatientEncounter.period.toInterval() starts during day of Interval[start of "Measurement Period" - 1 year,
end of "Measurement Period"]
|
Library Name |
Name |
AdvancedIllnessandFrailty |
Has Two Outpatient Encounters with Advanced Illness on Different Dates of Service |
|
define "Has Two Outpatient Encounters with Advanced Illness on Different Dates of Service":
exists ( from
"Outpatient Encounters with Advanced Illness" OutpatientEncounter1,
"Outpatient Encounters with Advanced Illness" OutpatientEncounter2
where OutpatientEncounter2.period ends 1 day or more after day of
end of OutpatientEncounter1.period
return OutpatientEncounter1
)
|
Library Name |
Name |
AdvancedIllnessandFrailty |
Has Inpatient Encounter with Advanced Illness |
|
define "Has Inpatient Encounter with Advanced Illness":
exists ( ( ([Encounter: "Acute Inpatient"]).isEncounterPerformed()) InpatientEncounter
where exists ((InpatientEncounter.encounterDiagnosis()) Diagnosis where Diagnosis.code in "Advanced Illness")
and InpatientEncounter.period.toInterval() starts during day of Interval[start of "Measurement Period" - 1 year,
end of "Measurement Period"]
)
|
Library Name |
Name |
AdvancedIllnessandFrailty |
Has Dementia Medications in Year Before or During Measurement Period |
|
define "Has Dementia Medications in Year Before or During Measurement Period":
exists (( ([MedicationRequest: "Dementia Medications"]).isMedicationActive()) DementiaMedication
where DementiaMedication.doNotPerform is not true and
CMD."MedicationRequestPeriod" ( DementiaMedication ) overlaps day of Interval[start of "Measurement Period" - 1 year,
end of "Measurement Period"]
)
|
Library Name |
Name |
AdvancedIllnessandFrailty |
Is Age 66 to 80 with Advanced Illness and Frailty or Is Age 81 or Older with Frailty |
|
define "Is Age 66 to 80 with Advanced Illness and Frailty or Is Age 81 or Older with Frailty":
( AgeInYearsAt(date from end of "Measurement Period")in Interval[66, 80]
and "Has Criteria Indicating Frailty"
and ( "Has Two Outpatient Encounters with Advanced Illness on Different Dates of Service"
or "Has Inpatient Encounter with Advanced Illness"
or "Has Dementia Medications in Year Before or During Measurement Period"
)
)
or ( AgeInYearsAt(date from end of "Measurement Period")>= 81
and "Has Criteria Indicating Frailty"
)
|
Library Name |
Name |
AdvancedIllnessandFrailty |
Is Age 66 or Older Living Long Term in a Nursing Home |
|
define "Is Age 66 or Older Living Long Term in a Nursing Home":
AgeInYearsAt(date from
end of "Measurement Period"
)>= 66
and ( ( Last( (([Observation: "Housing status"]).isAssessmentPerformed()) HousingStatus
where HousingStatus.effective.toInterval() ends on or before
day of end of "Measurement Period"
sort by
end of effective.toInterval() asc
)) LastHousingStatus
where LastHousingStatus.value ~ "Lives in a nursing home (finding)"
) is not null
|
Library Name |
Name |
PalliativeCare |
Has Palliative Care in the Measurement Period |
|
define "Has Palliative Care in the Measurement Period":
exists ((([Observation: "Functional Assessment of Chronic Illness Therapy - Palliative Care Questionnaire (FACIT-Pal)"]).isAssessmentPerformed()) PalliativeAssessment
where PalliativeAssessment.effective.toInterval() overlaps day of "Measurement Period"
)
or exists ([Condition: "Palliative Care Diagnosis"] PalliativeDiagnosis
where PalliativeDiagnosis.prevalenceInterval() overlaps day of "Measurement Period"
)
or exists ((([Encounter: "Palliative Care Encounter"]).isEncounterPerformed()) PalliativeEncounter
where PalliativeEncounter.period.toInterval() overlaps day of "Measurement Period"
)
or exists ((([Procedure: "Palliative Care Intervention"]).isInterventionPerformed()) PalliativeIntervention
where PalliativeIntervention.performed.toInterval() overlaps day of "Measurement Period"
)
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
Denominator Exclusions |
|
define "Denominator Exclusions":
Hospice."Has Hospice Services"
or exists ( "Pregnancy or Renal Diagnosis" )
or exists ( "End Stage Renal Disease Procedures" )
or exists ( "End Stage Renal Disease Encounter" )
or AIFrailLTCF."Is Age 66 to 80 with Advanced Illness and Frailty or Is Age 81 or Older with Frailty"
or AIFrailLTCF."Is Age 66 or Older Living Long Term in a Nursing Home"
or PalliativeCare."Has Palliative Care in the Measurement Period"
|
Library Name |
Name |
SupplementalDataElements |
SDE Race |
|
define "SDE Race":
Patient.race R
return Tuple {
codes: R.ombCategory union R.detailed,
display: R.text
}
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
SDE Race |
|
define "SDE Race":
SDE."SDE Race"
|
Library Name |
Name |
Status |
isObservationBP |
|
//fluent function versions
define fluent function isObservationBP(Obs List<"QICore.observation-bp">):
Obs O
where O.status in { 'final', 'amended', 'corrected' }
|
Library Name |
Name |
ControllingHighBloodPressureFHIR |
getEncounter |
|
define fluent function getEncounter(reference Reference):
singleton from ( [Encounter] E
where E.id = reference.reference.getId ( )
)
|
Library Name |
Name |
QICoreCommon |
getId |
|
/*
@description: Returns the tail of the given uri (i.e. everything after the last slash in the URI).
@comment: This function can be used to determine the logical id of a given resource. It can be used in
a single-server environment to trace references. However, this function does not attempt to resolve
or distinguish the base of the given url, and so cannot be used safely in multi-server environments.
*/
define fluent function getId(uri String):
Last(Split(uri, '/'))
|
Library Name |
Name |
QICoreCommon |
prevalenceInterval |
|
/*
@description: Returns an interval representing the normalized prevalence period of a given Condition.
@comment: Uses the ToInterval and ToAbatementInterval functions to determine the widest potential interval from
onset to abatement as specified in the given Condition. If the condition is active, or has an abatement date the resulting
interval will have a closed ending boundary. Otherwise, the resulting interval will have an open ending boundary.
*/
define fluent function prevalenceInterval(condition Condition):
if condition.clinicalStatus ~ "active"
or condition.clinicalStatus ~ "recurrence"
or condition.clinicalStatus ~ "relapse" then
Interval[start of condition.onset.toInterval(), end of condition.abatementInterval()]
else
(end of ToAbatementInterval(condition)) abatementDate
return if abatementDate is null then
Interval[start of ToInterval(condition.onset), abatementDate)
else
Interval[start of ToInterval(condition.onset), abatementDate]
|
Library Name |
Name |
Status |
isEncounterPerformed |
|
define fluent function isEncounterPerformed(Enc List<Encounter>):
Enc E
where E.status in {'finished', 'arrived', 'triaged', 'in-progress', 'onleave'}
|
Library Name |
Name |
QICoreCommon |
toInterval |
|
/*
@description: Normalizes a value that is a choice of timing-valued types to an equivalent interval
@comment: Normalizes a choice type of DateTime, Quanitty, Interval<DateTime>, or Interval<Quantity> types
to an equivalent interval. This selection of choice types is a superset of the majority of choice types that are used as possible
representations for timing-valued elements in QICore, allowing this function to be used across any resource.
The input can be provided as a DateTime, Quantity, Interval<DateTime> or Interval<Quantity>.
The intent of this function is to provide a clear and concise mechanism to treat single
elements that have multiple possible representations as intervals so that logic doesn't have to account
for the variability. More complex calculations (such as medication request period or dispense period
calculation) need specific guidance and consideration. That guidance may make use of this function, but
the focus of this function is on single element calculations where the semantics are unambiguous.
If the input is a DateTime, the result a DateTime Interval beginning and ending on that DateTime.
If the input is a Quantity, the quantity is expected to be a calendar-duration interpreted as an Age,
and the result is a DateTime Interval beginning on the Date the patient turned that age and ending immediately before one year later.
If the input is a DateTime Interval, the result is the input.
If the input is a Quantity Interval, the quantities are expected to be calendar-durations interpreted as an Age, and the result
is a DateTime Interval beginning on the date the patient turned the age given as the start of the quantity interval, and ending
immediately before one year later than the date the patient turned the age given as the end of the quantity interval.
If the input is a Timing, an error will be thrown indicating that Timing calculations are not implemented. Any other input will reslt in a null DateTime Interval
*/
define fluent function toInterval(choice Choice<DateTime, Quantity, Interval<DateTime>, Interval<Quantity>, Timing>):
case
when choice is DateTime then
Interval[choice as DateTime, choice as DateTime]
when choice is Interval<DateTime> then
choice as Interval<DateTime>
when choice is Quantity then
Interval[Patient.birthDate + (choice as Quantity),
Patient.birthDate + (choice as Quantity) + 1 year)
when choice is Interval<Quantity> then
Interval[Patient.birthDate + (choice.low as Quantity),
Patient.birthDate + (choice.high as Quantity) + 1 year)
when choice is Timing then
Message(null, true, 'NOT_IMPLEMENTED', 'Error', 'Calculation of an interval from a Timing value is not supported') as Interval<DateTime>
else
null as Interval<DateTime>
end
|
Library Name |
Name |
FHIRHelpers |
ToString |
|
define function ToString(value uri): value.value
|
Library Name |
Name |
FHIRHelpers |
ToCode |
|
/*
@description: Converts the given FHIR [Coding](https://hl7.org/fhir/datatypes.html#Coding) value to a CQL Code.
*/
define function ToCode(coding FHIR.Coding):
if coding is null then
null
else
System.Code {
code: coding.code.value,
system: coding.system.value,
version: coding.version.value,
display: coding.display.value
}
|
Library Name |
Name |
Status |
isAssessmentPerformed |
|
//Similar but different from QICoreCommon.isSurvey, which does not have status constraints
define fluent function isAssessmentPerformed(Obs List<Observation>):
Obs O
where O.status in { 'final', 'amended', 'corrected' }
and exists ( O.category ObservationCategory
where ( ObservationCategory ) ~ "survey"
)
|
Library Name |
Name |
FHIRHelpers |
ToConcept |
|
/*
@description: Converts the given FHIR [CodeableConcept](https://hl7.org/fhir/datatypes.html#CodeableConcept) value to a CQL Concept.
*/
define function ToConcept(concept FHIR.CodeableConcept):
if concept is null then
null
else
System.Concept {
codes: concept.coding C return ToCode(C),
display: concept.text.value
}
|
Library Name |
Name |
Status |
isInterventionOrder |
|
define fluent function isInterventionOrder(ServiceRequest List<ServiceRequest>):
ServiceRequest S
where S.status in { 'active', 'completed' }
and S.intent = 'order'
|
Library Name |
Name |
Status |
isInterventionPerformed |
|
define fluent function isInterventionPerformed(Proc List<Procedure>):
Proc P
where P.status ~ 'completed'
|
Library Name |
Name |
Status |
isProcedurePerformed |
|
define fluent function isProcedurePerformed(Proc List<Procedure>):
Proc P
where P.status ~ 'completed'
|
Library Name |
Name |
Status |
isDeviceOrder |
|
define fluent function isDeviceOrder(DeviceRequest List<DeviceRequest>):
DeviceRequest D
where D.status in { 'active', 'completed' }
and D.intent = 'order'
|
Library Name |
Name |
QICoreCommon |
doNotPerform |
|
/*
@description: Returns true if the given DeviceRequest is a negation (i.e. do not perform this order)
*/
define fluent function doNotPerform(deviceRequest DeviceRequest):
singleton from (
deviceRequest.modifierExtension E
where E.url = 'http://hl7.org/fhir/us/qicore/StructureDefinition/qicore-doNotPerform'
return E.value as Boolean
)
|
Library Name |
Name |
Status |
isSymptom |
|
define fluent function isSymptom(Obs List<Observation>):
Obs O
where O.status in { 'preliminary', 'final', 'amended', 'corrected' }
|
Library Name |
Name |
CQMCommon |
encounterDiagnosis |
|
/*
@description: Returns the Condition resources referenced by the diagnosis element of the Encounter
*/
define fluent function encounterDiagnosis(Encounter Encounter ):
Encounter.diagnosis D
return singleton from ([Condition] C where C.id = D.condition.reference.getId())
|
Library Name |
Name |
Status |
isMedicationActive |
|
define fluent function isMedicationActive(MedicationRequest List<MedicationRequest>):
MedicationRequest M
where M.status = 'active'
and M.intent = 'order'
|
Library Name |
Name |
CumulativeMedicationDuration |
MedicationRequestPeriod |
|
/*
Now that we have a ToDaily function, we can approach calculation of the
duration of medication for an order. First, consider the definitions
for each element:
* 1 and only 1 dosageInstruction
* 1 and only 1 doseAndRate
* 1 timing with 1 repeat
* frequency, frequencyMax, defaulting to 1
* period, periodUnit, defaulting to 1 'd'
* doseQuantity or doseRange
* timeOfDay
* authoredOn: The date the prescription was written
* dispenseRequest.validityPeriod: Time period supply is authorized for
* dispenseRequest.quantity: amount of medication supplied per dispense
* dispenseRequest.numberOfRepeatsAllowed: number of refills authorized
* dispenseRequest.expectedSupplyDuration: number of days supply per dispense
* dosageInstruction.timing.repeat.boundsDuration: total duration of the repeat
* dosageInstruction.timing.repeat.boundsRange: range of durations of the repeat
* dosageInstruction.timing.repeat.boundsPeriod: period bounds of the repeat
* dosageInstruction.timing.repeat.count: number of times to repeat
* dosageInstruction.timing.repeat.countMax: maximum number of times to repeat
* dosageInstruction.timing.repeat.frequency: event occurs frequency times per period
* dosageInstruction.timing.repeat.frequencyMax: event occurs up to frequencyMax times per period
* dosageInstruction.timing.repeat.period: event occurs frequency times per period
* dosageInstruction.timing.repeat.periodMax: upper limit of period
* dosageInstruction.timing.repeat.periodUnit: period duration (s | min | h | d | wk | mo | a)
* dosageInstruction.timing.repeat.timeOfDay: time of day for the event (0..*)
* dosageInstruction.timing.repeat.when: event timing (HS | WAKE | C | CM | CD | CV | AC | ACM...)
* dosageInstruction.timing.code: BID | TID | QID | AM | PM | QD | QOD...
* dosageInstruction.asNeeded
* dosageInstruction.doseAndRate.doseQuantity
* dosageInstruction.doseAndRate.doseRange
If expectedSupplyDuration is present, then the duration is
expectedSupplyDuration * (1 + numberOfRepeatsAllowed)
If expectedSupplyDuration is not present, then it must be calculated based on the quantity, dosage, and frequency:
(quantity / (dosage * frequency)) * (1 + numberOfRepeatsAllowed)
dosage: Coalesce(end of doseAndRate.doseRange, doseAndRate.doseQuantity)
frequency: Coalesce(frequencyMax, frequency)
period: Quantity(period, periodUnit)
If expectedSupplyDuration is not present and cannot be calculated, and the boundsPeriod is present (and completely specified), we can use that directly
dosage.timing.repeat.boundsPeriod
This calculation results in a number of days, which can then be turned into a period by anchoring that to the
start of the validityPeriod or the authoredOn:
Interval[earliestDispensable, earliestDispensable + expectedSupplyDuration - 1]
earliestDispensable: Coalesce(start of validityPeriod, authoredOn)
The following function illustrates this completely:
*/
/*
Calculates the Medication Period for a single MedicationRequest.
MedicationRequest instances provided to this function are expected
to conform to the [MMEMedicationRequest](http://build.fhir.org/ig/cqframework/opioid-mme-r4/StructureDefinition-mmemedicationrequest.html)
profile, which expects:
* 1 and only 1 dosageInstruction, multiple dosageInstruction elements will result in an error
* 1 and only 1 doseAndRate, multiple doseAndRate elements will result in an error
* 1 timing with 1 repeat, missing timing or repeat elements will result in a null
* frequency, frequencyMax, defaulting to 1
* period, periodUnit, defaulting to 1 'd'
* timeOfDay
* doseQuantity or doseRange, missing doseQuantity and doseRange will result in a null
Note that MedicationRequest status is not considered by this calculation, as the
list of MedicationRequest instances provided to this function should already have
considered appropriate statuses, depending on the use case, typically `completed`.
*/
define function MedicationRequestPeriod(Request "MedicationRequest"):
Request R
let
dosage: singleton from R.dosageInstruction,
doseAndRate: singleton from dosage.doseAndRate,
timing: dosage.timing,
frequency: Coalesce(timing.repeat.frequencyMax, timing.repeat.frequency),
period: Quantity(timing.repeat.period, timing.repeat.periodUnit),
doseRange: doseAndRate.dose,
doseQuantity: doseAndRate.dose,
dose: Coalesce(end of doseRange, doseQuantity),
dosesPerDay: Coalesce(ToDaily(frequency, period), Count(timing.repeat.timeOfDay), 1.0),
boundsPeriod: timing.repeat.bounds as Interval<DateTime>,
daysSupply: (convert R.dispenseRequest.expectedSupplyDuration to days).value,
quantity: R.dispenseRequest.quantity,
refills: Coalesce(R.dispenseRequest.numberOfRepeatsAllowed, 0),
startDate:
Coalesce(
date from start of boundsPeriod,
date from R.authoredOn,
date from start of R.dispenseRequest.validityPeriod
),
totalDaysSupplied: Coalesce(daysSupply, quantity.value / (dose.value * dosesPerDay)) * (1 + refills)
return
if startDate is not null and totalDaysSupplied is not null then
Interval[startDate, startDate + Quantity(totalDaysSupplied - 1, 'day') ]
else if startDate is not null and boundsPeriod."high" is not null then
Interval[startDate, date from end of boundsPeriod]
else
null
|
Library Name |
Name |
CumulativeMedicationDuration |
Quantity |
|
/**********************************************************************/
/* Functions in this region are copied from opioid-mme-r4 */
/**********************************************************************/
define function Quantity(value Decimal, unit String):
if value is not null then
System.Quantity { value: value, unit: unit }
else
null
|
Library Name |
Name |
CumulativeMedicationDuration |
ToDaily |
|
/*
Goal is to get to number of days
Two broad approaches to the calculation:
1) Based on supply and frequency, calculate the number of expected days the medication will cover/has covered
2) Based on relevant period, determine a covered interval and calculate the length of that interval in days
This topic covers several use cases and illustrates how to calculate Cumulative
Medication Duration for each type of medication resource using the supply and
frequency approach.
*/
/*
For the first approach, we need to get from frequency to a frequency/day
So we define ToDaily
*/
/*
Calculates daily frequency given frequency within a period
*/
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 Message(null, true, 'CMDLogic.ToDaily.UnknownUnit', ErrorLevel, 'Unknown unit ' & period.unit)
end
|