This page is part of the CDISC Mapping FHIR IG (v0.1.0: STU 1 Ballot 1) based on FHIR R4. The current version which supercedes this version is 1.0.0. For a full list of available versions, see the Directory of published versions
Contents:
This domain contains two mapping tables. The first is similar to the other domains and covers the SDTM and CDASH specification. The second covers the CDISC LAB specification. It is handled as a separate table because it has a significantly larger number of data elements than the other two specifications and the element names have less correlation. Readability of the mappings was enhanced by moving the content to a separate specification.
Lab data in FHIR is handled by two primary resources:
The CDISC specifications focus almost exclusively on the latter. As a result, mappings in both tables are expressed from the perspective of an Observation-rooted transformation. (I.e. All paths are rooted in Observation or are driven by a search based on Observation.) For studies interested in the retrieval of legacy lab information, it may in some cases be necessary to retrieve the DiagnosticReport and manually extract information from a PDF or other report representation. Obviously no standardized mapping can be provided here to assist with that.
In FHIR, the Observation resource is used for a wide range of data collection purposes. In addition to lab data, it is also used to capture vital signs, patient symptoms, psychological assessments, device data, and others. Ideally, lab data can be distinguished from types of Observations using the Observation.category element which should, ideally, have a code of laboratory
drawn from the http://terminology.hl7.org/CodeSystem/observation-category. However, the core FHIR specification does not mandate the use of this code or system. (The U.S. Realm implementation guide and several other national implementation guides do mandate the use of this category.)
The 'laboratory' category encompasses both simple chemical measurements as well as complex assessments including the description of genetic variants, microbiology tests, etc. This implementation guide focuses only on simple measurements and does not attempt to map more complex structures - which in some cases correspond to distinct CDISC domains. In part, this is because FHIR has not yet tried to enforce standardized representation of more complex areas, though initial work has been completed on the capture of genetic findings. Future versions of this implementation guide will likely tackle more complex lab structures.
Guidance on interpreting the table can be found here.
CDISC | FHIR map (or gap) | Comment | |||
---|---|---|---|---|---|
Name | CDASH | SDTM | Element | FHIRPath | |
Study ID or Number | STUDYID | STUDYID | ResearchStudy.identifier |
ResearchSubject.where(subject=Observation.subject).study.resolve().partOf.resolve().identifier.value Observation.extension(workflow-researchstudy).valueReference.resolve().partOf.resolve().identifier.value |
Mapping is based on presumption that research subject will be tied to site-specific ResearchStudy, which will then be part of overall ResearchStudy. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. |
Site ID or Number | SITEID | SITEID | ResearchStudy.identifier |
ResearchSubject.where(subject=Observation.subject).study.resolve().identifier.value Observation.extension(workflow-researchstudy).valueReference.resolve().identifier.value |
Mapping is based on presumption that research subject will be tied to site-specific ResearchStudy, which will then be part of overall ResearchStudy. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. |
Investigator ID or Number | INVID | INVID | Practitioner.identifier |
ResearchSubject.where(subject=Observation.subject).study.resolve().principleInvestigator.resolve().identifier.value Observation.extension(workflow-researchstudy).valueReference.resolve().principleInvestigator.resolve().identifier.value |
Will need to decide which id to expose. If you want the PI for the overall study rather than just for the site associated with the Observation, you'll need to traverse the partOf.resolve() from the study-specific ResearchStudy. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. |
Screen ID or Number (pre-randomization) | SUBJID | SUBJID | ResearchSubject.identifier |
ResearchSubject.where(individual=Observation.subject).identifier.value |
Study subject is found by finding the StudySubject that corresponds to the same Patient and ResearchStudy as the Observation. No standard way to decide which subject identifier to use |
Visit ID or Number | VISITNUM | VISITNUM | Encounter.identifier |
Observation.encounter.resolve().identifier |
|
Visit Name | VISIT | VISIT | ActivityDefinition.name |
Observation.encounter.resolve().extension(workflow-instantiates).valueCanonical.resolve().title |
We could go through Encounter.basedOn-> ServiceRequest.instantiatesCanonical, you arrive at ActivityDefinition. Encounter should have a standard instantiatesCanonical extension that would allow pointing to the ActivityDefinition. This would be the ActivityDefinition.name. Submit a change request to add the extension |
Accession ID or Number | LBREFID | LBREFID | Specimen.accessionIdentifier |
Observation.specimen.resolve().accessionIdentifier.value |
|
Specimen Actual Collection Start Date and Time | LBDTC | Specimen.collection.collectedPeriod |
Observation.specimen.resolve().collection.collectedPeriod.start |
||
Specimen Actual Collection End Date and Time | LBENDTC | Specimen.collection.collectedPeriod |
Observation.specimen.resolve().collection.collectedPeriod.end |
||
Specimen Collection Duration (for Clinical Research with extended time of collection) | LBCDUR | LBDUR | Specimen.collection.collectedPeriod |
Observation.specimen.resolve().collection.collectedPeriod |
|
Specimen Planned Time Point Name (Planned Collection Time Point - time within Encounter) | LBCTPT | LBTPT | Specimen.extension |
Observation.specimen.resolve().extension(cqf-relativeDateTime).valueReference.reference |
TBD - change being made to Specimen resource |
Specimen Planned Elapsed Time from Time Point Reference | LBCELTM | LBELTM | Specimen.extension |
Observation.specimen.resolve().extension(cqf-relativeDateTime).valueReference.reference |
TBD - change being made to Specimen resource |
Specimen Condition | LBCSPCCN | LBSPCCND | Specimen.condition |
Observation.specimen.resolve().condition.coding.code |
TBD - change being made to Specimen resource Extend the FHIR vocabulary to include CDISC values. NOTE: requires an extension to the FHIR vocabulary to include CDISC values (e.g., Refrigerated) |
Specimen Type | LBCSPEC | LBSPEC | Specimen.type |
Observation.specimen.resolve().type.coding.display |
NOTE: In some cases, this may be inferred from the LOINC. |
Fasting Status | LBCFAST | LBFAST | Specimen.collection.fastingStatus |
Observation.specimen.resolve().collection.fastingStatus.coding.code |
|
Condition Met (Y/N) | LBCOND | This is an 'ask on entry' question. May be able to determine some conditions, such as fasting, by using other specimen.collection attributes (e.g., fasting status). Others might be captured as components or extensions. Alternatively, obtain this information from the case report form entries. | There are explicit elements for Specimen.collection.fastingStatus and collection.fastingDuration. May need extensions for other pre-conditions | ||
Specimen Collection Position | LBCPOS | LBPOS | Specimen.colelction.extension |
Observation.specimen.resolve().collection.extension(observation-bodyPosition).valueCodeableConcept |
|
Specimen Usability for the Test | LBCSPCUF | LBSPCUFL | Specimen.status |
Observation.specimen.resolve()status.where($this='Unsatisfactory') |
|
Category | LBCCAT | LBCAT | DiagnosticReport.category.code |
DiagnosticReport.category.code.where(system='LBSCAT') |
NOTE: In some cases, this may be inferred from the LOINC. |
DiagnosticReport.code |
DiagnosticReport.code.text |
||||
Test Status | LBCSTAT | LBSTAT | ServiceRequest.doNotPerform |
Observation.basedOn.resolve().doNotPerform |
Sponsor may choose to map a situation in which the entire panel is cancelled as one summary record compliant with SDTM IG examples. Some sponsor may decline to accept cancelled records under specific circumstances (e.g., unscheduled) Sponsor may also choose to populate LBREASND as CANCELLED |
ServiceRequest.status |
Observation.basedOn.resolve().status |
||||
Reason Test Not Done | LBREASND | Observation.dataAbsentReason |
Observation.dataAbsentReason.text |
see notes on LBSTAT | |
Test Code | LBTESTCD | Observation.code |
Observation.code.coding.where(selected=true).code |
||
Test Name | LBTEST | Observation.code |
Observation.code.coding.where(selected=true).display |
||
Test LOINC Code | LBLOINC | LBLOINC | Observation.code |
Observation.code.coding.where(system='LOINC').code |
|
Performing Laboratory Name | LBNAM | LBNAM | Organization.name |
Observation.performer.where($this is Organization).resolve().name |
|
Reference Range Indicator | LBCNRIND | LBNRIND | Observation.interpretation |
Observation.interpretation.where(system ='NRIND') |
|
Toxicity Grade | LBTOXGR | Observation.interpretation |
Observation.interpretation.where(system=[Toxicity Grade]).coding.code |
||
Toxicity Grade Code List Version | LBCTOXV | LBTOX - 2 | Observation.interpretation |
Observation.interpretation.where(system=[Toxicity Grade]).coding.version |
|
Toxicity Grade Code List | LBCTOX | LBTOX - 1 | Observation.interpretation |
Observation.interpretation.where(system=[Toxicity Grade]).system |
|
Reported Reference Range Low | LBORNRLO | LBORNRLO | Observation.referenceRange |
Observation.referenceRange.low |
|
Reported Reference Range High | LBORNRHI | LBORNRHI | Observation.referenceRange |
Observation.referenceRange.high |
|
Reference Range (for string value) | LBCSTNRC | LBSTNRC | Observation.referenceRange |
Observation.referenceRange.text |
|
Result Value (numeric) | LBORRES | LBORRES | Observation.valueQuantity |
Observation.valueQuantity.value |
Might also include valueQuantity.comparator |
Result Value (string) | LBORRES | LBORRES | Observation.valueCodeableConcept |
Observation.valueCodeableConcept.text |
|
Reported Units | LBRESU | LBORRESU | Observation.valueQuantity |
Observation.valueQuantity.unit |
|
Result Clinically Significant (Y/N) | LBCLSIG | SUPPLB.QVAL | Observation.interpretation |
Observation.interpretation |
|
Method | LBCMETH | LBMETHOD | Observation.method |
Observation.method |
|
Anatomical Region | LBLOC | Specimen.bodySite |
Observation.specimen.resolve().collection.bodySite |
||
Run ID (ties data together across subjects) | LBRUNID | LBRUNID | Would need to introduce an extension | ||
Unique Subject ID for Sponsor | USUBJID | ResearchSubject.identifier |
ResearchSubject.where(individual=Observation.subject).identifier.value |
To distinguish SUBJID from USUBJID, would need to look at identifier.system | |
Result Categorization | LBRESCAT | LBRESCAT | This wouldn't come from the lab. | ||
Anatomical Region | LBANTREG | LBANTREG | Specimen.collection.bodySite |
Observation.specimen.resolve().collection.bodySite |
|
Unscheduled Flag | LBUSCHFL | LBUSCHFL | This can sort of be inferred from the absence of a link to a PlanDefinition or ActivityDefinition, however there are lots of other reasons these links could be missing, so that's not totally reliable. Could look at using an extension or a tag | ||
Planned Time Point Number (sequence to order the relative timepoints) | LBTPTNUM | Pull this information from the Clinical Plan (PlanDefinition) | Link to the clinical plan would be through the Observation.basedOn link to CarePlan or the instantiatesCanonical link to PlanDefinition or ActivityDefinition | ||
Analytical Method | LBANMETH | This does not apply to safety labs. | The corresponding values need to be evaluated and aligned accordingly to the CDISC context of --METHOD. Potentially could appear in Observation.method. An extension is required to distinguish. | ||
Baseline Flag | LBBLFL | Variable may be deprecated. This information would come from the Sponsor. | Could appear in Observation.reasonCode. In practice the notion of 'baseline' is more of a relationship. Any arbitrary Observation might be selected as the 'baseline' for a particular step in the study. As such, the real linkage is the tie to the CarePlan activity that's tied to the ActivityDefinition with a reason of 'baseline'. | ||
Derived Flag | LBDRVFL | This information would come from the Sponsor. | FHIR doesn't use a flag. If an Observation is derived, it should point to the Observations it's derived from with the derivedFrom association. (If that relationship is present, then the Derived Flag is true) |
Guidance on interpreting the table can be found here.
CDISC | FHIR map (or gap) | Comment | ||
---|---|---|---|---|
Name | LAB | Element | FHIRPath | |
Study ID or Number | /GTP/Study/@ID | ResearchStudy.identifier |
ResearchSubject.where(subject=Observation.subject).study.resolve().partOf.resolve().identifier.value Observation.extension(workflow-researchstudy).valueReference.resolve().partOf.resolve().identifier.value |
Mapping is based on presumption that research subject will be tied to site-specific ResearchStudy, which will then be part of overall ResearchStudy. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. |
Study Name | /GTP/Study/@Name | ResearchStudy.title |
ResearchSubject.where(subject=Observation.subject).study.resolve()partOf.resolve().title Observation.extension(workflow-researchstudy).valueReference.resolve().partOf.resolve().title |
Mapping is based on presumption that research subject will be tied to site-specific ResearchStudy, which will then be part of overall ResearchStudy. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. |
Transmission Type | /GTP/Study/@TransmissionType | Determine from type of call to service (requesting all data vs incremental data). NOTE: If data are not persisted between FHIR and LAB, cannot do incremental data processing (due to lack of delta detection). | If the data is being 'pushed' in a message, this could also be conveyed in the MessageHeader.event | |
Study Transaction Type | /GTP/Study/TransactionType | Determining whether transactions are insert or update is a task for the data consumer. (NOTE: This requires persistent storage to compare current data with data in the incoming file) | This would be conveyed using a transaction Bundle - specifically the Bundle.entry.request.method | |
Site ID or Number | /GTP/Study/Site/@ID | ResearchStudy.site |
ResearchSubject.where(subject=Observation.subject).study.resolve().identifier.value Observation.extension(workflow-researchstudy).valueReference.resolve().identifier.value |
Mapping is based on presumption that research subject will be tied to site-specific ResearchStudy, which will then be part of overall ResearchStudy. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. |
Site Transaction Type | /GTP/Study/Site/TransactionType | Determining whether transactions are insert or update is a task for the data consumer. (NOTE: This requires persistent storage to compare current data with data in the incoming file) | As per study transaction type (not clear why it happens at both levels - what would it mean to 'delete' at the study level and 'update at the site level?) | |
Investigator ID or Number | /GTP/Study/Site/Investigator/@ID | Practitioner.identifier |
ResearchSubject.where(subject=Observation.subject).study.resolve().principleInvestigator.resolve().identifier.value Observation.extension(workflow-researchstudy).valueReference.resolve().principleInvestigator.resolve().identifier.value |
Will need to decide which id to expose. If you want the PI for the overall study rather than just for the site associated with the Observation, you'll need to traverse the partOf.resolve() from the study-specific ResearchStudy. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. |
Investigator Name | /GTP/Study/Site/Investigator/@Name | Practitioner.name.text |
ResearchSubject.where(subject=Observation.subject).study.resolve().principleInvestigator.resolve().name.text Observation.extension(workflow-researchstudy).valueReference.resolve().principleInvestigator.resolve().name.text |
Will need to decide which name to expose. Can also extract the prefix, given and family names if text isn't specified. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. |
Investigator Transaction Type | /GTP/Study/Site/Investigator/TransactionType | Determining whether transactions are insert or update is a task for the data consumer. (NOTE: This requires persistent storage to compare current data with data in the incoming file) | As per study transaction type (not clear why it happens at both levels - what would it mean to 'delete' at the study level and 'update at the site level?) | |
Screen ID or Number | /GTP/Study/Site/Investigator/Subject/ScreenID | ResearchSubject.identifier |
ResearchSubject.where(subject=Observation.subject).identifier.value |
Study subject is found by finding the StudySubject that corresponds to the same Patient and ResearchStudy as the Observation. No standard way to decide which subject identifier to use. Also no standard way to differentiate subject id from screening id from spare subject id. |
Subject ID or Number | /GTP/Study/Site/Investigator/Subject/SubjectID | ResearchSubject.identifier |
ResearchSubject.where(subject=Observation.subject).identifier.value |
Study subject is found by finding the StudySubject that corresponds to the same Patient and ResearchStudy as the Observation. No standard way to decide which subject identifier to use. Also no standard way to differentiate subject id from screening id from spare subject id. |
Spare subject level ID or Number | /GTP/Study/Site/Investigator/Subject/SpareSubjectID | ResearchSubject.identifier |
ResearchSubject.where(subject=Observation.subject).identifier.value |
Study subject is found by finding the StudySubject that corresponds to the same Patient and ResearchStudy as the Observation. No standard way to decide which subject identifier to use. Also no standard way to differentiate subject id from screening id from spare subject id. |
Subject Sex | /GTP/Study/Site/Investigator/Subject/Sex/@Value | Patient.gender |
ResearchSubject.where(subject=Observation.subject).individual.resolve().gender |
|
Subject Sex Code List ID | /GTP/Study/Site/Investigator/Subject/Sex/@CodeListID | For FHIR, the administrative gender code list is fixed, so no need to send it in the instance. If there's a need to convey alternate gender codes, then those would appear either as Observation values or as extension values on Patient (the former for clinical information, the latter for administrative purposes). In either event, the code would be in CodeableConcept.coding which allows identifying both the code system and (if relevant), the version | ||
Subject Race | /GTP/Study/Site/Investigator/Subject/Race/@Value | There's an US-core extension (us-core-race) for capturing this in the U.S. and the possibility that other countries will define their own extensions. Note that this is for administrative, not clinical purposes. Genetic heritage would typically be captured as an Observation | ||
Subject Race Code List ID | /GTP/Study/Site/Investigator/Subject/Race/@CodeListID | Race, whether captured as an extension or observation value is generally a CodeableConcept allowing capturing both code system and (if relevant) version. Race is highly variable from country to country (both whether it's allowed and how it's coded), so there's no standard element for this in the core spec. | ||
Subject Initials | /GTP/Study/Site/Investigator/Subject/Confidential/@Initials | Patient.name.text |
ResearchSubject.where(subject=Observation.subject).individual.resolve().name.text |
Note that name.text will typically contain the full name, but *can* contain initials only. If the full name is present, initials can be extracted by looking at the given and family name components and converting to initials |
Subject Date Of Birth | /GTP/Study/Site/Investigator/Subject/Confidential/@Birthdate | Patient.birthDate |
ResearchSubject.where(subject=Observation.subject).individual.resolve().birthDate |
Note that precision can vary (YYYY, YYYY-MM or YYYY-MM-DD) |
Visit ID or Number | /GTP/Study/Site/Investigator/Subject/Visit/@ID | Encounter.identifier |
Observation.encounter.resolve().identifier.value |
No standard way to decide which identifier to use if multiples are present |
Visit Name | /GTP/Study/Site/Investigator/Subject/Visit/@Name | In practice, visit name would be the ActivityDefinition.title for the activity in the protocol associated with the encounter. There is no standard extension for this link (though one will be defined). Most clinical systems won't actually capture this, so the determination will need to be made at time of data extraction based on the protocol | See LB mapping comment | |
Visit Type | /GTP/Study/Site/Investigator/Subject/Visit/@Type | This is essentially whether the visit is tied to a particular activity within the PlanDefinition (study protocol) or not. Given that in non-study-specific systems, there won't typically be a linkage even when the encounter *is* driven by the study, this will generally need to be populated algorithmically on extension | This could theoretically be distinguished by whether there was a link to a CarePlan activity or ActivityDefinition. Alternatively, you could use an extension or tag. (What's 'planned' for one study might be unplanned for another) This would be Encounter.reasonCode |
|
Visit Type Modifier | /GTP/Study/Site/Investigator/Subject/Visit/@TypeModifier | Encounter.reasonCode |
Observation.encounter.resolve().reasonCode |
This would be Encounter.reasonCode |
Subject Transaction Type | /GTP/Study/Site/Investigator/Subject/TransactionType | Determining whether transactions are insert or update is a task for the data consumer. (NOTE: This requires persistent storage to compare current data with data in the incoming file) | As per study transaction type (not clear why it happens at both levels - what would it mean to 'delete' at the study level and 'update at the site level?) | |
Accession ID or Number | /GTP/Study/Site/Investigator/Subject/Visit/Accession/@ID | Specimen.accessionIdentifier |
Observation.resolve().accessionIdentifier.value |
|
Last Active Date and Time | /GTP/Study/Site/Investigator/Subject/Visit/Accession/@LastActiveDateTime | FHIR allows capture meta.lastUpdated which reflects when the data last changed on the server in question, but would need to look at Provenance to see when data last changed on a particular system. This typically won't be available. | ||
Visit Transaction Type | /GTP/Study/Site/Investigator/Subject/Visit/Accession/TransactionType | Determining whether transactions are insert or update is a task for the data consumer. (NOTE: This requires persistent storage to compare current data with data in the incoming file) | As per study transaction type (not clear why it happens at both levels - what would it mean to 'delete' at the study level and 'update at the site level?) | |
Central Laboratory ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/CentralLab/@ID | Organization.identifier |
Observation.performer.resolve().identifier.value |
Will need to look at identifier.type or identifier.system to know which identifier to use. In some cases, performer might be PractitionerRole, in which case, will need to map through PractitionerRole.organization. If there are multiple performers that link to multiple organizations, converter will need to look at Organization.type or have other rules to decide amongst the candidates. |
Central Laboratory Name | /GTP/Study/Site/Investigator/Subject/Visit/Accession/CentralLab/@Name | Organization.name |
Observation.performer.resolve().name |
If there are multiple performers that link to multiple organizations, converter will need to look at Organization.type or have other rules to decide amongst the candidates. |
Specimen ID or Number | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/@ID | Specimen.identifier |
Observation.specimen.resolve().identifier.value |
If there are multiple identifiers, need to look at identifier.system or identifier.type to determine |
Actual Collection Date and Time | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenCollection/@ActualCollectionDateTime | Specimen.collection.collectedPeriod |
Observation.specimen.resolve().collection.collectedPeriod.start |
|
Planned Collection Time Elapsed | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenCollection/@PlannedCollectionTimeElapsed | Specimen.extension |
Observation.specimen.resolve().extension(cqf-relativeDateTime).valueDuration.code |
Specimen.extension.extension.url=offset, then Specimen.extension.extension.valueDuration.value + Specimen.extension.extension.valueDuration.code |
Planned Collection Time Elapsed Description | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenCollection/@PlannedCollectionTimeElapsedDescription | Specimen.extension |
Observation.specimen.resolve().extension(cqf-relativeDateTime).valueReference.reference |
Specimen.extension.extension.url=relationship, then Specimen.extension.extension.valueString + Specimen.extension.extension.url=target, then Specimen.extension.extension.valueReference.reference |
Collection End Date and Time | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenCollection/@CollectionEndDateTime | Specimen.collection.collectedPeriod |
Observation.specimen.resolve().collection.collectedPeriod.end |
|
Received Date and Time | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenTransport/@ReceivedDateTime | Specimen.receivedTime |
Observation.specimen.resolve().receivedTime |
|
Specimen Condition | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenTransport/@SpecimenCondition | Specimen.condition |
Observation.specimen.resolve().condition.coding.code |
Will need to choose which coding to extract the code for |
Investigator - Specimen Comment Source | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenComment/@Source | Practitioner.identifier |
Observation.specimen.resolve().note.author.resolve().where($thisisPractitioner).identifier |
Note that practitioners can have multiple identifiers - use type or system to decide which identifier to expose |
Investigator - Specimen Comment Text | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenComment/@Text | Specimen.note.text |
Observation.specimen.resolve().where($author.resolve()isPractitioner).note.text |
|
Lab - Specimen Comment Source | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenComment/@Source | Observation.identifier |
Observation.specimen.resolve().note.author.resolve().where($thisisOrganization).identifier |
Note that organizations can have multiple identifiers - use type or system to decide which identifier to expose |
Lab - Specimen Comment Text | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenComment/@Text | Specimen.note |
Observation.specimen.resolve().where($author.resolve() isOrganization).note.text |
|
Specimen Material ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenMaterial/@ID | Specimen.type |
Observation.specimen.resolve().where($author.resolve() isOrganization).type.coding.code |
If multiple codes are present, filter based on system |
Specimen Material Name | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenMaterial/@Name | Specimen.type |
Observation.specimen.resolve().where($author.resolve() isOrganization).type.coding.display |
If multiple codes are present, filter based on system. |
Specimen Material Code List ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SpecimenMaterial/@CodeListID | Specimen.type |
Observation.specimen.resolve().where($author.resolve() isOrganization).type.coding.system |
If multiple codings are present, will need to decide which to use |
Subject Age at Collection | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SubjectAtCollection/@AgeAtCollection | If captured as an Observation, this would be in the ValueQuantity.code derived from the patient.birthDate(Observation.subject (ref:Patient.birthDate). If the full birthdate cannot be shared, due to country restrictions, use the birth year to derive age information. Due to lost accuracy in having only the year of birth, 'years' would be the default unit. |
||
Subject Age Units | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SubjectAtCollection/@AgeUnits | If captured as an Observation, this would be in the ValueQuantity.code derived from the patient.birthDate(Observation.subject (ref:Patient.birthDate). If the full birthdate cannot be shared, due to country restrictions, use the birth year to derive age information. Due to lost accuracy in having only the year of birth, 'years' would be the default unit. |
||
Fasting Status | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/SubjectAtCollection/@FastingStatus | Observation.specimenRefSpecimen.collection.fastingStatus |
Observation.specimenRefSpecimen.collection.fastingStatusCodeableConcept.code |
|
Battery ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/@ID | DiagnosticReport.identifier |
DiagnosticReport.identifier.value |
|
Battery Name | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/@Name | DiagnosticReport.code |
DiagnosticReport.code.text |
|
Battery Transaction Type | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/TransactionType | Determining whether transactions are insert or update is a task for the data consumer. (NOTE: This requires persistent storage to compare current data with data in the incoming file) | As per study transaction type (not clear why it happens at both levels - what would it mean to 'delete' at the study level and 'update at the site level?) | |
Test Status | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/@Status | ServiceRequest.doNotPerform |
Observation.basedOn.resolve().doNotPerform |
|
ServiceRequest.status |
Observation.basedon.resolve().status |
|||
Testing Date and Time | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/@TestingDateTime | Observation.effectiveDateTime |
Observation.effectiveDateTime |
|
Test Type | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/@TestType | The normal transmission of data, via FHIR, is for study tests. If non-study test results are required (e.g., AdverseEvent follow-up), these would be obtained via a special request from the data provider. Alternatively, if the system requires this field to be populated, derive whether the test was for the study or not, use the ServiceRequest resource. | Differentiation would be whether the Observation was basedOn a particular activity in the CarePlan (scheduled) or tied to a particular ActivityDefinition (Study test) | |
Performing Laboratory ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/PerformingLab/@ID | Organization.identifier |
Observation.performer.resolve().identifier |
Use "Organization/type" to pick the type of Organization that represents "Performing Lab" |
Performing Laboratory Name | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/PerformingLab/@Name | Organization.name |
Observation.performer.resolve().name |
|
Lab Test ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/LabTest/@ID | Observation.code |
Observation.code.coding.where(system = 'Lab Test') |
|
Lab Test Name | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/LabTest/@Name | Observation.code |
Observation.code.coding.display |
|
Additional Test Description | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/LabTest/@AdditionalDescription | Observation.comment |
Observation.comment |
|
Receiver Test ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/ReceiverTest/@ID | Observation.code |
Observation.code.coding.where (system = Recipient Test) |
Observation/code/coding/system/@value ("system" element used to designate the type of code that is being represented (in this case the "ReceiverTest") by the "code" element) |
Receiver Test Name | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/ReceiverTest/@Name | Observation.code |
Observation.code.coding.display where (coding system = 'Recipient Test') |
|
LOINC Code | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/LOINCTestCode/@Value | Observation.code |
Observation.code.coding.where (coding system = 'LOINC') |
|
LOINC Code List ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/LOINCTestCode/@CodeListID | Observation.code |
Observation.code.coding.where(system = 'http://loinc.org') |
|
Test Level Comments | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/TestLevelComment | Observation.extension |
Observation.extension(event-note).valueAnnotation.text |
New extension from Observation |
Reported Result Status | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/@ReportedResultStatus | Observation.status |
Observation.status |
|
Alert Flag | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/@AlertFlag | Observation.interpretation |
Observation.interpretation.coding.where(system='Alert Flag') |
|
Delta Flag | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/@DeltaFlag | Observation.interpretation |
Observation.interpretation.coding.where (system = 'Delta Flag') |
|
Exclusion Flag | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/@ExclusionFlag | Observation.interpretation |
Observation.interpretation.coding.where (system = 'Exclusion Flag') |
|
Blinding Flag | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/@BlindingFlag | Observation.meta.security |
Observation.meta.security.code |
|
Reported Date and Time | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/@ReportedDateTime | Observation.issued |
Observation.issued |
|
Test Transaction Type | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/TransactionType | Determining whether transactions are insert or update is a task for the data consumer. (NOTE: This requires persistent storage to compare current data with data in the incoming file) | As per study transaction type (not clear why it happens at both levels - what would it mean to 'delete' at the study level and 'update at the site level?) | |
Toxicity Grade | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/ToxicityGrade/@Value | Observation.interpretation |
Observation.interpretation.coding.where (system = 'Toxicity Grade') |
|
Toxicity Grade Code List ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/ToxicityGrade/@CodeListID | Observation.interpretation |
Observation.interpretation.coding.where (system = 'Toxicity Grade') |
|
Reported Result Type (C=coded; N=numeric; T=text; R=range; G = GT; L = LT) | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/@ResultType | Determine from the field in which the result resides. e.g., Observation/category/coding/code/@value For text and code results, which both use CodeableConcept, look at the field within CC to determine code vs. text. | ||
Text Result | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/TextResult/@Value | Observation.valueCodeableConcept |
Observation.valueCodeableConcept.text |
|
Text Result Code List ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/TextResult/@CodeListID | Observation.valueCodeableConcept |
Observation.valueCodeableConcept.coding.system |
|
Conventional Numeric Result | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/NumericResult/@Value | Observation.valueQuantity |
Observation.valueQuantity.value |
|
Reported Numeric Result | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/NumericResult/@Value | Observation.valueQuantity |
Observation.valueQuantity.value |
|
SI Numeric Result | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/NumericResult/@Value | Observation.valueQuantity |
Observation.valueQuantity.value |
|
Conventional Numeric Result Precision | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/NumericResult/@Precision | Observation.valueQuantity |
Observation.valueQuantity.value |
Determine the precision from the value. Precision is implicitly determined from the attribute Observation/valueQuantity/value/@value |
Reported Numeric Result Precision | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/NumericResult/@Precision | Observation.valueQuantity |
Observation.valueQuantity.value |
Determine the precision from the value. Precision is implicitly determined from the attribute Observation/valueQuantity/value/@value |
SI Numeric Result Precision | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/NumericResult/@Precision | Observation.valueQuantity |
Observation.valueQuantity.value |
Determine the precision from the value. Precision is implicitly determined from the attribute Observation/valueQuantity/value/@value |
Conventional Reference Range Low | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultReferenceRange/@ReferenceRangeLow | Observation.referenceRange |
Observation.referenceRange.low.value Observation.referenceRange.low.valueunit |
|
Reported Reference Range Low | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultReferenceRange/@ReferenceRangeLow | Observation.referenceRange |
Observation.referenceRange.low.value Observation.referenceRange.low.valueunit |
|
SI Reference Range Low | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultReferenceRange/@ReferenceRangeLow | Observation.referenceRange |
Observation.referenceRange.low.value Observation.referenceRange.low.valueunit |
|
Conventional Reference Range High | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultReferenceRange/@ReferenceRangeHigh | Observation.referenceRange |
Observation.referenceRange.high.value Observation.referenceRange.high.valueunit |
|
Reported Reference Range High | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultReferenceRange/@ReferenceRangeHigh | Observation.referenceRange |
Observation.referenceRange.high.value Observation.referenceRange.high.valueunit |
|
SI Reference Range High | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultReferenceRange/@ReferenceRangeHigh | Observation.referenceRange |
Observation.referenceRange.high.value Observation.referenceRange.high.valueunit |
|
Conventional Units | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultUnits/@Value | Observation.valueQuantity |
Observation.valueQuantity.unit |
|
Reported Units | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultUnits/@Value | Observation.valueQuantity |
Observation.valueQuantity.unit |
|
SI Units | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultUnits/@Value | Observation.valueQuantity |
Observation.valueQuantity.unit |
|
Conventional Units Code List ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultUnits/@CodeListID | Observation.valueQuantity |
Observation.valueQuantity.system |
|
Reported Units Code List ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultUnits/@CodeListID | Observation.valueQuantity |
Observation.valueQuantity.system |
|
SI Units Code List ID | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultUnits/@CodeListID | Observation.valueQuantity |
Observation.valueQuantity.system |
|
Record Extension Type | Populate with a default value, depending on the type of data being transmitted. E.g., "BASE" |
|||
Result Class | /GTP/Study/Site/Investigator/Subject/Visit/Accession/BaseSpecimen/BaseBattery/BaseTest/BaseResult/SingleResult/ResultClass/@Value | Derive this from the unit of measure system (on the result value), provide only one type of result, or provide a way to differentiate which results are reported, conventional, or international units. In some cases, the result unit of measure may provide some indication of whether the results are in conventional or SI. | ||
Model Version | /GTP/@ModelVersion | Populate with a default value. | The version of FHIR in use is conveyed using Resource.meta.profile | |
File Creation Date and Time | /GTP/@CreationDateTime | Pull from the message wrapper. (file creation date) | Bundle.timestamp | |
Transaction Type | /GTP/TransactionType | No mitigation. If required, fill with a default value. | As per study.transaction | |
Transmission Source ID | /GTP/TransmissionSource/@ID | Pull from the message wrapper. | MessageHeader.source.endpoint if using messaging, otherwise determined out of band based on sender authentication process | |
Transmission Source Name | /GTP/TransmissionSource/@Name | Pull from the message wrapper. | MessageHeader.source.name if using messaging, otherwise determined out of band based on sender authentication process |