Skip to main content

Digital Quality Measures (DQM)

The fhir4ds.dqm module evaluates FHIR Measure resources with their CQL logic against a DuckDB-backed FHIR resources view. It is designed for production batch runs as well as Python workflows: load source data, load terminology, evaluate one or more measures, and write patient-level results plus FHIR MeasureReport resources.

1. Evaluation Workflow

Most DQM runs follow the same shape:

  1. Load FHIR resources into the standard resources view.
  2. Load expanded ValueSets used by the measure libraries.
  3. Parse each FHIR Measure and resolve its referenced CQL library.
  4. Translate CQL populations to vectorized DuckDB SQL.
  5. Write tabular results, summaries, optional definition outputs, and optional FHIR MeasureReport resources.

For production jobs, prefer the CLI batch runner. For notebooks, tests, and custom applications, use MeasureEvaluator directly.

For source-specific examples, see Source-to-DQM Production Recipes. For CLI behavior and exit codes, see the Command Line Interface.

For HAPI FHIR PostgreSQL deployments that need event-driven recalculation and persisted patient-level measure results, see HAPI FHIR Server Integration.

2. CLI Batch Runner

The CLI exposes three DQM subcommands:

fhir4ds dqm validate --config dqm-run.json
fhir4ds dqm inspect --config dqm-run.json
fhir4ds dqm run --config dqm-run.json

validate checks paths and required configuration. inspect prints the measures, libraries, valuesets, outputs, and audit settings that will be used. run evaluates the configured measures and writes one output directory per measure.

Config File

{
"measures": [
{
"id": "CMS124",
"path": "./measures/Measure-CMS124.json",
"cql": "./cql/CMS124FHIR.cql"
}
],
"libraries": {
"paths": ["./cql"]
},
"source": {
"type": "filesystem",
"path": "./bulk-export/**/*.ndjson",
"format": "ndjson"
},
"terminology": {
"valuesets": ["./valuesets"]
},
"period": {
"start": "2025-01-01",
"end": "2025-12-31"
},
"audit": {
"mode": "population",
"narratives": false
},
"outputs": {
"directory": "./dqm-output",
"formats": ["json", "parquet"],
"measure_reports": "both",
"definitions": {
"mode": "all",
"formats": ["json"],
"include_sde": false
}
},
"continue_on_error": true
}

CLI-Only Run

For a single measure, the same run can be launched without a config file:

fhir4ds dqm run \
--measure ./measures/Measure-CMS124.json \
--cql ./cql/CMS124FHIR.cql \
--library-dir ./cql \
--source "./bulk-export/**/*.ndjson" \
--source-type filesystem \
--source-format ndjson \
--valuesets ./valuesets \
--period 2025-01-01:2025-12-31 \
--audit-mode population \
--measure-reports both \
--definitions all \
--definition-format json \
--output ./dqm-output

3. Outputs

Each successful measure run writes a directory named from the measure id:

dqm-output/
run.json
CMS124/
results.json
results.parquet
summary.json
MeasureReport-summary.json
definitions.json
definitions.schema.json
individual-reports/
patient-1.json
patient-2.json

Tabular Results

results.<format> contains one row per evaluated patient or population-basis record. It always includes patient_id and population columns such as initial_population, denominator, numerator, and exclusion/exception columns when they are present in the measure.

When audit is enabled, population columns contain audit structs rather than bare booleans. The struct has a result value and an evidence list. CSV output serializes dict/list cells as JSON strings.

Summary

summary.json contains aggregate population counts, denominator/numerator final counts, performance rate, and stratifier summaries when the Measure defines stratifiers.

Definition Outputs

outputs.definitions writes CQL define statements as machine-readable per-patient columns. Use this when downstream systems need more than final population membership.

Supported modes:

ModeBehavior
noneDo not write definition outputs.
allWrite every define in the primary CQL library, excluding SDE* by default.
selectedWrite only the names listed in outputs.definitions.names.

definitions.schema.json maps output column names back to authored CQL define names. This is important because output columns are normalized to SQL-safe names.

4. MeasureReport Resources

Set outputs.measure_reports to control FHIR MeasureReport output:

ModeOutput
noneNo MeasureReport resources.
summaryOne aggregate MeasureReport-summary.json per measure.
individualOne individual report per patient in individual-reports/.
bothWrite summary and individual reports.

Summary reports include the computed performance rate extension:

{
"url": "http://hl7.org/fhir/us/davinci-deqm/StructureDefinition/performanceRate",
"valueDecimal": 0.84
}

Individual reports use the Da Vinci DEQM individual MeasureReport profile:

{
"resourceType": "MeasureReport",
"type": "individual",
"meta": {
"profile": [
"http://hl7.org/fhir/us/davinci-deqm/StructureDefinition/indv-measurereport-deqm"
]
},
"subject": {
"reference": "Patient/patient-1"
}
}

The engine preserves authored Measure group and population ids in the MeasureReport when present. It also adds R5 backport linkId extensions so consumers can correlate report groups/populations with the source Measure.

5. Supporting Evidence

FHIR4DS reads Measure-authored cqf-supportingEvidenceDefinition references on population criteria and can serialize the corresponding values into individual reports using cqf-supportingEvidence.

The extension is attached to the relevant MeasureReport.group.population.extension entry. Each supporting evidence item contains:

  • name: the referenced CQL expression name.
  • description: if provided by the Measure.
  • code: if provided by the Measure.
  • value: the evaluated CQL result for the individual patient.

Example:

{
"url": "http://hl7.org/fhir/StructureDefinition/cqf-supportingEvidence",
"extension": [
{
"url": "name",
"valueCode": "Most Recent Blood Pressure"
},
{
"url": "value",
"valueReference": {
"reference": "Observation/bp-1"
}
}
]
}

Supporting evidence is gathered during the primary measure evaluation when individual reports are requested. It does not require a second evidence-only evaluation. If audit mode wraps a value as {result, evidence}, only result is serialized into the MeasureReport extension; internal audit trace details remain in the tabular audit output.

6. Audit Modes

Audit mode controls how much evidence is captured in results.<format>:

ModeUse ForCost
noneFast production scoring and summary reports.Lowest
populationRoutine review, individual reports, and resource-level evidence.Moderate
fullDeep debugging of CQL logic and expression-level traceability.Highest

Narratives require audit mode and add human-readable text to audit structs. Use them for review workflows, not default scoring jobs.

For routine batch output with individual MeasureReports, start with audit.mode = "population". Use full only when expression-level debugging is needed.

7. Python API

import fhir4ds
from fhir4ds.dqm import MeasureEvaluator, AuditMode
from fhir4ds.sources import FileSystemSource

con = fhir4ds.create_connection(
source=FileSystemSource("./bulk-export/**/*.ndjson", format="ndjson")
)

evaluator = MeasureEvaluator(con)
result = evaluator.evaluate(
measure_bundle="./measures/Measure-CMS124.json",
cql_library_path="./cql/CMS124FHIR.cql",
include_paths=["./cql"],
parameters={"Measurement Period": ("2025-01-01", "2025-12-31")},
audit_mode=AuditMode.POPULATION,
include_supporting_evidence=True,
)

summary = evaluator.summary_report(result)
report = evaluator.to_measure_report(
result,
period_start="2025-01-01",
period_end="2025-12-31",
report_type="summary",
)

8. Artifact Resolvers

Rather than passing raw file paths for measure_bundle and cql_library_path, FHIR4DS supports pluggable Artifact Resolvers. This is crucial for integrating with FHIR servers like HAPI, where Measures and ValueSets are fetched dynamically via canonical URLs.

For full details, see the Artifact Resolvers API Reference.

9. Compiled Measures

For production workloads involving thousands of patients, translating CQL to SQL per-patient is inefficient. FHIR4DS introduces the compile_measure() API, which allows you to compile the Measure and CQL into a highly optimized DuckDB SQL plan once, and execute it repeatedly across patient batches.

# 1. Compile the measure once
compiled = evaluator.compile_measure(
measure_ref="http://example.org/fhir/Measure/CMS122|2025",
artifact_resolver=resolver, # Load from HAPI, file system, etc.
patient_scope="target_table",
)

# 2. Execute repeatedly
for batch in patient_batches:
result = evaluator.execute_compiled_measure(
compiled,
patient_ids=batch
)
# ... process results

See the DQM API Reference for the full Python and batch configuration surface. For CI and benchmark baseline maintenance, see the repository's CONTRIBUTING.md file.