def value_quantity(g: Graph, subject: Node, obs_fact: ObservationFact) -> List[ObservationFact]: """ Process a FHIR:valueQuantity, recording salient information in obs_fact :param g: Graph containing the quantity :param subject: Subject of the fhir quantity node :param obs_fact: Fact to add the information to :return: Empty list - no additional facts are generated """ units = fhirgraphutils.value(g, subject, FHIR.Quantity.unit) if not units: system = fhirgraphutils.value(g, subject, FHIR.Quantity.system) code = fhirgraphutils.value(g, subject, FHIR.Quantity.code) if code: ns = fhir_namespace_for(system) units = ((ns.upper() + ':') if ns else '') + code comparator = fhirgraphutils.value(g, subject, FHIR.Quantity.comparator) value_ = fhirgraphutils.value(g, subject, FHIR.Quantity.value) if value_ is not None: obs_fact._valtype_cd = valuetype_number obs_fact._nval_num = value_ obs_fact._tval_char = 'E' if comparator is None else comparator_map.get( str(comparator), '?') obs_fact._units_cd = str(units) if units else None else: obs_fact._valtype_cd = valuetype_novalue return []
def test_value_quantity_units(self): self.g.parse(os.path.join(self.test_dir, 'observation-example-f204-creatinine-unit2.ttl'), format="turtle") s = URIRef("http://hl7.org/fhir/Observation/f204") # Units present obsf = ObservationFact(self.ofk, FHIR.SimpleQuantity) qval = self.g.value(s, FHIR.Observation.valueQuantity1) value_quantity(self.g, qval, obsf) self.assertEqual('umol/L', obsf.units_cd) # System/code obsf = ObservationFact(self.ofk, FHIR.SimpleQuantity) qval = self.g.value(s, FHIR.Observation.valueQuantity2) value_quantity(self.g, qval, obsf) self.assertEqual('SCT:258814008', obsf.units_cd) obsf = ObservationFact(self.ofk, FHIR.SimpleQuantity) qval = self.g.value(s, FHIR.Observation.valueQuantity3) value_quantity(self.g, qval, obsf) self.assertEqual('GPF', obsf.units_cd) # No units at all obsf = ObservationFact(self.ofk, FHIR.SimpleQuantity) qval = self.g.value(s, FHIR.Observation.valueQuantity4) value_quantity(self.g, qval, obsf) self.assertIsNone(obsf.units_cd)
def setUp(self): from i2fhirb2.i2b2model.data.i2b2observationfact import ObservationFact, ObservationFactKey ObservationFact._clear() ObservationFact.update_date = datetime(2017, 2, 19, 12, 33) # Patient / provider / encounter / start date self.ofk = ObservationFactKey(12345, 23456, 'provider', datetime(2017, 5, 23, 11, 17)) self.g = Graph()
def value_integer(g: Graph, subject: Node, obs_fact: ObservationFact) -> List[ObservationFact]: """ Process a FHIR:valueInteger, recording salient information in obs_fact :param g: Graph containing the quantity :param subject: Subject of the fhir quantity node :param obs_fact: Fact to add the information to :return: Empty list - no additional facts are generated """ obs_fact._valtype_cd = valuetype_number obs_fact._nval_num = g.value(subject, FHIR.value, any=False).value obs_fact._tval_char = 'E' return []
def test_value_string(self): self.g.parse(os.path.join(self.test_dir, 'observation-example-eye-color.ttl'), format="turtle") obsf = ObservationFact(self.ofk, FHIR.string) s = URIRef("http://hl7.org/fhir/Observation/eye-color") sval = self.g.value(s, FHIR.Observation.valueString) vs = value_string(self.g, sval, obsf) self.assertEqual(0, len(vs)) self.assertEqual(valuetype_text.code, obsf.valtype_cd) self.assertEqual("blue", obsf.tval_char) obsf = ObservationFact(self.ofk, FHIR.string) vs2 = proc_value_node(self.g, obsf, FHIR.Observation.valueString, sval) self.assertEqual(0, len(vs2)) self.assertEqual("blue", obsf.tval_char)
def test_value_integer(self): self.g.parse(os.path.join(self.test_dir, 'diagnosticreport-micro1.ttl'), format="turtle") s = URIRef("https://example.com/base/Observation/obx2-10") obsf = ObservationFact(self.ofk, FHIR.integer) qval = self.g.value(s, FHIR.Observation.valueInteger) vs = value_integer(self.g, qval, obsf) self.assertEqual(0, len(vs)) self.assertEqual('E', obsf.tval_char) self.assertEqual(-17243, obsf.nval_num) self.assertIsNone(obsf.units_cd) # Dispatch test obsf = ObservationFact(self.ofk, FHIR.string) vs2 = proc_value_node(self.g, obsf, FHIR.Observation.valueInteger, qval) self.assertEqual(-17243, obsf.nval_num)
def value_string(g: Graph, node: Node, obs_fact: ObservationFact) -> List[ObservationFact]: """ Convert a FHIR.string type value into the i2b2 equivalent :param g: Graph containing the data :param node: Node containing the string value :param obs_fact: target fact to have string added to it :return: Empty list - no additional facts are generated """ obs_fact._valtype_cd = valuetype_text obs_fact._tval_char = g.value(node, FHIR.value, default=Literal(""), any=False).value return []
def value_codeable_concept(g: Graph, subject: Node, obs_fact: ObservationFact) -> List[ObservationFact]: """ Process a FHIR:valueCodeableConcept node. The first FHIR:CodeableConcept.coding entry is recorded as the value for the passed `obs_fact`. Additional obs_fact entries are generated to carry the text, if it exists, and any additional codings. :param g: Graph containing the data :param subject: CodeableConcept node :param obs_fact: target fact(s) :return: Additional obs_facts beyond obs_fact itself """ from i2fhirb2.fhir.fhirobservationfact import FHIRObservationFact rval = [] if obs_fact.modifier_cd != '@': print( f"{obs_fact.concept_cd}, {obs_fact.modifier_cd}: Modifier on modifier!" ) codings = sorted(list(g.objects(subject, FHIR.CodeableConcept.coding))) additional_entries = False if codings: for coding in codings: obs_fact_copy = copy.copy(obs_fact) if obs_fact.modifier_cd == '@': concept_uri = concept_uri_for(g, coding) concept_ns_name = FHIRObservationFact.ns_name_for( concept_uri) if concept_uri else None if concept_ns_name: obs_fact._modifier_cd = concept_ns_name display = fhirgraphutils.value(g, coding, FHIR.Coding.display) if not display: display = fhirgraphutils.value(g, subject, FHIR.CodeableConcept.text) if display: obs_fact._valtype_cd = valuetype_text obs_fact._tval_char = display if additional_entries: rval.append(obs_fact) else: additional_entries = True obs_fact = obs_fact_copy else: text = fhirgraphutils.value(g, subject, FHIR.CodeableConcept.text) if text: obs_fact._valtype_cd = valuetype_text obs_fact._tval_char = text return rval
def test_value_codeable_concept_2(self): self.g.parse(os.path.join(self.test_dir, 'observation-example-2minute-apgar-score.ttl'), format="turtle") s = URIRef("http://hl7.org/fhir/Observation/2minute-apgar-score") found = False for v in self.g.objects(s, FHIR.Observation.component): if self.g.value(v, FHIR.index).value == 0: found = True cval = self.g.value(v, FHIR.Observation.component.valueCodeableConcept, any=False) obsf = ObservationFact(self.ofk, FHIR.CodeableConcept) output_buffer = StringIO() with redirect_stdout(output_buffer): addl_facts = value_codeable_concept(self.g, cval, obsf) self.assertTrue('Unrecognized namespace: http:/acme.ped/apgarcolor/' in output_buffer.getvalue()) self.assertEqual(valuetype_text.code, obsf.valtype_cd) self.assertEqual('1. Good color in body with bluish hands or feet', obsf.tval_char) self.assertEqual('@', obsf.modifier_cd) self.assertEqual(1, len(addl_facts)) obsf2 = addl_facts[0] self.assertEqual(valuetype_text.code, obsf2.valtype_cd) self.assertEqual("Good color in body with bluish hands or feet", obsf2.tval_char) self.assertEqual("LOINC:LA6723-6", obsf2.modifier_cd) self.assertTrue(found)
def test_value_codeable_concept_1(self): self.g.parse(os.path.join(self.test_dir, 'diagnosticreport-micro1.ttl'), format="turtle") s = URIRef("https://example.com/base/Observation/obx1-4") obsf = ObservationFact(self.ofk, FHIR.CodeableConcept) cval = self.g.value(s, FHIR.Observation.valueCodeableConcept) vs = value_codeable_concept(self.g, cval, obsf) self.assertEqual(0, len(vs)) self.assertEqual(valuetype_text.code, obsf.valtype_cd) self.assertEqual("Staphylococcus aureus", obsf.tval_char) self.assertEqual("@", obsf.modifier_cd)
def clear_i2b2_sourcesystems(tables: I2B2Tables, sourcesystemcd: str) -> None: print("Deleted {} patient_dimension records" .format(PatientDimension.delete_sourcesystem_cd(tables, sourcesystemcd))) print("Deleted {} patient_mapping records" .format(PatientMapping.delete_sourcesystem_cd(tables, sourcesystemcd))) print("Deleted {} observation_fact records" .format(ObservationFact.delete_sourcesystem_cd(tables, sourcesystemcd))) print("Deleted {} visit_dimension records" .format(VisitDimension.delete_sourcesystem_cd(tables, sourcesystemcd))) print("Deleted {} encounter_mapping records" .format(EncounterMapping.delete_sourcesystem_cd(tables, sourcesystemcd)))
def test_basics(self): from i2fhirb2.i2b2model.data.i2b2observationfact import ObservationFact, ObservationFactKey ObservationFact._clear() ObservationFact.update_date = datetime(2017, 2, 19, 12, 33) with self.sourcesystem_cd(): ObservationFact.sourcesystem_cd = self._sourcesystem_cd ofk = ObservationFactKey(12345, 23456, 'provider', datetime(2017, 5, 23, 11, 17)) x = ObservationFact(ofk, 'fhir:concept', sourcesystem_cd=self._sourcesystem_cd) self.assertEqual( 'encounter_num\tpatient_num\tconcept_cd\tprovider_id\tstart_date\tmodifier_cd\tinstance_num\t' 'valtype_cd\ttval_char\tnval_num\tvalueflag_cd\tquantity_num\tunits_cd\tend_date\t' 'location_cd\tobservation_blob\tconfidence_num\tupdate_date\tdownload_date\timport_date\t' 'sourcesystem_cd\tupload_id', x._header()) self.assertEqual( OrderedDict([('encounter_num', 23456), ('patient_num', 12345), ('concept_cd', 'fhir:concept'), ('provider_id', 'provider'), ('start_date', datetime(2017, 5, 23, 11, 17)), ('modifier_cd', '@'), ('instance_num', 0), ('valtype_cd', '@'), ('tval_char', None), ('nval_num', None), ('valueflag_cd', None), ('quantity_num', None), ('units_cd', None), ('end_date', None), ('location_cd', None), ('observation_blob', None), ('confidence_num', None), ('update_date', datetime(2017, 2, 19, 12, 33)), ('download_date', datetime(2017, 2, 19, 12, 33)), ('import_date', datetime(2017, 2, 19, 12, 33)), ('sourcesystem_cd', self._sourcesystem_cd), ('upload_id', None)]), x._freeze())
def test_value_quantity(self): self.g.parse(os.path.join(self.test_dir, 'observation-example-f204-creatinine.ttl'), format="turtle") obsf = ObservationFact(self.ofk, FHIR.SimpleQuantity) s = URIRef("http://hl7.org/fhir/Observation/f204") qval = self.g.value(s, FHIR.Observation.valueQuantity) vs = value_quantity(self.g, qval, obsf) self.assertEqual(0, len(vs)) self.assertEqual(valuetype_number.code, obsf.valtype_cd) self.assertEqual('E', obsf.tval_char) self.assertEqual(122, obsf.nval_num) self.assertEqual('umol/L', obsf.units_cd) # Test '>' self.g.parse(os.path.join(self.test_dir, 'diagnosticreport-micro1.ttl'), format="turtle") obsf = ObservationFact(self.ofk, FHIR.SimpleQuantity) s = URIRef("https://example.com/base/Observation/obx2-2") qval = self.g.value(s, FHIR.Observation.valueQuantity) vs = value_quantity(self.g, qval, obsf) self.assertEqual(0, len(vs)) self.assertEqual('G', obsf.tval_char) self.assertEqual(2, obsf.nval_num) self.assertIsNone(obsf.units_cd) # Test '>=' s = URIRef("https://example.com/base/Observation/obx2-4") obsf = ObservationFact(self.ofk, FHIR.SimpleQuantity) qval = self.g.value(s, FHIR.Observation.valueQuantity) vs = value_quantity(self.g, qval, obsf) self.assertEqual(0, len(vs)) self.assertEqual('GE', obsf.tval_char) self.assertEqual(4, obsf.nval_num) self.assertIsNone(obsf.units_cd) # Test '<' s = URIRef("https://example.com/base/Observation/obx2-6") obsf = ObservationFact(self.ofk, FHIR.SimpleQuantity) qval = self.g.value(s, FHIR.Observation.valueQuantity) vs = value_quantity(self.g, qval, obsf) self.assertEqual(0, len(vs)) self.assertEqual('L', obsf.tval_char) self.assertEqual(0.5, obsf.nval_num) self.assertIsNone(obsf.units_cd) # Test '<; s = URIRef("https://example.com/base/Observation/obx2-8") obsf = ObservationFact(self.ofk, FHIR.SimpleQuantity) qval = self.g.value(s, FHIR.Observation.valueQuantity) vs = value_quantity(self.g, qval, obsf) self.assertEqual(0, len(vs)) self.assertEqual('LE', obsf.tval_char) self.assertEqual(1, obsf.nval_num) self.assertIsNone(obsf.units_cd) # Dispatch test obsf = ObservationFact(self.ofk, FHIR.string) vs2 = proc_value_node(self.g, obsf, FHIR.Observation.valueQuantity, qval) self.assertEqual(0, len(vs2)) self.assertEqual(1, obsf.nval_num)
def test_sourcesystem_cd(self): ObservationFact._clear() ofk = ObservationFactKey(1, 1, "Provider") obsf = ObservationFact(ofk, "FHIR:Test") fobsf = FHIRObservationFact(Graph(), ofk, "FHIR:test", None, None) if obsf.sourcesystem_cd != "Unspecified": print("HERE") self.assertEqual("Unspecified", obsf.sourcesystem_cd) self.assertEqual("Unspecified", fobsf.sourcesystem_cd) cd1 = "SourceSystemCdTestCase_cd1" cd2 = "SourceSystemCdTestCase_cd2" ObservationFact.sourcesystem_cd = cd1 FHIRObservationFact.sourcesystem_cd = cd2 self.assertEqual(cd2, obsf.sourcesystem_cd) self.assertEqual(cd2, fobsf.sourcesystem_cd) ObservationFact._clear() self.assertEqual("Unspecified", obsf.sourcesystem_cd) self.assertEqual("Unspecified", fobsf.sourcesystem_cd) ObservationFact.sourcesystem_cd = cd1 FHIRObservationFact.sourcesystem_cd = cd2 self.assertEqual(cd2, obsf.sourcesystem_cd) self.assertEqual(cd2, fobsf.sourcesystem_cd) FHIRObservationFact._clear() self.assertEqual("Unspecified", obsf.sourcesystem_cd) self.assertEqual("Unspecified", fobsf.sourcesystem_cd) ObservationFact.sourcesystem_cd = cd1 self.assertEqual(cd1, obsf.sourcesystem_cd) self.assertEqual(cd1, fobsf.sourcesystem_cd) FHIRObservationFact._clear() self.assertEqual("Unspecified", obsf.sourcesystem_cd) self.assertEqual("Unspecified", fobsf.sourcesystem_cd)
def clear_i2b2_tables(tables: I2B2Tables, uploadid: int) -> None: """ Remove all entries in the i2b2 tables for uploadid. :param tables: :param uploadid: :return: """ # This is a static function to support the removefacts operation print("Deleted {} patient_dimension records" .format(PatientDimension.delete_upload_id(tables, uploadid))) print("Deleted {} patient_mapping records" .format(PatientMapping.delete_upload_id(tables, uploadid))) print("Deleted {} observation_fact records" .format(ObservationFact.delete_upload_id(tables, uploadid))) print("Deleted {} visit_dimension records" .format(VisitDimension.delete_upload_id(tables, uploadid))) print("Deleted {} encounter_mapping records" .format(EncounterMapping.delete_upload_id(tables, uploadid)))
def load_i2b2_tables(self, check_dups=False) -> None: # session = sessionmaker(bind=tables.crc_engine)() I2B2Core._check_dups = check_dups if self._opts.remove: # TODO: This should really be within a transaction boundary self.clear_i2b2_tables(self._opts.tables, self._opts.uploadid) change_column_length(self._opts.tables.observation_fact, self._opts.tables.observation_fact.c.concept_cd, 200, self._opts.tables.crc_connection) change_column_length(self._opts.tables.observation_fact, self._opts.tables.observation_fact.c.modifier_cd, 200, self._opts.tables.crc_connection) print("{} / {} patient_dimension records added / modified" .format(*PatientDimension.add_or_update_records(self._opts.tables, self.patient_dimensions))) print("{} / {} patient_mapping records added / modified" .format(*PatientMapping.add_or_update_records(self._opts.tables, self.patient_mappings))) print("{} / {} visit_dimension records added / modified" .format(*VisitDimension.add_or_update_records(self._opts.tables, self.visit_dimensions))) print("{} / {} encounter_mapping records added / modified" .format(*EncounterMapping.add_or_update_records(self._opts.tables, self.encounter_mappings))) print("{} / {} observation_fact records added / modified" .format(*ObservationFact.add_or_update_records(self._opts.tables, self.observation_facts)))
def test_insert(self): from i2fhirb2.i2b2model.data.i2b2observationfact import ObservationFactKey print("{} records deleted".format(ObservationFact.delete_upload_id(self.opts.tables, self.opts.uploadid))) ofk = ObservationFactKey(12345, 23456, 'provider', datetime(2017, 5, 23, 11, 17)) ObservationFact.update_date = datetime(2017, 2, 19, 12, 33) with self.sourcesystem_cd(): ObservationFact.sourcesystem_cd = self._sourcesystem_cd ObservationFact.upload_id = self.opts.uploadid obsf = ObservationFact(ofk, 'fhir:concept', sourcesystem_cd="FHIR R4") n_ins, n_upd = ObservationFact.add_or_update_records(self.opts.tables, [obsf]) self.assertEqual((0, 1), (n_upd, n_ins)) obsf._instance_num = 2 obsf2 = ObservationFact(ofk, 'fhir:concept', sourcesystem_cd="FHIR R4z") obsf2._instance_num = 2 obsf2._modifier_cd = "fhir:modifier" n_ins, n_upd = ObservationFact.add_or_update_records(self.opts.tables, [obsf, obsf2]) self.assertEqual((0, 2), (n_upd, n_ins)) self.assertEqual(3, ObservationFact.delete_upload_id(self.opts.tables, self.opts.uploadid))
def tearDown(self): ObservationFact._clear()
def _clear(cls, complete=True): cls._unknown_namespaces = [] ObservationFact._clear(complete)
def as_observation_facts(self, encounter_num: int, provider_id: str, start_date: datetime) -> List[ObservationFact]: rval = [] pde = self.patient_dimension_entry ofk = ObservationFactKey(self.patient_dimension_entry.patient_num, encounter_num, provider_id, start_date) # Age entry rval.append( ObservationFact(ofk, I2B2DemographicsCodes.age(pde.age_in_years_num))) # Sex rval.append( ObservationFact( ofk, I2B2DemographicsCodes.sex_female if pde.sex_cd == 'F' else I2B2DemographicsCodes.sex_male if pde.sex_cd == 'M' else I2B2DemographicsCodes.sex_undifferentiated if pde.sex_cd == 'U' else I2B2DemographicsCodes.sex_unknown)) # Birthdate if pde.birth_date: bd_of = ObservationFact(ofk, I2B2DemographicsCodes.birthdate) bd_of._date_val(pde.birth_date) rval.append(bd_of) # Deathdate if pde.death_date: dd_of = ObservationFact(ofk, I2B2DemographicsCodes.birthdate) dd_of._date_val(pde.death_date) rval.append(dd_of) # Language rval.append( ObservationFact(ofk, I2B2DemographicsCodes.language(self._language))) # Marital status rval.append( ObservationFact( ofk, I2B2DemographicsCodes.marital_status(self._marital_status))) # race rval.append( ObservationFact(ofk, I2B2DemographicsCodes.race(self._race))) # religion # Religion codes currently like the FHIR rval.append( ObservationFact(ofk, I2B2DemographicsCodes.religion(self._religion))) # vital -- no idea what vital_deferred means rval.append( ObservationFact( ofk, I2B2DemographicsCodes.vital_living if pde._vital_status_code.dd_deceased == VitalStatusCd.dd_living else I2B2DemographicsCodes.vital_unknown if pde._vital_status_code.dd_unknown else I2B2DemographicsCodes.vital_dead)) # zip rval.append(ObservationFact(ofk, I2B2DemographicsCodes.zip(pde.zip_cd))) return rval