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.id integer · id
    PKrequired
    transform: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.subject integer · Reference(Patient)
    FK→PERSONrequired
    transform: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.type integer · CodeableConcept
    FK→CONCEPTrequiredmap:specimen_type
    Map to OMOP concept in Specimen domain. Prefer SNOMED coding if multiple codings present. Fall back to 0 if no mapping found.
    2 sources ▾
  • specimen_type_concept_id constant integer · constant
    FK→CONCEPTrequired=32817
    Provenance of the specimen record, not the kind of specimen. Set to 32817 (EHR) for EHR-sourced data. omoponfhir hardcodes 0.
    2 sources ▾
  • specimen_date Specimen.collection.collected[x] date · dateTime | Period
    required
    transform:date_component(collected[x]); if Period use Period.start; fallback to Specimen.receivedTime
    OMOP requires this field (NOT NULL). If collected[x] is a Period, use Period.start. If absent, try Specimen.receivedTime as fallback.
    2 sources ▾
  • specimen_datetime Specimen.collection.collected[x] datetime · dateTime | Period
    transform:full_datetime(collected[x]); if date-only append T00:00:00
    Full datetime of collection. Same source as specimen_date but preserves time component.
  • quantity Specimen.collection.quantity.value float · decimal
    Amount of specimen collected. Direct numeric copy from collection.quantity.value.
  • unit_concept_id Specimen.collection.quantity integer · Quantity
    FK→CONCEPTmap:ucum_unit
    transform: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.unit varchar(50) · string
    Raw unit string. Prefer quantity.unit (human-readable); fall back to quantity.code (UCUM code).
  • anatomic_site_concept_id Specimen.collection.bodySite integer · CodeableConcept
    FK→CONCEPTmap:anatomic_site
    SNOMED body site code mapped to OMOP concept. Use first coding from bodySite.coding[]. Default 0 if unmapped.
  • anatomic_site_source_value Specimen.collection.bodySite.text varchar(50) · string
    Source text for anatomic site. Prefer bodySite.text, then coding[0].display, then coding[0].code.
  • disease_status_concept_id Specimen.condition integer · CodeableConcept
    FK→CONCEPT=0
    Semantic mismatch: FHIR condition describes specimen quality (hemolyzed, lipemic), not patient disease status. Most implementations set 0.
  • disease_status_source_value Specimen.condition.text varchar(50) · string
    Source text for disease/condition status. Prefer condition.text, then coding[0].display, then coding[0].code.
  • specimen_source_id Specimen.identifier[0].value varchar(50) · string
    Source system identifier. omoponfhir uses first identifier value. Can also use Specimen.accessionIdentifier.value.
    2 sources ▾
  • specimen_source_value Specimen.type.text varchar(50) · string
    Verbatim 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