PreNUDGE FHIR® IG for Data Provider / Data from Apps (R4)
0.1.0 - ci-build

PreNUDGE FHIR® IG for Data Provider / Data from Apps (R4) - Local Development build (v0.1.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions

## StructureMap: Physical Activity Minutes Q to O

Official URL: https://fhir.hl7.at/prenudge/appdata/r4/StructureMap/PhysicalActivityMinutesQtoO | Version: 0.1.0
Draft as of 2026-06-25 | Responsible: The PreNUDGE Consortium | Computable Name: Physical Activity Minutes Q to O

Physical Activity EHIS-PAQ Q7 / ATHIS PE7 to O (aggregate-only variant)

    map "https://fhir.hl7.at/prenudge/appdata/r4/StructureMap/PhysicalActivityMinutesQtoO" = "Physical Activity Minutes Q to O"

    // Physical Activity EHIS-PAQ Q7 / ATHIS PE7 to O (aggregate-only variant)

    uses "http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse" alias QR as source
    uses "http://hl7.org/fhir/StructureDefinition/Observation" alias Obs as target

    imports "http://hl7.org/fhir/StructureMap/*"
    imports "https://fhir.hl7.at/prenudge/appdata/r4/StructureMap/QuestionnaireResponseToObservationBase"

    // ---------------------------------------------------------------------------
    // Main entry group
    // ---------------------------------------------------------------------------
    group PhysicalActivityQuestionnaireResponseToObservation(source src : QR, target tgt : Obs) {
      // Shared base: identifier copy, derivedFrom, subject, issued.
      // SetObservationBase also sets method = SCT 87982008 (Manual) — correct for
      // all questionnaire-derived observations in this IG.
      src then SetObservationBase(src, tgt) "Base";
      // Explicitly confirm method = Manual (base already does this; listed for clarity).
      src -> tgt.method = cc('http://snomed.info/sct', '87982008', 'Manual') "SetMethodManual";
      // Target profile
      src ->  tgt.meta = create('Meta') as meta,  meta.profile = 'https://fhir.hl7.at/prenudge/appdata/r4/StructureDefinition/at-prenudge-physical-activity-minutes-observation' "SetProfile";
      // Panel code
      src -> tgt.code = cc('http://loinc.org', '101691-4', 'Duration of physical activity') "SetCode";
      // effectiveDateTime from authored (EHIS-PAQ Q7 has no embedded date item)
      src.authored as authored -> tgt.effectiveDateTime = authored "SetEffectiveDateTime";
      // Map Q7 group to component[aggregateActivity]
      src.item as q7 where linkId = 'Q7' then MapQ7ToAggregate(q7, tgt) "ProcessQ7";
    // component[moderateActivity] : NOT mapped
    // Q7 asks for total leisure activity time without separating intensity levels.
    // There is no questionnaire source for a moderate-only figure.
    // component[vigorousActivity] : NOT mapped
    // Total leisure time maps directly to aggregateActivity (see MapQ7ToAggregate).
    // component[classificationMethod] : NOT mapped
    // method = Manual → component must be absent or self-rp (pa-manual-comp-01).
    // The map does not set it; a consuming system may add self-rp post-transform
    // if explicit documentation of the classification basis is required.
    }

    // ---------------------------------------------------------------------------
    // Q7 → component[aggregateActivity]  (LOINC 101691-4)
    // Formula: aggregateMinutes = (Q7-hours × 60) + Q7-minutes
    // This is a direct transcription of the patient-reported total time.
    // No intensity weighting is applied because Q7 does not capture intensity.
    // The ×2 vigorous weighting (WHO/IPAQ) is ONLY applied when a wearable
    // separately measures moderate and vigorous minutes (wearable variant).
    // Note on FML arithmetic / MaLaC-HD compatibility:
    // This map uses evaluate() with integer arithmetic (* 60, +) which is NOT
    // supported by MaLaC-HD 1.6.0. MaLaC-HD fails at parse time with
    // "Param type 14 not implemented" (integer literal in FHIRPath expression).
    // The questionnaire captures hours and minutes as separate integer items,
    // so no MaLaC-HD compatible rewrite exists without redesigning the questionnaire
    // or changing the output unit. Use matchbox or another evaluate()-capable engine.
    // ---------------------------------------------------------------------------
    group MapQ7ToAggregate(source src : QR, target tgt : Obs) {
      src -> tgt.component as aggComp then {
        // Component discriminator code: LOINC 101691-4
        // Note: same code as panel Observation.code — collision documented in profile.
        // obs-7 is not violated because Observation.value[x] is absent.
        src -> aggComp.code = cc('http://loinc.org', '101691-4', 'Duration of physical activity') "SetAggregateCode";
        src -> aggComp.value = create('Quantity') as qty then {
          // aggregateMinutes = (Q7-hours × 60) + Q7-minutes
          src -> qty.value = evaluate(src, (item.where(linkId = 'Q7-hours').answer.valueInteger * 60) + item.where(linkId = 'Q7-minutes').answer.valueInteger) "ComputeAggregateMinutes";
          src -> qty.unit = 'min/wk' "SetUnit";
          src -> qty.system = 'http://unitsofmeasure.org' "SetSystem";
          src -> qty.code = 'min/wk' "SetUCUM";
        } "SetAggregateQuantity";
      } "MapAggregateComponent";
    }