示例#1
0
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 []
示例#2
0
    def __init__(self, g: Graph, tables: Optional[I2B2Tables],
                 patient: URIRef) -> None:
        """
        Generate i2b2 patient dimension and patient_mapping records from PATIENT resources in graph g

        :param g: Graph containing 0 or more FHIR Patient resources
        :param tables: i2b2 tables connection if we are using a database (vs. tsv output)
        :param patient: Graph subject
        """
        assert value(g, patient, FHIR.animal) is None  # We don't do animals
        parsed_resource = parse_fhir_resource_uri(patient)
        self.patient_mappings = FHIRPatientMapping(
            tables, parsed_resource.resource, str(parsed_resource.namespace))
        active = value(g, patient, FHIR.Patient.active)
        if active is not None and not active:
            self.patient_mappings._patient_ide_status = PatientIDEStatus.inactive
        self.patient_dimension_entry = PatientDimension(
            self.patient_mappings.patient_num,
            VitalStatusCd(VitalStatusCd.bd_unknown, VitalStatusCd.dd_unknown))

        # Additional attributes that don't go into patient dimension but are recorded as observation facts
        self._language = None
        self._marital_status = None
        self._race = None
        self._religion = None
        self.add_patient_information(g, patient)
示例#3
0
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
示例#4
0
def concept_uri_for(g: Graph, coding: Node) -> Optional[URIRef]:
    """ Return the URI for the concept in coding, if any.  If a type arc is present, it will be used.  Otherwise
    we will attempt to synthesize one from system and code.

    :param g: Graph containing the coding node
    :param coding: node that contains the FHIR.Coding entry
    :return: URI or None if nothing is available
    """
    uri = g.value(coding, RDF.type)
    if uri is None:
        # TODO: Combine this with the rules in fhirtordf - they should do exactly the same thing
        system = fhirgraphutils.value(g, coding, FHIR.Coding.system)
        code = fhirgraphutils.value(g, coding, FHIR.Coding.code)
        if system and code:
            uri = URIRef(system +
                         ('' if system.endswith(('#', '/')) else '/') + code)
    return uri
 def test_value(self):
     from fhirtordf.rdfsupport.fhirgraphutils import value
     g = Graph()
     g.load(os.path.join(self.base_dir, "account-example.ttl"),
            format="turtle")
     s = FHIR['Account/example']
     self.assertEqual("example", value(g, s, FHIR.Resource.id))
     self.assertEqual(Literal("example"), value(g, s, FHIR.Resource.id,
                                                True))
     self.assertEqual(FHIR.treeRoot, value(g, s, FHIR.nodeRole))
     period = g.value(s, FHIR.Account.period)
     self.assertEqual(date(2016, 1, 1), value(g, period, FHIR.Period.start))
     period_end = g.value(period, FHIR.Period.end)
     self.assertEqual(date(2016, 6, 30), value(g, period_end, FHIR.value))
     self.assertIsNone(value(g, s, FHIR.Account.type))
     self.assertIsNone(value(g, s, FHIR.foo))
示例#6
0
 def process_resource_instance(self, subj: URIRef,  mapped_type: FHIR_Resource_type) \
         -> Tuple[Optional[FHIRPatientMapping], Optional[FHIRVisitDimension], Optional[datetime]]:
     patient_id_uri, encounter_id_uri, provider_id = mapped_type.fact_key_for(self._g, subj)
     if patient_id_uri is not None:
         parsed_resource = parse_fhir_resource_uri(patient_id_uri)
         pm = FHIRPatientMapping(self.tables, parsed_resource.resource, str(parsed_resource.namespace))
         self.patient_mappings += pm.patient_mapping_entries
         start_date = value(self._g, subj, FHIR.Observation.effectiveDateTime)
         if not start_date:
             start_date = datetime.now()
         vd = FHIRVisitDimension(subj, pm.patient_num, parsed_resource.resource, str(parsed_resource.namespace),
                                 start_date)
         self.visit_dimensions.append(vd.visit_dimension_entry)
         self.encounter_mappings += vd.encounter_mappings.encounter_mapping_entries
         return pm, vd, start_date
     else:
         # Just a reference to a resource instance -- drop it
         return None, None, None
示例#7
0
 def resource_id(self) -> Optional[str]:
     return value(self._g, self._resource_uri, FHIR.Resource.id)
示例#8
0
    def add_patient_information(self, g: Graph, patient: URIRef) -> None:
        """
        Add additional information to the patient
        :param g: Graph carrying additional facts about the patient
        :param patient: URI of the actual patient
        """
        if not g.value(patient,
                       FHIR.Patient.animal):  # i2b2 doesn't do animals
            # gender
            gender = value(g, patient, FHIR.Patient.gender)
            if gender == "male":
                self.patient_dimension_entry._sex_cd = 'M'
            elif gender == "female":
                self.patient_dimension_entry._sex_cd = 'F'
            elif gender == "other":
                self.patient_dimension_entry._sex_cd = 'U'

            # deceased.deceasedBoolean --> vital_status_code.deathInd
            isdeceased = value(g, patient, FHIR.Patient.deceasedBoolean)
            if isdeceased is not None:
                self.patient_dimension_entry._vital_status_cd = VitalStatusCd.dd_deceased if isdeceased \
                    else VitalStatusCd.dd_living

            # deceased.deceasedDateTime --> deathcode / death_date
            self.deathdate = value(g, patient, FHIR.Patient.deceasedDateTime,
                                   True)

            # birthdate - must be processed after deceased, as deceased goes into age calculation
            bd = g.value(patient, FHIR.Patient.birthDate)
            birthdate = None
            if bd:
                birthdate = extension(
                    g,
                    bd,
                    "http://hl7.org/fhir/StructureDefinition/patient-birthTime",
                    asLiteral=True)
                if not birthdate:
                    birthdate = value(g,
                                      patient,
                                      FHIR.Patient.birthDate,
                                      asLiteral=True)
            self.birthdate = birthdate

            # address -- use == home / period.end is empty or past deathcode date
            addresses = g.objects(patient, FHIR.Patient.address)
            for address in addresses:
                address_use = value(g, address, FHIR.Address.use)
                if address_use is None or address_use == "home":
                    period = g.value(address, FHIR.Address.period)
                    if not period or (period and value(
                            g, period, FHIR.Period.end) is None):
                        city = value(g, address, FHIR.Address.city)
                        state = value(g, address, FHIR.Address.state)
                        zipcode = value(g, address, FHIR.Address.postalCode)
                        if zipcode:
                            self.patient_dimension_entry._zip_cd = zipcode
                            if city and state:
                                self.patient_dimension_entry._statecityzip_path = \
                                    'Zip codes\\' + state + '\\' + city + '\\' + zipcode + '\\'

            # maritalStatus --> map to 'single', 'married', 'divorced', 'widow', other?
            marital_stati = codeable_concept_code(g, patient,
                                                  FHIR.Patient.maritalStatus)
            for ms in marital_stati:
                if ms.system == str(V3.MaritalStatus):
                    self._marital_status = marital_stati[0]
                    msc = self._marital_status.code
                    if msc != 'UNK':
                        self.patient_dimension_entry._marital_status_cd = \
                            'divorced' if msc in ['A', 'D'] else \
                            'married' if msc in ['L', 'M', 'P'] else \
                            'widow' if msc in ['W'] else \
                            'single'
                    break
            else:
                msuri = concept_uri(g, patient, FHIR.Patient.maritalStatus,
                                    SNOMEDCT)
                if msuri:
                    # TODO: figure out what to do with SNOMED id's (terminology service, anyone?)
                    pass

            # language
            communications = list(
                g.objects(patient, FHIR.Patient.communication))
            language = None
            for communication in communications:
                pref = value(g, communication,
                             FHIR.Patient.communication.preferred)
                if pref or (pref is None and len(communications) == 1):
                    languages = codeable_concept_code(
                        g, communication, FHIR.Patient.communication.language)
                    if languages:
                        language = languages[0]
                        break

            if language is not None:
                self._language = language.code