Specimen
→
specimen
documented
primary
One FHIR Specimen maps to exactly one OMOP specimen row. The specimen table captures biological samples collected from a person, including specimen type, collection date, quantity, anatomic site, and disease status. Specimen type (kind of material) maps to specimen_concept_id via SNOMED, while specimen_type_concept_id is a provenance metadata field (EHR = 32817). Collection date is required in OMOP but optional in FHIR.
Conversion profile
omop-specimen-specimen
A FHIR instance converts to specimen iff it validates against this profile.
| Path | Card | Type | Binding / Fixed | Comment |
|---|---|---|---|---|
| Specimen.type | 1..*MS | omop-specimen-codesrequired | ||
| Specimen.subject | 1..* | Reference | Required for specimen.person_id. Group/Device/Substance subjects are rejected. |
ViewDefinition (Stage 1 flattener)
omop-specimen-specimen
16 columns · resource Specimen
| column name | FHIRPath | type |
|---|---|---|
| id | Specimen.id | id |
| type_snomed | Specimen.type.coding.where(system='http://snomed.info/sct').first().code | code |
| type_text | Specimen.type.text | string |
| body_site_snomed | Specimen.collection.bodySite.coding.where(system='http://snomed.info/sct').first().code | code |
| body_site_text | Specimen.collection.bodySite.text | string |
| unit_ucum | Specimen.collection.quantity.code.coding.where(system='http://unitsofmeasure.org').first().code | code |
| unit_text | Specimen.collection.quantity.code.text | string |
| subject_id | Specimen.subject | Reference(Patient) |
| specimen_date | Specimen.collection.collected[x] | dateTime | Period |
| specimen_datetime | Specimen.collection.collected[x] | dateTime | Period |
| quantity | Specimen.collection.quantity.value | decimal |
| anatomic_site | Specimen.collection.bodySite | CodeableConcept |
| anatomic_site_text | Specimen.collection.bodySite.text | string |
| disease_status | Specimen.condition | CodeableConcept |
| disease_status_text | Specimen.condition.text | string |
| specimen_source_id | Specimen.identifier[0].value | string |
Fields (15)
-
specimen_id←Specimen.idinteger · idPKrequiredtransform:hash_or_sequence(Specimen.id)Surrogate key. Hash/sequence/lookup of Specimen.id. Store FHIR ID or first identifier in specimen_source_id for traceability. -
person_id←Specimen.subjectinteger · Reference(Patient)FK→PERSONrequiredtransform:resolve_patient_reference(Specimen.subject)Resolve Patient reference to integer person_id. Subject must be a Patient -- reject Device, Group, Location, Substance subjects. -
specimen_concept_id←Specimen.typeinteger · CodeableConceptFK→CONCEPTrequiredmap:specimen_typeMap to OMOP concept in Specimen domain. Prefer SNOMED coding if multiple codings present. Fall back to 0 if no mapping found.2 sources ▾
-
SNOMED-preferred multi-coding lookup via ConceptService; iterates codings, picks SNOMED first
-
Logical model only — no FML transform for Specimen; field defined but not implemented
- fhir-omop-ig(fsh) refs/refs/fhir-omop-ig/input/fsh/Specimen.fsh:1-22
-
-
specimen_type_concept_id← constant integer · constantFK→CONCEPTrequired=32817Provenance of the specimen record, not the kind of specimen. Set to 32817 (EHR) for EHR-sourced data. omoponfhir hardcodes 0.2 sources ▾
-
Hardcoded to 0 — provenance not captured
- omoponfhir-v54(java) refs/refs/omoponfhir-v54-r4/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopSpecimen.java:387-387 — specimen_.setSpecimenTypeConcept(new Concept(0L))
-
32817 (EHR) — recommended for EHR-sourced FHIR data
- fhir-omop-ig(fsh) refs/refs/fhir-omop-ig/input/fsh/Specimen.fsh:1-22 — field defined in logical model as provenance concept
-
-
specimen_date←Specimen.collection.collected[x]date · dateTime | Periodrequiredtransform:date_component(collected[x]); if Period use Period.start; fallback to Specimen.receivedTimeOMOP requires this field (NOT NULL). If collected[x] is a Period, use Period.start. If absent, try Specimen.receivedTime as fallback.2 sources ▾
-
collectedDateTime only — throws FHIRException if absent or if type is Period
- omoponfhir-v54(java) refs/refs/omoponfhir-v54-r4/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopSpecimen.java:330-342
- omoponfhir-v54(java) refs/refs/omoponfhir-v54-r4/omoponfhir-r4-server/src/main/java/edu/gatech/chai/omoponfhir/r4/provider/SpecimenResourceProvider.java:269-285
-
Maps specimen_date from OMOP (O→F direction); no FHIR→OMOP date extraction logic
- tofhir-mappings(json) refs/refs/tofhir-mappings/mappings/omop/specimen-mapping.json:44-61
-
-
specimen_datetime←Specimen.collection.collected[x]datetime · dateTime | Periodtransform:full_datetime(collected[x]); if date-only append T00:00:00Full datetime of collection. Same source as specimen_date but preserves time component. -
quantity←Specimen.collection.quantity.valuefloat · decimalAmount of specimen collected. Direct numeric copy from collection.quantity.value. -
unit_concept_id←Specimen.collection.quantityinteger · QuantityFK→CONCEPTmap:ucum_unittransform:lookup_ucum(quantity.code where quantity.system = 'http://unitsofmeasure.org')Look up UCUM code in CONCEPT table (vocabulary_id = 'UCUM'). Default 0 if lookup fails. -
unit_source_value←Specimen.collection.quantity.unitvarchar(50) · stringRaw unit string. Prefer quantity.unit (human-readable); fall back to quantity.code (UCUM code). -
anatomic_site_concept_id←Specimen.collection.bodySiteinteger · CodeableConceptFK→CONCEPTmap:anatomic_siteSNOMED body site code mapped to OMOP concept. Use first coding from bodySite.coding[]. Default 0 if unmapped. -
anatomic_site_source_value←Specimen.collection.bodySite.textvarchar(50) · stringSource text for anatomic site. Prefer bodySite.text, then coding[0].display, then coding[0].code. -
disease_status_concept_id←Specimen.conditioninteger · CodeableConceptFK→CONCEPT=0Semantic mismatch: FHIR condition describes specimen quality (hemolyzed, lipemic), not patient disease status. Most implementations set 0. -
disease_status_source_value←Specimen.condition.textvarchar(50) · stringSource text for disease/condition status. Prefer condition.text, then coding[0].display, then coding[0].code. -
specimen_source_id←Specimen.identifier[0].valuevarchar(50) · stringSource system identifier. omoponfhir uses first identifier value. Can also use Specimen.accessionIdentifier.value.2 sources ▾
-
First Specimen.identifier value (not accessionIdentifier)
-
Hashed specimen_id string (O→F direction, not FHIR identifier)
- tofhir-mappings(json) refs/refs/tofhir-mappings/mappings/omop/specimen-mapping.json:33-33
-
-
specimen_source_value←Specimen.type.textvarchar(50) · stringVerbatim source code/text for the specimen type. Populated when specimen_concept_id is 0 (unmapped). Use type.text if available, otherwise system|code or display of first coding, truncated to 50 chars.
Vocabularies
specimen_type
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| 119297000 | Blood specimen | 4045667 | Blood specimen |
| 119361006 | Plasma specimen | 4046275 | Plasma specimen |
| 119364003 | Serum specimen | 4045666 | Serum specimen |
| 122555007 | Venous blood specimen | 4046280 | Venous blood specimen |
| 258580003 | Whole blood sample | 4264829 | Whole blood |
| 119339001 | Stool specimen | 4002890 | Stool specimen |
| 122575003 | Urine specimen | 4045668 | Urine specimen |
| 258529004 | Throat swab | 4218410 | Throat swab |
| 309051001 | Body fluid sample | 4046274 | Body fluid sample |
| 119376003 | Tissue specimen | 4002893 | Tissue specimen |
| 258566005 | Deoxyribonucleic acid sample | 4046281 | Deoxyribonucleic acid sample |
| 119342007 | Saliva specimen | 4045669 | Saliva specimen |
| 258587000 | Buffy coat | 4215183 | Buffy coat |
| 119359002 | Bone marrow specimen | 4000626 | Bone marrow specimen |
| (unmapped) | -- | 0 | No matching concept |
specimen_type_concept
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| EHR | EHR-sourced data | 32817 | EHR |
| EHR encounter | EHR encounter record | 32882 | EHR encounter record |
| Claim | Claims data | 32810 | Claim |
| Lab | Lab result | 32856 | Lab |
| Patient self-report | Survey/PRO | 32865 | Patient self-report |
ucum_unit
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| mL | milliliter | 8587 | milliliter |
| uL | microliter | 8585 | microliter |
| g | gram | 8504 | gram |
| mg | milligram | 8576 | milligram |
| {cells} | cells | 45891014 | cells |
| (unmapped) | -- | 0 | No matching concept |
anatomic_site
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| 14016003 | Structure of median cubital vein | 4138766 | Structure of median cubital vein |
| 66480008 | Structure of left forearm | 4263504 | Structure of left forearm |
| 49852007 | Structure of median basilic vein | 4139757 | Structure of median basilic vein |
| 368208006 | Left upper arm structure | 4136361 | Left upper arm structure |
| (unmapped) | -- | 0 | No matching concept |
disease_status
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| AUT | Autolyzed | - | No standard mapping |
| CLOT | Clotted | - | No standard mapping |
| HEM | Hemolyzed | - | No standard mapping |
| (any) | -- | 0 | No matching concept |
Edge Cases
Missing collection.collected[x]
OMOP specimen_date is NOT NULL. Options: (a) reject the resource and log warning, (b) fall back to Specimen.receivedTime, (c) use current date (not recommended). omoponfhir throws FHIRException.
collected[x] is a Period
OMOP only supports a single date/datetime, not a range. Use Period.start as the collection date. Period.end is lost. omoponfhir throws if collected is not a DateTimeType.
subject references non-Patient (Device, Group, Location, Substance)
Reject the resource. OMOP person_id requires a patient. Log warning with the unsupported resource type.
subject reference unresolvable (Patient not yet in OMOP)
Either: (a) process Patients first (dependency ordering), (b) defer Specimen to a retry queue, (c) reject. omoponfhir throws FHIRException if patient lookup returns null.
Missing Specimen.type
Set specimen_concept_id to 0 and leave specimen_source_value empty. omoponfhir treats type as required via the coding iteration logic -- null type will cause NPE.
Multiple codings in Specimen.type
Prefer SNOMED CT coding (http://snomed.info/sct). If no SNOMED, try any coding that maps to a known OMOP vocabulary. If none map, use concept_id 0.
Specimen.type uses HL7 v2 Table 0487
These codes (BLD, UR, TISS, etc.) are in the 'v2 Specimen Type' vocabulary in OMOP. Look up via vocabulary_id = 'v2 Specimen Type'. If not found, set 0 and preserve in source_value.
Specimen.parent (aliquot/derived specimen)
No OMOP field for parent-child specimen relationships. Lost in mapping. Could potentially be captured in fact_relationship with a custom relationship concept.
Specimen.status = entered-in-error
OMOP has no status field on specimen. Options: (a) skip the resource entirely (recommended), (b) insert anyway (bad data quality).
Quantity without unit
Set unit_concept_id = 0, unit_source_value = null. The quantity value is still stored.
disease_status_concept_id semantic mismatch
FHIR Specimen.condition describes specimen quality (hemolyzed, clotted), not patient disease status. Most implementations set 0. If a clinical use case requires mapping, use vocabulary lookup for SNOMED or v2 codes.
Duplicate specimens
omoponfhir deduplicates on (patient, specimen_concept, collection_date) tuple. If a matching specimen exists, it updates rather than creating a duplicate. Other implementations do not deduplicate.
specimen_source_id truncation
OMOP field is varchar(50). FHIR identifiers (especially UUIDs in urn:uuid: format) can exceed 50 characters. Truncate or hash if necessary.
Reference Implementations
- fhir-omop-ig(fsh) refs/refs/fhir-omop-ig/input/fsh/Specimen.fsh:1-22 — Logical model only; no FML transform map exists for Specimen.
- omoponfhir-v54(java) refs/refs/omoponfhir-v54-r4/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopSpecimen.java:1-531 — Bidirectional mapper. Most complete Specimen implementation. FHIR->OMOP: lines 234-390. OMOP->FHIR: lines 89-192. Subject validation: lines 392-408. specimen_type_concept_id hardcoded to 0: line 387.
- tofhir-mappings(json) refs/refs/tofhir-mappings/mappings/omop/specimen-mapping.json — OMOP-to-FHIR direction. Maps specimen_id, person_id, concept_code/vocabulary_id to Specimen.type, specimen_date to collectedDateTime, quantity + unit, and body site.
- NACHC-fhir-to-omop(java) refs/refs/NACHC-fhir-to-omop/src/main/java/org/nachc/tools/omop/yaorma/dvo/SpecimenDvo.java:32-48 — DVO only, no actual Specimen FHIR mapper.