Skip to content

Authoring Patterns QICore v6.0.0

juliet-rubini edited this page Sep 16, 2024 · 38 revisions

Authoring Patterns QI-Core v6.0.0

This page provides discussion and best-practice recommendations for authoring patterns for accessing patient information in FHIR and CQL. For general conventions and guidance regarding the use of FHIR and CQL, refer to the Using CQL topic in the Quality Measure IG.

Feedback on the patterns and discussion here can be provided by submitting a New Issue to this repository.

QI-Core Information Model Overview

HL7 Fast Healthcare Interoperability Resources (FHIR) is a platform specification for exchanging healthcare data. FHIR defines a core information model that can be profiled for use in a variety of applications across the healthcare industry. These profiles are defined in Implementation Guides that provide constraints on the ways that FHIR resources can be used in to support interoperability (i.e. the ability of both sides of an interaction to correctly interpret the information being exchanged).

In the United States, the US Core Implementation Guide defines a floor for that interoperability, enabling a broad range of clinical and administrative use cases. For quality improvement use cases, such as decision support and quality measurement, the QI Core Implementation Guide extends US Core to support additional information used for quality improvement. For the most part, US Core covers the data required, but some use cases, such as documentation of events that did not occur, require additional profiles.

Clinical Quality Language(CQL) is high-level, domain-specific language focused on clinical quality and targeted at measure and decision support artifact authors.

To simplify the expression of logic in quality improvement artifacts, CQL can be authored directly against the information model defined by the QI Core profiles. In the simplest terms, that information model provides:

  1. Patient - Representation of patient demographic and basic characteristics
  2. Encounters - Encounters between a patient and healthcare providers, typically taking place at a facility or virtually
  3. Observations - Facts about the patient such as lab results, vital signs, social history, etc.
  4. Conditions - Conditions the patient has (or does not have)
  5. Medications - Information related to medications the patient is prescribed and/or using
  6. Procedures - Information related to procedures ordered and/or performed for the patient
  7. Devices - Information related to devices the patient is using and/or has been prescribed
  8. Allergies - Allergies and intolerances the patient has (or does not have)
  9. Immunizations - Information related to immunizations the patient has received or been recommended
  10. Communication - Information related to communications with or about the patient

NOTE: The information in this page specifically uses the 6.0.0 version of QI-Core, which depends on the 6.1.0 version of USCore, and both of which are based on the R4 version 4.0.1 of FHIR.

The following sections provide specific examples of best practices for accessing information in each of these high-level areas.

Intro to Playing with FHIR

As an aside, whether expressions in general should use the various elements of a profile depends entirely on measure or rule intent. However, there are some general guidelines that should be followed to ensure correct expression and evaluation of CQL.

To begin with, all elements in FHIR profiles have a cardinality that determines whether and how many values may appear in that element. Cardinality is expressed as a range, typically from 0 or 1 to 1 or . A cardinality of 0..1 means the element is optional. A cardinality of 1..1 means the element is required. A cardinality of 0.. means the element may appear any number of times, and a cardinality of 1..* means the element must appear at least once, but may appear multiple times. Although other cardinalities are possible, those described above are the most common.

NOTE: Cardinality determines whether and how many values may appear for a given element, but the fact that an element is specified as required (e.g. 1..1) does not mean that expressions using that profile must use that element.

In addition, elements in FHIR profiles may be marked must support, meaning that implementations are required to provide values for the element if they are present in the system. To ensure expression logic can be evaluated correctly, expressions must only use elements that are marked must support. For a complete discussion of this aspect, refer to the MustSupport Flag topic in the QI-Core Implementation Guide.

And finally, elements in FHIR profiles may be marked as modifier elements, meaning that the value of the element may change the overall meaning of the resource. For example, the clinicalStatus element of a Condition is a modifier element because the value determines whether the Condition overall represents the presence or absence of a condition. As a result, for each modifier element, authors must carefully consider whether each possible value would impact the intent of the expression.

To summarize, cardinality determines whether data will be present at all, must support determines whether the element can be used in an expression, and modifier elements must always be considered to determine the impact of possible values of the element on the result of the expression. End of aside.

Use of Terminologies

FHIR supports various types of terminology-valued elements, including:

Within CQL, references to terminology code systems, value sets, codes, and concepts are directly supported, and all such usages are declared within CQL libraries, as described in the Terminology section of the CQL Author's Guide.

When referencing terminology-valued elements within CQL, the following comparison operations are supported:

As a general rule, the equivalent (~) operator should be used whenever the terminology being compared is a direct-reference code, and the in operator should be used whenever the terminology being compared is a value set. The equal (=) operator should only be used with code-valued elements that have a required binding.

code

In FHIR, code-valued elements are most often used with required bindings, meaning that the only values that can appear are established by the specification. Because of this, basic string comparison can be used, for example:

where Encounter.status = 'finished'

NOTE: The comparison here is to the code value, not the display

NOTE: Note also that there are edge-cases where the string-valued elements may contain terminology values. For more detail on this case, refer to the Using CQL IG

CodeableConcept

Most terminology-valued elements in FHIR are CodeableConcepts. If the terminology being compared is a value set (e.g. valueset "Inpatient Encounter"), use the in operator:

where Encounter.type in "Inpatient Encounter"

Note that the in operator works whether the element is single cardinality or multi-cardinality.

If the terminology being compared is a direct-reference code (e.g. code "Blood Pressure"), use the ~ operator:

where Observation.code ~ "Blood Pressure"

Note that this comparison only works if the element is single-cardinality. For multi-cardinality elements with direct-reference code comparison (e.g. code "Right Breast"), each CodeableConcept must be tested using the ~ operator, so an exists is used:

where exists (Condition.bodySite S where S ~ "Right Breast")

Coding

Some terminology-valued elements in FHIR use the Coding type specifically. The same comparison patterns are used for elements of this type. For value sets (e.g. valueset "Inpatient Class"), use in:

where Encounter.class in "Inpatient Class"

And for direct-reference codes (e.g. code "Inpatient"), use ~:

where Encounter.class ~ "Inpatient"

Patient

Reviewed 2024-06-18

QI-Core defines a QICore Patient profile that extends the USCore patient.

Patient age

Patient information includes the birth date, and CQL provides a built-in function to calculate the age of a patient, either current age (i.e. as of now), or as of a particular date. In quality improvement artifacts, age is typically calculated as of a particular date such as the start of the measurement period:

define "Patient Age Between 50 and 75":
  AgeInYearsAt(date from start of "Measurement Period") between 50 and 75

NOTE: The AgeInYearsAt function in CQL uses the data model (QICore in this case) to understand how to access the patient's birth date information. NOTE: CQL supports age calculation functions using both Date and DateTime values. In both cases the function is shorthand for a date/datetime duration calculation. If the DateTime overloads are used, note that the timezone offset is considered and there may be edge cases that result in unexpected results, depending on how large the timezone offset is from the execution timestamp. To avoid these edge cases, best practice is to use the date from extractor as shown in the above pattern to ensure the Date calculation is used.

Patient gender

Patient gender in FHIR is represented using codes from the AdministrativeGender code system:

define "Patient Is Male":
  Patient.gender = 'male'

NOTE: Terminology-valued elements in FHIR resources are bound to value sets. The gender element is an example of a required binding, which means that only the codes in that binding are allowed to be used. This is why the logic here can be specific about comparing to the actual string 'male'. In general, terminology-valued elements should be compared using terminology operators. For more information see the Using Terminology topic in the Quality Measure IG.

Patient race and ethnicity

US Core defines extensions for representing the race and ethnicity of a patient using the CDC's race and ethnicity codes. When authoring using QI-Core, these extensions can be accessed directly on the patient using the "slice name" of the extension:

define "Patient Race Includes Alaska Native":
  Patient P
    where exists (P.race.ombCategory C where C ~ "American Indian or Alaska Native")
      and exists (P.race.detailed C where C ~ "Alaska Native")

NOTE: CQL uses the data model (QI-Core in this case) to understand how to access patient information using the Patient definition. This definition is available in Patient contexts.

Encounters

Reviewed 2024-06-18 - Updates to be made and reviewed again with group based on discussions

QI-Core defines an Encounter profile to model any encounter between a patient and any number of providers in any setting, including virtual.

NOTE: For background information on accessing clinical information with CQL, see the Retrieve topic in the CQL specification.

Office visit encounters

By default, encounters in QI-Core are characterized by the type element, which is typically associated with a value set to limit the set of encounters returned to those that a code in the given value set. For example:

define "Office Visit Encounters":
  [Encounter: "Office Visit"]

Accessing Encounters with a Direct-reference code

The type element of Encounters is plural meaning that a given Encounter may have multiple types associated with it. When using value sets such as the "Office Visit" example above, the retrieve resolves using the List overload of the in(ValueSet) operator in CQL. However, when attempting to use a direct-reference code, there is no overload of the Equivalent (~) operator to support the comparison.

This issue is being reviewed and may result in a specification or tooling change to support this use case (see Translator Issue 1181). However, at this time there are two possible workarounds:

  1. Define a value set containing the required code and use that value set to perform the retrieve
  2. Use an equivalent where clause with an exists to retrieve the expected results, as shown in the below example:
define "Office Visit Encounters By Code":
  [Encounter] E
    where exists ((E.type) T where T ~ "Office Visit Code")

Note that this latter workaround will typically result in an unrestricted data requirement for Encounters. For this reason, best-practice is to use the first workaround.

Encounters by class

The QI-Core profile also supports characterizing encounters by the class element, which is used to categorize encounters more broadly than the type element, using the ActEncounterCode value set. For example:

define "Virtual Encounters":
  [Encounter: class ~ QICoreCommon."virtual"]

Note that although QDM-based eCQMs have typically used a type-based approach to filtering encounters, because class is a required element in USCore, we propose using class to filter encounters first, unless measure intent needs to search for encounters by type across classes. Additional filtering may be required beyond the class to limit encounters based on specialty, for example:

define "Opthalmology Encounter Codes":
  [Encounter: class in "Inpatient Encounter Classes"] InpatientEncounter
    where InpatientEncounter.type in "Opthalmology Encounter Codes"

Completed encounters in a period

Encounters often need to be filtered based on status and period, for example:

define "Completed Encounters During the Measurement Period":
  [Encounter: "Office Visit"] OfficeVisit
    where OfficeVisit.status = 'finished'
      and OfficeVisit.period during "Measurement Period"

Encounters with a certain length

The CQMCommon library defines a lengthInDays() function that calculates the difference in days between the start and end of a period. For example, to filter encounters by the duration of stay:

define "Non-Elective Inpatient Encounter Less Than 120 Days":
  ["Encounter": "Non-Elective Inpatient Encounter"] NonElectiveEncounter
    where NonElectiveEncounter.period.lengthInDays() <= 120

Other durations can also be calculated, for example:

define "Non-Elective Inpatient Encounter Over 24 Hours":
  ["Encounter": "Non-Elective Inpatient Encounter"] NonElectiveEncounter
    where duration in hours of NonElectiveEncounter.period >= 24

NOTE: For ongoing encounters, the end of the period is often not specified, which will typically be interpreted in CQL as an ongoing period, resulting in large duration values.

Hospitalization

For inpatient encounters, measures and rules often need to consider total hospitalization period, including any immediately prior emergency department and/or observation status encounters. To facilitate this, the CQMCommon library defines a hospitalizationWithObservation() function that returns the total duration from admission to the emergency department or observation to the end of the inpatient encounter. For example:

define "Comfort Measures Performed":
  ["Procedure": "Comfort Measures"] InterventionPerformed
    where InterventionPerformed.status in { 'completed', 'in-progress' }

define "Encounter with Comfort Measures Performed during Hospitalization":
  "Non-Elective Inpatient Encounter Less Than 120 Days" Encounter
    with "Comfort Measures Performed" ComfortMeasure
      such that start of ComfortMeasure.performed.toInterval() during Encounter.hospitalizationWithObservation()

Conditions

Reviewed 2024-06-25 - Updates will be made based on discussion and reviewed with group

Change from 4.1.1: QI-Core STU 6 defines two profiles:

Change from 4.1.1: QI-Core STU6 no longer supports the use of the Encounter.diagnosisPresentOnAdmission element. This concept should be modeled using the Claim profile and is discussed in the Conditions present on admission section below . Measure developers need to consider their measure intent when building measure logic to look for conditions. If the measure intent is looking to capture conditions that were present on admission or a principal diagnosis, the Claim profile is now used to access that billing related content. Please reference the Conditions present on admission section for patterns related to those concepts.

Active conditions

By default, Condition resources are characterized by the code element which is typically associated with a value set of diagnosis codes.

Many clinical systems make a distinction between the active conditions for a patient (i.e. the problem list or health concerns) and the diagnoses associated with an encounter. Problem list items and health concerns are typically documented with additional information about the condition such as prevalence period and clinical status, while encounter diagnoses typically have less information, usually only the diagnosis code as part of the encounter information. Within FHIR, both these types of data are represented using the Condition resource. The category element is used to indicate which kind of data the Condition represents, a problem list item, a health concern, or an encounter diagnosis, and the ConditionHealthProblems and ConditionEncounterDiagnosis profiles separate conditions by these ctaegories.

Depending on measure intent, different approaches may be needed to access condition data. In particular, clinical status and prevalence period would only be expected to be present on problem list items and health concerns:

define "Active Diabetes Conditions":
  [ConditionProblemsHealthConcerns: "Diabetes"] Condition
    where Condition.isActive()

The QICoreCommon library defines isProblemListItem() and isHealthConcern() functions to facilitate identifying the category of a Condition, as well as an isActive() function to facilitate determining whether the Condition indicates the presence of a particular diagnosis for the patient. The isActive() function is equivalent to testing the clinicalStatus element for the active, recurrence, and relapse values.

NOTE: If measure intent is such that condition information should be considered whether it is problem list, health concern, or encounter diagnosis, the category check can be omitted.

Encounters with a condition

New to STU 6.0 To determine a condition existed during the encounter, measure developers should use one of the following approaches:

  1. Encounter.reasonCode = direct reference code or value set (of the Condition)
  2. Encounter.reasonReference = ConditionProblemHealthConcern or ConditionEncounterDiagnosis
  3. Claim.diagnosis

This is a change from 4.1.1 where measure developers used the Encounter.diagnosis= value set pattern. Measure developers should note that not all EHRs will have both Encounter.reasonCode and Encounter.reasonReference and patterns are developed below to look for that information both ways to account for differences in EHR implementation. The following example combines the approaches from 1 and 2 above:

define "Encounters with a Diabetes Condition":
  "Completed Encounters During the Measurement Period" CompletedEncounter
    where CompletedEncounter.reasonCode in "Diabetes"
    or CompletedEncounter.reasonReference = [ConditionEncounterDiagnosis: "Diabetes"]

It is also important for measure developers to consider that if their clinical use case requires the use of prevalence period (i.e., onset to abatement time for a condition) or even just onset time, that will require the use of option 2 – the Encounter.reasonReference – format. This is due to the fact that only referenced profiles provide ability to indicate onset and/or abatement times.

History of a condition

Change from 4.1.1 When looking for history of a condition, clinical status and whether or not the condition is documented as a problem list, health concern, or encounter diagnosis are typically less relevant, so those elements are not typically referenced. However, in QI-Core, because the two types of conditions are represented with different profiles, separate retrieve statements are used to gather both:

define "History of Diabetes":
  [ConditionProblemsHealthConcerns: "Diabetes"]
    union [ConditionEncounterDiagnosis: "Diabetes"]

Note that depending on measure intent, it may still be necessary to reference elements such as:

  • Completion status of the associated encounter for encounter diagnoses
  • Clinical status of problem list items and health concerns
  • Verification status of problem list items and health concerns, especially refuted conditions

For example:

define "History of Diabetes":
  ([ConditionProblemsHealthConcerns: "Diabetes"] Condition
    where Condition.verificationStatus is not null implies Condition.verificationStatus !~ "refuted"
  ) union (
    [ConditionEncounterDiagnosis: "Diabetes"] Condition
      where Condition.getEncounter().status = 'finished'
  )

Onset, abatement, and prevalence period

The Condition profiles define onset and abatement elements that specify the prevalence period of the condition. The elements can be specified as choices of various types to allow systems flexibility in the way that information is represented. The QI-Core profile for Condition constrains those choices to only those that support actual computation of a prevalence period, and the QICoreCommon library defines abatementInterval and prevalenceInterval functions to facilitate accessing this information:

define "Active Diabetes Conditions Onset During the Measurement Period":
  "Active Diabetes Conditions" Diabetes
    where Diabetes.prevalenceInterval() starts during "Measurement Period"

The prevalenceInterval function takes a Condition resource and returns the interval from the start of the onset to the end of the abatement. If the Condition is active (i.e. has a clinicalStatus of active, recurrence, or relapse), then the ending boundary of the interval is inclusive (i.e. closed). Otherwise, the ending boundary of the interval is exclusive (i.e. open). When looking for whether a condition was active at some point, use the prevalenceInterval function rather than looking at the status element only.

Conditions present on admission

QICore STU6 no longer supports the use of the Encounter.diagnosisPresentOnAdmission element. To express the concept of a condition present on admission, measure developers should be use the QI Core Claim profile.

Observations

Reviewed 2024-06-25

QI-Core defines a variety of profiles for use in accessing observations for a patient. Specifically, QI-Core includes the vital signs profiles defined in US Core such as blood pressure, body height and weight, and BMI, as well as several social determinants observations like occupation and sexual orientation. In addition, US Core includes two new profiles around pregnancy:

New QI-Core profiles added (since 4.1.1 and 5.0) include:

In general, these profiles do not constrain the value of the status element, meaning that retrieves of these profiles will return observations in any status. As a modifier element, authors must consider the possible values of the observation status when determining how to filter the results of a retrieve of these profiles.

Vital Signs

Reviewed 2024-06-25

When using QI-Core to access profiled resources, the result of the retrieve will only include resources that conform to that profile. This means that the retrieve is effectively a filter by conformance, meaning that the expression does not need to provide filters for values that are fixed by the profile definition. When retrieving Respiratory rate, for example, this means that the expression does not need to test that the code of the Observation is the LOINC code for respiratory rate (9279-1), the retrieve will only result in observations that already have that code:

// Respiratory rate - 9279-1
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-respiratory-rate.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-respiratory-rate.html)
define RespiratoryRate:
  ["USCoreRespiratoryRateProfile"] O
    where O.status in { 'final', 'amended', 'corrected' }

As a rule of thumb, if a profile definition defines a fixed value constraint for an element, then the expression does not need to use that element.

// Heart rate - 8867-4
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-heart-rate.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-heart-rate.html)
define HeartRate:
  [USCoreHeartRateProfile] O
    where O.status in { 'final', 'amended', 'corrected' }
// Body temperature - 8310-5
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-temperature.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-temperature.html)
define BodyTemperature:
  [USCoreBodyTemperatureProfile] O
    where O.status in { 'final', 'amended', 'corrected' }
// Body height - 8302-2
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-height.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-height.html)
define BodyHeight:
  [USCoreBodyHeightProfile] O
    where O.status in { 'final', 'amended', 'corrected' }
// Head circumference - 9843-4
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-head-occipital-frontal-circumference-percentile.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-head-occipital-frontal-circumference-percentile.html)
define HeadCircumference:
  [USCoreHeadCircumferenceProfile] O
    where O.status in { 'final', 'amended', 'corrected' }
// Body weight - 29463-7
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-weight.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-weight.html)
define BodyWeight:
  [USCoreBodyWeightProfile] O
    where O.status in { 'final', 'amended', 'corrected' }
// Body mass index - 39156-5
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-bmi.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-bmi.html)
define BodyMassIndex:
  [USCoreBMIProfile] O
    where O.status in { 'final', 'amended', 'corrected' }
// Blood pressure systolic and diastolic - 85354-9
// Systolic blood pressure - 8480-6
// Diastolic blood pressure - 8462-4
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-blood-pressure.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-blood-pressure.html)
define "BloodPressure less than 140 over 90":
  [USCoreBloodPressureProfile] BP
    where BP.status in { 'final', 'amended', 'corrected' }
      and BP.systolic.value < 140 'mm[Hg]'
      and BP.diastolic.value < 90 'mm[Hg]'
// USCore Pediatric BMI for Age - 59576-9
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-pediatric-bmi-for-age.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-pediatric-bmi-for-age.html)
define PediatricBMIForAge:
  [USCorePediatricBMIforAgeObservationProfile] O
    where O.status in { 'final', 'amended', 'corrected' }
// USCore Pediatric Weight for Height - 77606-2
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-pediatric-weight-for-height.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-pediatric-weight-for-height.html)
define PediatricWeightForHeight:
  [USCorePediatricWeightForHeightObservationProfile] O
    where O.status in { 'final', 'amended', 'corrected' }
// USCore Pulse Oximetry - 59408-5
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-pulse-oximetry.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-pulse-oximetry.html)
define PulseOximetry:
  [USCorePulseOximetryProfile] O
    where O.status in { 'final', 'amended', 'corrected' }

Note that Oxygen Saturation is now part of the pulse oximetry profile.

New US Core profiles referenced in QI-Core:

Pregnancy Status https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-observation-pregnancystatus.html This profile sets minimum expectations for the Observation resource to record, search, and fetch the “state or condition of being pregnant”. For measure developers looking to capture a pregnancy status, the following pattern can be used:

define "Currently pregnant":
["USCorePregnancyStatusProfile"] PregStatus
where PregStatus.status = 'final'
and PregStatus.value = 'Pregnant'

Pregnancy Intent https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-observation-pregnancyintent.html this profile sets minimum expectations for the Observation resource to record, search, and fetch the “patient’s intent to become pregnant” over the next year.

define "Pregnancy Intent":
["USCorePregnancyIntentProfile"] PregIntent
where PregIntent.status = 'final'
and PregIntent.value = 'No desire to become pregnant (finding)'

Smoking Status

Reviewed 2024-06-25

QI-Core includes the USCore Smoking Status profile:

// USCore Smoking Status
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-smokingstatus.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-smokingstatus.html)
define SmokingStatus:
  ["USCoreSmokingStatusProfile"] O
    where O.status in { 'final', 'amended', 'corrected' }

Laboratory Result

Reviewed 2024-06-25

Laboratory results in QI-Core use the [LaboratoryResultObservation] https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-observation-lab.html profile. By default, Laboratory results in QI-Core are characterized by the code element.

define LaboratoryResultObservation:
  ["LaboratoryResultObservation"] O
    where O.status in { 'final', 'amended', 'corrected' }

Clinical Test Result

Reviewed 2024-06-25

Clinical test results (including imaging results) in QI-Core use the [ObservationClinicalResult] https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-observation-clinical-result.html profile. By default, clinical test results in QI-Core are characterized by the code element.

define ObservationClinicalResult:
  ["ObservationClinicalResult"] O
    where O.status in { 'final', 'amended', 'corrected' }

Surveys and assessment

Reviewed 2024-06-25

New from 4.1.1 Surveys and assessments in QI-Core use the [ObservationScreeningAssessment] https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-observation-screening-assessment.html profile. By default, survey observations in QI-Core are characterized by the code element.

define ObservationAssessemt:
  ["ObservationScreeningAssessment"] O
    where O.status in { 'final', 'amended', 'corrected' }

Simple Observations (NEW)

Reviewed 2024-06-25

In addition, QI-Core defines a Simple Observation https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-simple-observation.html profile for use when accessing observations that are not covered by the specific profiles defined in FHIR and US Core. Observations in QI-Core are characterized by the code element, which is typically filtered to a particular value set:

define "Pap Test with Results":
  ["SimpleObservation": "Pap Test"] PapTest
    where PapTest.value is not null
      and PapTest.status in { 'final', 'amended', 'corrected', 'preliminary' }

NOTE: As with the other observation profiles, the status of a QI-Core Observation must be considered in order to ensure that the results of the expression will match measure intent. This typically means that the status element will be used in the expression as in the prior example.

Observations cancelled (not done)

Reviewed 2024-06-25

QI-Core defines an [ObservationCancelled] https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-observationcancelled.html profile to support identifying observations that were not performed for a particular reason:

define "Pap Test Refused":
  ["ObservationCancelled": "Pap Test"] PapTest
    where PapTest.notDoneReason in "Patient Refusal"

Observations Non Patient (NEW)

Reviewed 2024-06-25

QI-Core defines an [ObservationNonPatient] https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-nonpatient-observation.html profile for evaluating resource use and availability rather than focusing on patients:

define "Hemodialysis machine available":
  ["ObservationNonPatient": "Hemodialysis"] Hemo
    where Hemo.status= 'final'
    and Hemo.value = 'Equipment available (finding)'

Medications

(Reviewed 2024-08-06) FHIR defines several medication-related resources that are profiled for use in the US by US Core, and then by QI-Core for use in quality improvement artifacts. For background on the FHIR medication resources, see the Medication module in the base FHIR specification. Additional guidance on how medication information is profiled within US Core can be found in the Medication list guidance topic in the US Core implementation guide. In comparison to STU 4.1.1, there are no new medication profiles added to STU6 of QI-Core.

Medication ordered

QICore defines the MedicationRequest profile to represent medication proposals, plans, and orders, as well as self-reported medications. The following example illustrates an order for Antithrombotic Therapy to be taken by the patient once discharged. MedicationRequest resources in QI-Core are characterized by the medication element which can be represented as a code or a reference.

define "Antithrombotic Therapy at Discharge":
  ["MedicationRequest": medication in "Antithrombotic Therapy"] Antithrombotic
    where (Antithrombotic.isCommunity() or Antithrombotic.isDischarge())
      and Antithrombotic.status in { 'active', 'completed' }
      and Antithrombotic.intent = 'order'

NOTE: Because the status element is a modifier that is not constrained by the profile to a specific value or value set, authors must consider all the possible values of the status to ensure the expression matches measure intent. In this case the statuses of active and completed indicate active or filled prescriptions for medications in the Antithrombotic Therapy value set. NOTE: Because the MedicationRequest profile fixes the value of the doNotPerform element to false if it is present, that element does not need to be tested in the expression.

Medication not ordered

QI-Core defines the MedicationNotRequested profile to represent documentation of the reason for not ordering a particular medication or class of medications. By default, MedicationNotRequested resources in QI-Core are characterized by the medication element which can be represented as a code or a reference.

define "Reason for Not Ordering Antithrombotic":
  ["MedicationNotRequested": "Antithrombotic Therapy"] NoAntithromboticDischarge
    where (NoAntithromboticDischarge.reasonCode in "Medical Reason"
      or NoAntithromboticDischarge.reasonCode in "Patient Refusal")
      and (NoAntithromboticDischarge.isCommunity() or NoAntithromboticDischarge.isDischarge())
      and NoAntithromboticDischarge.status in { 'active', 'completed' }
      and NoAntithromboticDischarge.intent = 'order'

NOTE: Because the status element is a modifier that is not constrained by the profile to a specific value or value set, authors must consider all the possible values of the status to ensure the expression matches measure intent. In this case the statuses of active and completed indicate no active or filled prescriptions for medications in the Antithrombotic Therapy value set. NOTE: Because the MedicationNotRequested profile fixes the value of doNotPerform to true, that element does not need to be tested in the expression.

Medication administered

QI-Core defines the MedicationAdministration profile to represent the administration of a medication to a patient. By default, MedicationAdministration resources in QICore are characterized by the medication element, which can be represented as a code or a reference.

define "Low Dose Unfractionated Heparin Administration":
  ["MedicationAdministration": medication in "Low Dose Unfractionated Heparin for VTE Prophylaxis"] VTEMedication
    where VTEMedication.status = 'completed'
      and VTEMedication.category ~ QICoreCommon."Inpatient"

NOTE: Because the MedicationAdministration profile does not fix the value of the status element, authors must consider all the possible values of the element to ensure the expression matches measure intent. In this case, the completed status indicates the only completed medication administrations should be returned.

Medication not administered

QI-Core defines the MedicationAdministrationNotDone profile to represent documentation of the reason a medication administration did not occur. By default, MedicationAdministrationNotDone resources in QI-Core are characterized by the medication element, which can be represented as a code or a reference.

define "Low Dose Unfractionated Heparin for VTE Prophylaxis Not Administered":
  ["MedicationAdministrationNotDone": "Low Dose Unfractionated Heparin for VTE Prophylaxis"] VTEMedication
    where VTEMedication.category ~ QICoreCommon."Inpatient"
      and (VTEMedication.reasonCode in "Medical Reason" or VTEMedication.reasonCode in "Patient Refusal")

NOTE: Because the MedicationAdministrationNotDone profile fixes the value of status to not-done, that element does not need to be tested in the expression.

Medication dispensed QI-Core defines the MedicationDispense profile to represent the fulfillment of a medication request, either in a hospital or community pharmacy. By default, MedicationDispense resources in QI-Core are characterized by the medication element, which can be represented as a code or a reference.

define "Dementia Medication Dispensed":
  ["MedicationDispense": "Dementia Medications"] MedicationDispense
    where MedicationDispense.status in { 'active', 'completed', 'on-hold' }

NOTE: Because the MedicationDispense profile does not fix the value of the status element, authors must consider all the possible values of the element to ensure the expression matches measure intent. In this case, the active, completed, and on-hold statuses are used to retrieve any positive dispensing event.

Medication not dispensed

QI-Core defines the MedicationDispenseDeclined profile to represent documentation of the reason that a dispense did not occur. By default, MedicationDispenseDeclined resources in QICore are characterized by the medication element, which can be represented as a code or a reference.

define "Dementia Medication Not Dispensed":
    ["MedicationDispenseDeclined": "Dementia Medications"] MedicationDispense
      where MedicationDispense.statusReason in "Medical Reason"
        or MedicationDispense.statusReason in "Patient Refusal"

NOTE: Because the MedicationDispenseDeclined profile fixes the value of the status element to declined, that element does not need to be tested in the expression.

Medication in use

In addition to medications ordered at discharge or administered in the hospital setting, measure developers may also want to look for medications that are currently in use by a patient outside the hospital setting or those medications not prescribed by a provider (commonly referred to as OTC or over the counter). Two examples are shown below:

Medication in use

define "Antithrombotic Therapy Active":
  ["MedicationRequest": "Antithrombotic Therapy"] Antithrombotic
    where Antithrombotic.status = 'active'

Self administered OTCs

define "Niacin OTC at home":
  ["MedicationRequest": "NiacinOTC"] Niacin
    where (Niacin.isCommunity())
      and Niacin.status = 'active'
      and Niacin.intent = 'plan'
      and Niacin.reporter = 'patient'

Note that 'Niacin.isCommunity' reflects the MedicationRequest category which indicates the setting in which the medication is taken (or is expected to be taken) is community.

Procedures

(Reviewed 2024-08-06) FHIR defines several procedure-related resources to support representing the proposal, planning, ordering, and performance of services and procedures for a patient. In comparison to STU 4.1.1, there are no new procedure profiles added to STU6 of QI-Core.

Procedure performed

QI-Core defines the Procedure profile to represent an in-progress or complete procedure for a patient. By default, Procedure resources in QI-Core are characterized by the code element.

define "Application of Intermittent Pneumatic Compression Devices":
  ["Procedure": "Application of Intermittent Pneumatic Compression Devices (IPC)"] DeviceApplied
    where DeviceApplied.status = 'completed'

NOTE: Because the Procedure profile does not fix the value of the status element, authors must consider all the possible values of the element to ensure the expression meets measure intent. In this case, completed status is used to indicate that only completed procedures should be returned.

Procedure not done

QI-Core defines the ProcedureNotDone profile to represent documentation of the reason a particular procedure, or class of procedures, was not performed. By default, ProcedureNotDone resources in QI-Core are characterized by the code element.

define "Intermittent Pneumatic Compression Devices Not Applied":
  [ProcedureNotDone: "Application of Intermittent Pneumatic Compression Devices (IPC)"] DeviceNotApplied
    where DeviceNotApplied.statusReason in "Medical Reason" 
      or DeviceNotApplied.statusReason in "Patient Refusal"

NOTE: Because the ProcedureNotDone profile fixes the value of the status element to not-done, that element does not need to be tested in the expression.

Procedure ordered QI-Core defines the ServiceRequest profile to represent the proposal, planning, or ordering of a particular service. By default, ServiceRequest resources in QI-Core are characterized by the code element.

define "Intermittent Pneumatic Compression Devices Ordered":
  ["ServiceRequest": "Application of intermittent pneumatic compression devices (IPC)"] DeviceOrdered
    where DeviceOrdered.status in { 'active', 'completed', 'on-hold' }

NOTE: Because the ServiceRequest profile does not fix the value of the status element, authors must consider all the possible values of the element to ensure the expression matches measure intent. In this case, the active, completed, and on-hold statuses are used to ensure a positive order. NOTE: Because the ServiceRequest profile fixes the value of the doNotPerform element to false if it is present, that element does not need to be tested in the expression.

Procedure not ordered

QI-Core defines the ServiceNotRequested profile to represent documentation of the reason a particular service or class of services was not ordered. By default, ServiceNotRequested resources in QI-Core are characterized by the code element.

define "Intermittent Pneumatic Compression Devices Not Ordered":
  ["ServiceNotRequested": "Application of intermittent pneumatic compression devices (IPC)"] DeviceNotOrdered
    where (DeviceNotOrdered.reasonRefused in "Medical Reason"
      or DeviceNotOrdered.reasonRefused in "Patient Refusal")
      and DeviceNotOrdered.status in { 'active', 'completed', 'on-hold' }

NOTE: Because the ServiceNotRequested profile does not fix the value of the status element, authors must consider all the possible values of the element to ensure the expression matches measure intent. In this case, the active, completed, and on-hold statuses are used to ensure a valid order statement. NOTE: Because the ServiceNotRequested profile fixes the value of doNotPerform to true, that element does not need to be tested in the expression.

Devices

FHIR defines several resources related to the tracking and management of devices used by patients, including Device and DeviceRequest. It is important to note that the types of devices modelled by these profiles are those that are considered personal use by the patient (examples include frailty devices like canes, glucometers or CPAP machines). In comparison to STU 4.1.1, there are no new device profiles added to STU6 of QI-Core.

Device ordered

QI-Core defines the DeviceRequest profile to represent proposals, planning, and ordering of devices for a patient. By default, DeviceRequest resources in QICore are characterized by the code element, which can be represented as a code or a reference.

define "Device Indicating Frailty":
  [DeviceRequest: "Frailty Device"] FrailtyDeviceOrder
    where FrailtyDeviceOrder.status in { 'active', 'on-hold', 'completed' }
      and FrailtyDeviceOrder.intent in { 'order', 'original-order', 'reflex-order', 'filler-order', 'instance-order' }

NOTE: Because the DeviceRequest profile does not fix the value of the status element, authors must consider all the possible values of the element to ensure the expression matches measure intent. In this case the active, completed and on-hold statuses are used to ensure a positive device order.

NOTE: Because the DeviceRequest profile fixes the value of the doNotPerform element to false if it is present, that element does not need to be tested in the expression.

Device not ordered

QI-Core defines the DeviceNotRequested profile to represent documentation of the reason for not ordering a particular device, or class of devices. By default, DeviceNotRequested resources in QI-Core are characterized by the code element, which can be represented as a code or a reference.

define "CPAP not requested":
  ["DeviceNotRequested": "CPAP"] CPAPNotRequested
    where CPAPNotRequested.status in {'active'}
    and CPAPNotRequested.intent in {'plan', 'proposal', 'order'}

NOTE: Because the DeviceNotRequested profile fixes the value of doNotPerform to true, this element does not need to be tested in the expression.

Device in use

For those cases where measurement is looking to capture the use of a device, the Device profile should be used.

define "CPAP in use":
  ["Device": "CPAP"] CPAPInUse
    where CPAPInUse.status in {'active'}

Allergies

FHIR defines the AllergyIntolerance resource to represent allergies and intolerances for a patient. In comparison to STU 4.1.1, there are no new allergy/ intolerance profiles added to STU6 of QI-Core.

Current allergies

QI-Core defines the AllergyIntolerance profile to represent allergies and intolerances for a patient. By default, AllergyIntolerance resources in QI-Core are characterized by the code element.

define "Statin Allergy Intolerance":
  ["AllergyIntolerance": "Statin Allergen"] StatinAllergyIntolerance
    where StatinAllergyIntolerance.clinicalStatus is null 
      or StatinAllergyIntolerance.clinicalStatus ~ QICoreCommon."allergy-active"

NOTE: Because the AllergyIntolerance profile does not constrain the values of the clinicalStatus or verificationStatus elements of the resource, authors must consider the possible values of these elements to ensure the expression matches measure intent. In this case, the clinicalStatus, if present, must be "allergy-active".

No known allergies

US Core guidance for allergies (https://hl7.org/fhir/us/core/STU6.1/AllergyIntolerance-example.html) states that if a patient has been asked, but has indicated they have no known allergies, this would be represented as:

define "No Known Allergies":
 ["AllergyIntolerance": "No known allergy (situation)"] NKA
    where NKA.verificationStatus = "confirmed"

Immunizations

FHIR defines several immunization-related resources to track and manage the immunization information for a patient, including Immunization and ImmunizationRecommendation. In comparison to STU 4.1.1, there are no new immunization profiles added to STU6 of QI-Core.

NOTE: The Immunization resources are reflective of immunization information as recorded in an Immunization Information System. For immunizations as part of clinical workflow, the medication resources should be used?

Immunization performed

QI-Core defines the Immunization profile to represent immunization information for a patient. By default, Immunization resources in QI-Core are characterized by the vaccineCode element.

define "Polio Immunizations":
  ["Immunization": "Inactivated Polio Vaccine (IPV)"] PolioVaccination
    where PolioVaccination.status = 'completed'

NOTE: Because the Immunization profile does not fix the value of the status element, authors must consider all the possible values for the element to ensure the expression meets measure intent.

Immunization not performed

QI-Core defines the ImmunizationNotDone profile to represent documentation of the reason an immunization was not performed. By default, ImmunizationNotDone resources in QI-Core are characterized by the vaccineCode element.

define "Reason for No Polio Immunization":
  ["ImmunizationNotDone": "Inactivated Polio Vaccine (IPV)"] PolioVaccination
    where PolioVaccination.statusReason in "Medical Reason"
      or PolioVaccination.statusReason in "Patient Refusal"

NOTE: Because the ImmunizationNotDone profile fixes the value of the status element to not-done, this element does not need to be tested in the expression.

Communication

Communication

QI-Core defines the Communication profile to represent communications with or about the patient. It is important to note that the definition of the profile is "A record of information transmitted from a sender to a receiver". Measure developers looking to model clinical concepts like patient education should use the Procedure profile as that represents "An action that is being or was performed on a patient".

By default, Communication resources in QI-Core are characterized by the topic element. In comparison to STU 4.1.1, there are no new communication profiles added to STU6 of QI-Core.

define "Lab results communicated":
   ["Communication": "report-labs"] LabReport
       where LabReport.topic = 'report-labs'
       and LabReport.status = 'completed'
       and LabReport.reasonCode = 'Serum pregnancy test negative (finding)'

NOTE: Because the Communication profile does not fix the value of the status element, authors must consider all the possible values for the element to ensure the expression meets measure intent.

NOTE: This expression uses a direct-reference code of "Macular edema absent (situation)" (i.e. referencing a specific code from a code system, rather than a value set consisting of multiple codes). For more information on using direct-reference codes in CQL expressions, refer to the Codes topic in the Using CQL with FHIR IG.

Communication not done

QI-Core defines the CommunicationNotDone to represent documentation of the reason a communication was not done. By default, CommunicationNotDone resources in QI-Core are characterized by the topic element.

define "Medication Not Available":
["CommunicationNotDone": "progress update"] ProgressUpdate 
    where ProgressUpdate.topic = 'progress-update'
    and ProgressUpdate.status = 'completed'
    and ProgressUpdate.reasonCode = 'Medication not available from manufacturer (finding)'

NOTE: Because the CommunicationNotDone profile fixes the value of the status element to not-done, this element does not need to be tested in the expression.

NOTE: At this time, direct-reference codes cannot be used as the terminology target of a retrieve of a negation profile. Available workarounds for this issue are to either create a value set with the single required code or to use the long-hand expression of the negation statement.

Wiki Index

Home

Authoring Patterns - QICore v4.1.1

Authoring Patterns - QICore v5.0.0

Authoring Patterns - QICore v6.0.0

Authoring Measures in CQL

Composite Measure Development

Cooking with CQL Examples

Cooking with CQL Q&A All Categories
Additional Q&A Examples

CQL 1.3 Impact Guidance

CQL Error Messages

Developers Introduction to CQL

Discussion Items

Example Measures

Formatting and Usage Topics

Formatting Conventions

Library Versioning

Negation in QDM

QDM Known Issues

Specific Occurrences

Specifying Population Criteria

Supplemental Data Elements

Terminology in CQL

Translator Options For Measure Development

Unions in CQL

Clone this wiki locally