Situational Awareness for Novel Epidemic Response
1.0.1 - CI Build International flag

Situational Awareness for Novel Epidemic Response, published by HL7 International / Public Health. This guide is not an authorized publication; it is the continuous build for version 1.0.1 built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/HL7/fhir-saner/ and changes regularly. See the Directory of published versions

A Phrase Book for Measures Supporting Automation

This section of the IG explains possible ways to record the expressions used to automate a Measure. Essentially it is a phrase book from English to the Expression elements used in the PublicHealthMeasure resource to describe the automation. Due to different workflows and national requirements, these phrases may require translation to different FHIR models to represent the concept being tested.

Preferred models are marked with an asterisk.

The examples below are informative, and show how measures could be developed to support different constraints using existing vocabularies and value sets supported by HL7 FHIR.

In the text below, examples are based on measures analyzed from the CDC Patient Impact and Hospital Capacity module used for reporting in the first half of 2020 and shown below.

CDC Patient Impact and Hospital Capacity module

Active Patient Encounters

Encounters represent interactions between a patient and a healthcare provider in inpatient, outpatient or other settings. Many measures for situational awareness start with a patient encounter as the context for the measurement.

The HOSPITAL INPATIENT BED OCCUPANCY measure can be evaluated through encounters. The initial set of encounters can be retrieved using the Encounters?status=in-progress FHIR query, or represented as Encounter.where(status='in-progress') in FHIRPath.

Active Encounters Within a Time Frame

Both Encounter.period.start and Encounter.period.end can be tested for occurrence on a specific day, or within a given date range, allowing for tests of Admit/Discharge/Transfer/Death by date.

If looking for encounters started yesterday, and today is September 1, 2020, the appropriate FHIR query is: Encounter?date=sa2020-08-30T23:59:59&date=le2020-09-01. This query will find encounters that start after the last second of August 30, and which were present before September 1. These encounters must have been present Yesterday, and started after the day before yesterday, thus, must have started yesterday. The same query expressed as a filter in FHIRPath is Encounter.where(period.start.toDate() = @2020-08-31). FHIRPath provides finer grained access than FHIR queries, enabling direct access to the start component of the encounter period. The start component needs to be converted to a date to ensure that precision matches for the equals operator.

The first and second examples above can be combined to ensure that the encounters in question are still in-progress, and filter out other encounters (e.g., those created in error). For the FHIR query, this would be Encounters?status=in-progress&date=sa2020-08-30T23:59:59&date=le2020-09-01. In FHIRPath, this would be Encounter.where(period.start.toDate() = @2020-08-31 and status = 'in-progress')

Admission

An admission generally starts an encounter that lasts more than a single day, although might also be used for encounters lasting only a single day (e.g., emergency department encounters which could last more than a day, but often are completed with a single day).

Admission
An admission is identified from an Encounter that has not yet ended. Encounter.status should be “in-progress”. The date (and time) of admission can generally be determined from Encounter.period.start. Encounter.period.end will not be present, and Encounter.hospitalization.dispositionCode will also not be present, but the latter is not generally directly accessible through a search.
Examples for Admission
Locating Admissions via the Encounter resource
FieldDescriptionFHIR QueryFHIR PathCQL
Encounter.status Active encounters Encounter?status=in-progress Encounter.where(status='in-progress') [Encounter] E where E.status = 'in-progress'
Encounter.period.start Encounters starting on a given date or within a particular period Encounter?date=sa2020-09-07&date=lt2020-09-09
Because the date search parameter is compared to a period data type, the upper and lower bounds must be set in a way that ensures inclusion of the target period. Using a high precision time value for the sa component is less likely to run into implementation errors even though sa2020-09-07 **should** be equivalent.
Encounter.where(period.start >= @2020-09-08 and period.start < @2020-09-09)
It is generally preferable for comparisons in for a time period to use an the inclusive lower bound with greater than or equal to (>=) and an exclusive upper bound with less-than (<). This is less likely to run into implementation errors affecting date comparisions.
parameter MeasurementPeriod default Interval[@2020-09-08, @2020-09-09)
[Encounter] E where E.period starts during MeasurementPeriod

Encounters with a Disposition

The base FHIR specification does not support query by discharge disposition. Some FHIR Servers may be configurable to support this search. See the disposition search parameter for an example of a resource that can be used to support this capability. When present, discharge disposition codes are often populated according to requirements established for payment (e.g., US Medicare payment requirements, rather than treatment.

*The date of the disposition (discharge/transfer or death) may be determined from Encounter.period.end.

Locating Discharges, Transfers and Deaths via the Encounter resource
FieldDescriptionFHIR QueryFHIR PathCQL
Encounter.status Encounters that have been completed Encounter?status=finished Encounter.where(status='finished') [Encounter] E where E.status = 'finished'
Encounter.period.end Encounters ending on a given date or within a particular period. Encounter?date=ge2020-09-07T23:59:59&date=eb2020-09-09
Because the date search parameter is compared to a period data type, the upper and lower bounds must be set.
Encounter.where(period.end >= @2020-09-08 and period.end < @2020-09-09)
It is generally preferable for comparisons in for a time period to use an the inclusive lower bound with greater than or equal to (>=) and an exclusive upper bound with less-than (<). This is less likely to run into implementation errors affecting date comparisons.
parameter MeasurementPeriod default Interval[@2020-09-08, @2020-09-09)
[Encounter] E where E.period ends during MeasurementPeriod

To distinguish between discharge to home vs. a transfer to another facility vs. death, the value of *Encounter.hospitalization.disposionCode must be examined. Usually discharge means “to home” or other non-healthcare setting (e.g., another family member’s home). These cases are shown in more detail below.

Discharge

A discharge is represented by an Encounter that has been completed in some way, either Encounter.status is “finished” to indicate normal completion, or in some cases, the Encounter.status may be marked as “cancelled” for special cases. Encounter.hospitalization.dispositionCode should be present, and where the the patient was discharged to.

Locating Discharges via the Encounter resource
FieldDescriptionFHIR QueryFHIR PathCQL
Encounter.hospitalization.dispositionCode Transitions to home or similar settings Encounter?disposition=http://terminology.hl7.org/CodeSystem/discharge-disposition|home,
http://terminology.hl7.org/CodeSystem/discharge-disposition|alt-home
,
http://terminology.hl7.org/CodeSystem/discharge-disposition|aadvice</i>,
http://terminology.hl7.org/CodeSystem/discharge-disposition|oth</i>
Encounter.where(
hospitalization.dispositionCode.where(system='http://terminology.hl7.org/CodeSystem/discharge-disposition'
and code = ('home'|'alt-home'|'aadvice'|'oth') ) )
valueset HomeEnvironment http://example.com/valueset/HomeEvironment
[Encounter] E where E.hospitalization.dispositionCode in HomeEnvironment
Transfers

A transfer to another facility (inter-facility transfer) is like a discharge, except that the Encounter.hospitalization.dispositionCode should be present and indicates a transfer to a different healthcare setting (e.g., rehabilitation, hospice, long-term care).

Locating Transfers via the Encounter resource
FieldDescriptionFHIR QueryFHIR PathCQL
Encounter.hospitalization.dispositionCode Transitions to other healthcare settings other than home or death Encounter?disposition=http://terminology.hl7.org/CodeSystem/discharge-disposition|other-hcf,
http://terminology.hl7.org/CodeSystem/discharge-disposition|hosp,
http://terminology.hl7.org/CodeSystem/discharge-disposition|long,
http://terminology.hl7.org/CodeSystem/discharge-disposition|psy,
http://terminology.hl7.org/CodeSystem/discharge-disposition|rehab,
http://terminology.hl7.org/CodeSystem/discharge-disposition|snf
Encounter.where(
hospitalization.dispositionCode.where(system='http://terminology.hl7.org/CodeSystem/discharge-disposition'
and code = ('other-hcf'|'hosp'|'long'|'psy'|'rehab'|'snf') ) )
valueset TransferEnvironment http://example.com/valueset/TransferEnvironment
[Encounter] E where E.hospitalization.dispositionCode in TransferEnvironment
Notes
A transfer within a facility (intra-facility transfer) can mark a change in patient class (e.g., outpatient, emergency, observation, inpatient, long-term care) and type of service being provided, but may also simply indicate movement between locations within a facility.

Measure developers should provide clarity around the distinctions between discharge and transfer. Is discharge to home-health a “discharge” or a “transfer”? If “long-term care” is the same as “home” for the patient, how would different hospital workflows vary with regard to coding these values?

Death

Not every discharge is a good outcome. Discharge due to death requires special handling because of different hospital workflows used to track the death of a patient.

  1. *The discharge disposition may indicate death in the Encounter.hospitalization.dispositionCode value, or
  2. The fact that a patient has died (but not when) may appear in Patient.deceasedBoolean, or
  3. *The date of death may appear in Patient.deceasedDateTime, or
  4. A date of death may be recorded in an Observation for the patient, or
  5. The Location resource referenced by Encounter.hospitalization.destination may indicate a morgue or autopsy room in Location.type.

When testing for death during an encounter using date of death (numbers 3 and 4 above), take care to verify that death occurred during the encounter (i.e., date of death is >= Encounter.period.start and <= Encounter.period.end).

Locating Deaths via the Encounter resource
FieldDescriptionFHIR QueryFHIR PathCQL
Encounter.hospitalization.dispositionCode Transitions due to Death Encounter?disposition=http://terminology.hl7.org/CodeSystem/discharge-disposition|exp Encounter.where(
hospitalization.dispositionCode.where(system='http://terminology.hl7.org/CodeSystem/discharge-disposition'
and code = 'exp') ) )
valueset PatientExpired http://example.com/valueset/PatientExpired
[Encounter] E where E.hospitalization.dispositionCode in PatientExpired
Locating Deaths via the Patient resource
FieldDescriptionFHIR QueryFHIR PathCQL
Patient.deceasedDateTime Patient date of death Patient?death-date=2020-09-09 Patient.where(deceasedDateTime = @2020-09-09) [Patient] P where P.deceasedDateTime = @2020-09-09
Patient.deceased[x] Patient has died Patient?deceased=true // Patient has died, or there is a date of death
Patient.where(deceasedBoolean = true | deceasedDateTime.exists())
[Patient] P where P.deceasedBoolean = true or P.deceasedDateTime is not null
Patient has died within this encounter // NOTE: This query uses chained search, and will NOT test that the patient died during the encounter
// It will return both encounters and patients so that further analysis can
// be performed by the client. This sort of issue should be documented in
// Expression.description in the measure definition.
Encounter?patient.deceased=true&_include=Encounter:subject
Encounter.where(
// Patient has died during the encounter
(resolve(patient).deceasedDateTime >= $this.period.start and
 resolve(patient).deceasedDateTime <= $this.period.end) or
// Encounter is in-progress and patient has died
  ($this.status = 'in-progress' and
  // Patient has died, or there is a date of death
   resolve(patient).where(deceasedDateTime.exists() or deceasedBoolean = true)
  )
)
Context Encounter
[Patient] P where
P.id = E.patient and
// Patient has died during the encounter
 (P.deceasedDateTime in E.period or
// Encounter is in-progress and patient has died
  (E.status = 'in-progress' and
   (P.deceasedBoolean = true or P.deceasedDateTime is not null)
  )
 )

For a type of healthcare service (e.g., ED, Observation, Acute, ICU, Outpatient)

The type of healthcare service may be determined in a couple of different ways depending on hospital workflow:

  1. *It may be broadly coded in Encounter.class (e.g., ED, Observation, Acute, ICU, Outpatient), or
  2. Deeply coded in Encounter.serviceClass (more detailed encoding for different kinds of services, from which one can infer ED, Observation, et cetera.
  3. Encoded in the Location resource referenced by Encounter.location.location in Location.type, again, from which one can infer ED, Observation, et cetera.

Many HL7 standards use the HL7 Version 3 HealthcareServiceLocation vocabulary to describe locations. Based on the U.S. HSLOC Coding System is used to record the type of healthcare service for the HL7 Healthcare Acquired Infections Implementation Guides in both CDA and FHIR. This coding system supports development of value set that can be used in the expression to identify a location supporting a specific type of service.

Determining the type of service using Encounter resource
FieldDescriptionFHIR QueryFHIR PathCQL
Encounter.class Inpatient (Acute) Encounters Encounter?class=http://terminology.hl7.org/CodeSystem/v3-ActCode|ACUTE Encounter.where(status.where(system='http://terminology.hl7.org/CodeSystem/v3-ActCode' and code='ACUTE')) valueset AcuteEncounter http://example.com/valueset/AcuteEncounter [Encounter] E where E.class in AcuteEncounter
Encounter.serviceType Encounters providing a specific kind of service // NOTE: Requires custom search parameter for service-type Encounter?serviceType=http://terminology.hl7.org/CodeSystem/service-type|237 Encounter.where(serviceType.where(system='http://terminology.hl7.org/CodeSystem/service-type' and code='237') valueset EncounterServiceType http://example.com/valueset/EncounterServiceType
[Encounter] E where
E.serviceType in EncounterServiceType
Location.type Encounters in a specific type of location // NOTE: Used chained search for Encounters in a hospital unit Encounter?location.type=http://terminology.hl7.org/ValueSet/v3-ServiceDeliveryLocationRoleType|HU Encounter.where(location.physicalType.where(system='http://terminology.hl7.org/ValueSet/v3-ServiceDeliveryLocationRoleType' and code='HU')) valueset LocationType http://example.com/valueset/LocationType
context Encounter [Location] L where
L.id = Encounter.location L.type in LocationType

Temporary/Surge/Overflow

Some facilities, especially under stress will house patients in temporary locations, known as surge or overflow locations. NHSN defined these thus:

Overflow locations include any physical locations created to accommodate patients including but not > limited to 24-hour observation units, hallways, parking lots, or tents.

There is no common workflow or model used to represent this sort of situation. This IG recommends the use of a special code within Encounter.location.physicalType to identify a location that is a temporary location. This value should also appear within Location.physicalType in the location resource referenced by Encounter.location.location.

With a Given Condition or Symptom

Patient conditions or symptoms may appear in several places, with different degrees of confidence in the patient having the condition (e.g., admission, preliminary, differential, possible, or confirmed diagnosis).

Admitted/Seen for:

In the context of a given encounter, the condition may appear in:

  1. The Condition resource referenced by Encounter.diagnosis.condition in Condition.code. When using this field, consider also the value of Encounter.diagnosis.use, which encodes the provider confidence in the diagnosis, or
  2. As a coded value in Encounter.reasonCode, or
  3. As a reference to a Condition resource in Encounter.reasonReference, or
  4. As a reference to an Observation resource in Encounter.reasonReference
  5. As a problem in a Condition resource linked to the encounter, i.e., where Condition.encounter references the Encounter of interest.
  6. As a problem in a Condition resource from a prior period or encounter.
  7. As an finding reported in an Observation resource linked to the encounter i.e., where Observation.encounter references the encounter of interest. These observations may report subjective or objective findings during review of systems or physical examination (e.g., shortness of breath, sense of smell, et cetera).
  8. As a finding reported in an Observation from a prior period or encounter.

NOTE: In all cases where Condition is used, consider also the values of Condition.verificationStatus and Condition.clinicalStatus during evaluation. The verificationStatus indicates whether the condition is unconfirmed, provisional, confirmed or even refuted or entered-in-error. Note that the last two cases the patient does NOT have the condition. The clinicalStatus may describe clinical status of the condition of interest, using the value active, inactive or resolved. Again, note that resolved indicates the condition is no longer active.

The Condition.onset[x] and Condition.abatement[x] fields identity the time frame over which the condition was active. The Condition.recordedDate indicates when the provider recorded the condition in the system.

Determining the reason for care using Encounter resources
FieldDescriptionFHIR QueryFHIR PathCQL
Encounter.reasonCode Encounter for a specific disease by code Encounter?reason-code=http://snomed.info/sct|186747009,http://snomed.info/sct|713084008,http://snomed.info/sct|840539006,http://snomed.info/sct|840544004 Encounter.where(reasonCode.where(system='http://snomed.info/sct' and code=('186747009','713084008','840539006','840544004'))) valueset AcuteEncounter http://example.com/valueset/AcuteEncounter [Encounter] E where E.class in AcuteEncounter
Encounter.reasonReference Encounters referencing a condition resource // Chained search
Encounter.reasonReference.code=http://snomed.info/sct|186747009,
http://snomed.info/sct|713084008,
http://snomed.info/sct|840539006,
http://snomed.info/sct|840544004
Encounter.where(reasonReference.resolve().code.where(system='http://snomed.info/sct' and
code=('186747009','713084008','840539006','840544004'))
valueset COVID19Conditions http://example.com/valueset/COVID19Conditions
[Condition] C where
C.id = Encounter.reasonReference and
C.code in COVID19Conditions
Condition.code Condition recorded for a given encounter Condition?encounter=encounterId&
code=http://snomed.info/sct|186747009,http://snomed.info/sct|713084008,http://snomed.info/sct|840539006,http://snomed.info/sct|840544004
Condition.where(system='http://snomed.info/sct' and
code=('186747009','713084008','840539006','840544004')) and
encounter=encounterId
valueset COVID19Conditions http://example.com/valueset/COVID19Conditions
context Encounter [Condition] C where
C.encounter = Encounter.id
C.code in COVID19Conditions

Measures based on codes or results

Several different kinds of measures can be based on codes describing a diagnostic tests, a procedure, or other activity having been performed, and in the case of diagnostic tests, combinations including both the test code and result value.

Test / Procedure / Immunization Performed

Electronic laboratory reporting is used to track both the kinds of tested performed as well as the results. A commonly reported measure for COVID-19 is the number of COVID-19 diagnostic tests performed, regardless of outcome, where the results are then stratified by outcome. This can be counted by looking for the existence of an Observation or Procedure. Reporting of certain kinds of observations (e.g., Fraction of Inhaled Oxygen or Positive End Expiratory Pressure) are commonly reported for patients who are on a ventilator. Existence of these observations indicate that a patient is on a ventilator.

Determining the reason for care using Encounter resources
FieldDescriptionFHIR QueryFHIR PathCQL
Observation.code Diagnostic Result from a COVID-19 test Observation?code=http://loinc.org|94307-6,http://loinc.org|94308-4,http://loinc.org|94309-2,http://loinc.org|94310-0,
http://loinc.org|94314-2,http://loinc.org|94315-9,http://loinc.org|94316-7,http://loinc.org|94500-6,
http://loinc.org|94533-7,http://loinc.org|94534-5,http://loinc.org|94558-4,http://loinc.org|94559-2
Observation.where(code.where(system = 'http://loinc.org' and
code = ('19994-3','19995-0','19996-8','94310-0','94314-2','94315-9','94316-7','94500-6','94533-7','94534-5','94558-4','94559-2') ) )
valueset SarsCoV2Labs http://example.com/valueset/SarsCoV2Labs [Observation] O where O.code in SarsCoV2Labs
Observation.code Patients with observations indicating that they are on a ventilator Observation?code=http://loinc.org|19835-8,http://loinc.org|19994-3,http://loinc.org|20077-4,http://loinc.org|20079-0,http://loinc.org|20103-8,
http://loinc.org|20112-9,http://loinc.org|20115-2,http://loinc.org|33438-3,http://loinc.org|57655-3,http://loinc.org|76530-5,http://loinc.org|19839-0
Observation.where(code.where(system = 'http://loinc.org' and
code = ('19835-8','19994-3','20077-4','20079-0','20103-8','20112-9','20115-2','33438-3','57655-3','76530-5','19839-0') ) )
valueset PatientsOnVentilator http://example.com/valueset/PatientsOnVentilator [Observation] O where O.code in PatientsOnVentilator

The handling of Procedure or Immunization resources is similar. For Procedure, change Observation above to Procedure. For Immunization, change Observation to Immunization, and code to vaccine-code for FHIR Query, or to vaccineCode for FHIRPath and CQL.

Test with a coded result or interpretation

To test for a specific coded result, add the following clauses to the above expressions:

Determining the reason for care using Encounter resources
FieldDescriptionFHIR QueryFHIR PathCQL
Observation.valueCodeableConcept Coded Result matching a particular value &value-concept=http://snomed.info/sct|260385009 Observation.where( ... and valueCodeableConcept.where(system='http://snomed.info/sct' and value='260385009')) valueset NegativeResults http://example.com/valueset/NegativeResults [Observation] O where O.valueCodeableConcept in NegativeResults
Observation.interpretation A result interpretation of a specified value // NOTE: Requires custom search parameter for interpretation &interpretation=http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation|NEG Observation.where( ... and interpretation.where(system='http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation' and value='NEG')) valueset NegativeInterpretations http://example.com/valueset/NegativeInterpretations [Observation] O where O.interpreation in NegativeInterpretations

Test Value within a Range

Determining the reason for care using Encounter resources
FieldDescriptionFHIR QueryFHIR PathCQL
Observation.valueQuantity Quantity above/below/with a range &value-quantity=gt5.4|http://unitsofmeasure.org|mg
&value-quantity=lt5.4|http://unitsofmeasure.org|mg
&value-quantity=gt5.4|http://unitsofmeasure.org|mg&value-quantity=lt8.0|http://unitsofmeasure.org|mg
Observation.where( ... and valueQuantity > 5.4 'mg')
Observation.where( ... and valueQuantity < 5.4 'mg')
Observation.where( ... and valueQuantity > 5.4 'mg' and valueQuantity < 8.0 'mg')
[Observation] O where O.valueQuantity > 5.4 'mg'
[Observation] O where O.valueQuantity < 5.4 'mg'
[Observation] O where O.valueQuantity > 5.4 'mg' and O.valueQuantity < 8.0 'mg'
</tr> </tbody> </table> ### Handling Temporal Relationships In the example below, NHSN defined HOSPITAL ONSET for COVID-19 as shown below: > HOSPITAL ONSET: Patients currently hospitalized in an inpatient bed with onset of suspected or confirmed COVID-19 fourteen or more days after hospital admission due to a condition other than COVID-19 This kind of query cannot be handled directly using a FHIR Search query, as it requires computing a relationship between to related resources. In FHIRPath, assuming both the encounter and condition are available in the current set of results, one would write: ``` Condition.where(resolve(encounter).period.start + 14 'days' < onsetDateTime) ``` This expression will select Condition resources for which the associated Condition.encounter.period.start date plus 14 days is less than the time of onset of the condition. A similar expression can be written for CQL: ``` [Condition] C where C.encounter = Encounter.id and C.code in COVID19Conditions and C.onset - 14 days > Encounter.period.start ```