Monday, December 3, 2018

Thinking through FHIR Mapping dependencies and products

This is part of a continuing series on mapping to FHIR.  So far, we've explored some of the information that I need to handle mappings, and some ways to do inference and identify mappings, and how all of this could actually be stored more simply in ConceptMap (rather than StructureMap).  It's interesting to note that ConceptMap as originally designed in STU2 anticipated mapping StructureDefinitions.  I'm wondering why (or perhap not considering how complicated this stuff is) we have StructureMap as well.

Now, I'll delve into some features of ConceptMap, including two that started me down this path, dependsOn and product.  These are two sides of the same coin.  If X appears in dependsOn in a concept map, then then it will likely show up as a product reverse mapping, and vice versa.

Let's look at how we might use dependencies and products here. When mapping codes in the message to FHIR, you might need to go through a mapping table (another ConceptMap resource).  How you determine which concept map to go through varies based on context (the messaging being mapped, the channel or system configuration for mapping, et cetera).  That makes the ConceptMap a dependency of the mapping from source to destination.

So far so good.  But here's the next challenge: How do I represent that in ConceptMap?  I'm using ConceptMap in ways that it's not quite (but almost) intended to be used. We've almost got what we need, but figuring out how to use these fields right is important (at least to me).  So, let's look at the definitions for the required parts of dependsOn:

dependsOn PropertyDefinition
propertyA reference to an element that holds a coded value that corresponds to a code system property. The idea is that the information model carries an element somwhere that is labeled to correspond with a code system property.
codeIdentity (code or path) or the element/item/ValueSet that the map depends on / refers to.

Tricky definitions here.  Property says "where in the context do I find this", and code says what is its identity.  Ok, it's getting a little bit message, perhaps I should start simpler.  How would I normally use this?

A dependency could be a filter on the mapping element, in which case, it might address the question of when to use this mapping.  If property was MSH-9 (Message Type), then the code might identify a specific message type that this concept mapping element is to be used for.  If instead it was a ValueSet, it could identify a set of discrete values, which, if MSH-9 matched, might indicate activation of this concept mapping element (e.g., if building a mapping for specific types of ADT messages).

OK, so far, that makes sense.  Let's see how this works:

When the message is an ORM_O01, it's clearly an order, and it can produce DiagnosticOrder, ProcedureRequest, ReferralRequest and several others in STU2 with a slightly different list in STU3 and beyond.  MSH-9 doesn't always tell you what kind of thing to produce, but OBR and RXO segments might indicate what to produce based on the codes found in OBR-4, or RXO-1.

So, we might indicate that an OBR produces a ProcedureRequest when OBR-4 is in a particular value set (one containing inhalation treatment for example), and that RXO also produces ProcedureRequest based on RXO-1 being in a different value set (e.g., one containing inhalation therapy).  And that in both cases, the code will appear in ProcedureRequest.code as a product of this concept mapping (note, this might also be stated elsewhere as a mapping, where RXO-1 and OBR-4 produce value for ProcedureRequest.code). Thus, when doing the reverse mapping, ProcedureRequest might produce an OBR segment or an RXO segment, depending on the code found in ProcedureRequest.code, and the products of the reverse mapping will be a value in RXO-1 or OBR-4.  So, the reversal seems to work.

When a value set is given, that implies that the operation to be used as a condition for the mapping is to see if the value set given contains the code.  And when using fixed code values, it implies that the condition for mapping is an equality test.  So, code describes what the mapping depends on, and the type of thing depended on implies the operation to perform.  Extending from that logic, if what appears in code is a reference to a concept map, the implied dependency is to perform a concept map translation based on the property referenced.

Let's say that a requirement of my mapping is to translate local codes into standard ones, I could represent the code as a specific concept map used for translating the values, and then indicate that code depends on that concept map.  OK, that seems to work.  Except what if there isn't a mapping?  Looking to DSTU3 I can see they'e added a case to ConceptMap that handles unmapped codes, but this isn't present in DSTU2.  Ah well, I can fall back on my forward compatibility cheat.

Now it gets ugly.  OBR-4 could be a local code, in which case I can have two dependencies, one which says what to build, and another that says what to map.  Ahh, but recall that there's both model to model and instance to instance mappings.  Hmm.  Model to model says what to create, instance to instance says how to copy values.  OK, theory is being more clear, but closer to etched glass rather than painted black (where I started).  It's still fuzzy BUT, I think I have enough now to write some code.

   Keith

P.S. Welcome to my mind.  These last three posts are all part of a single stream of consciousness as I work out some of the details of this gnarly problem.



Crosswalking structures to and from FHIR

Boston - Crosswalk
In thinking about how to express the mappings, I'm going through a process of identifying assets that can be used. The biggest of these assets is knowledge, that is to say, expressed, declarative statements that provide facts about how the process might be executed.  These need to be stored in some sort of data structure.  I struggle with how StructureMap is put together, and so I'm going to try something different.  ConceptMap is used for mapping concepts, and model elements are nothing more than specializations of concepts, so I'm going to use that I think.  In fact, if you look at it, you can see the developers of it considered that it could be used for just that purpose as well, as you can see certain references in it to StructureDefinition.  So, the next thing I need to figure out is how to use that.  Let's go look at the knowledge I need to be able to capture.

For example:  The V2 MSH structure should map to a FHIR MessageHeader resource, or a CWE should map to a CodeableConcept.  A lot of this information is already present (or largely so) as data in Mapping tables found in the FHIR Resource definitions (with some semi-regular structure).

Another core component is information that can be used to make inferences.  For example, ways to convert Instant to DateTime, or CodeableConcept to Coding, or Family Name (FN in V2) to String (ST).  I might even be able to make an inference based on a rule that PPN = Flatten(XCN)+TS (well, not quite, but close, I think I'll skip that one).

Heuristics are also important in this.  My goal is to make this as simple as possible for the implementer of a conversion.  One such heuristic might be that if source structure A maps to target structure B, and the parts of source structure A produce substructures A1, A2, ... AN, and target structure B has substructures B1, B2, ... BM then it would be reasonable to assume that for some values n and m that An => Bm.  Figuring out how n and m are determined is the tricky bit.  That is to say, the subcomponents of B will be found in the subcomponents of A.

Inferring the values of n and m could be done by matching types.  So, if PV1-7 is an XCN, and XCN produces HumanName and Identifier, and PV1 produces an Encounter resource, the software would have to make some guesses about where these things go.  Knowing the HumanName and Identifier are part of several resources, It might guess (based on following references) that these might be part of Patient, RelatedPerson or Practitioner resources as found in Encounter.participant.individual or Encounter.patient, but would have to have something else to disambiguate where these fields go in more detail.

If I were also to say that PV1-7 also produces a fixed Coding having the value "http://hl7.org/fhir/v3/ParticipationType|ATND", now we might have enough information to tip the balance towards Encounter.participant.individual, because this code properly appears in the Encounter.participant.type, and PV1-7 created both.

Looking at it from the instance level, if Identifier.type was populated with the value http://hl7.org/fhir/v2/0203|PRN, http://hl7.org/fhir/v2/0203|MD, http://hl7.org/fhir/identifier-type|PLAC or http://hl7.org/fhir/identifier-type|FILL, again, we'd have some inference somewhere that says these codes apply to Practitioner.identifier.type, and so we could also just handle it by adding a fixed mapping from XCN to one of these based on the context.

XCN -> HumanName, Identifier expresses a concept mapping from coded concepts in HL7 Version 2 (type names are a concept from a coded vocabulary, we could for example, use the names of things in the V2 XML schemas) into coded concepts in HL7 FHIR (using values in /StructureDefinition//element/path or a combination thereof with type (to get to specific detail such as valueInteger on paths with [x] at the end).

So, a concept map going from V2 to FHIR might have elements looking like this:

"element": [
  ...
  {
    "code": "MSH",
    "target": [
      {
        "code": "MessageHeader",
        "equivalence": "equivalent"
      }
    ]
  },
  ...
  { "code": "XCN",
    "target": [
      {
        "code": "Identifier",
        "equivalence": "narrower"
      },
      { "code": "HumanName",
        "equivalence": "narrower"
      }
    ]
  },
  ...
],

Translating the table above to the reverse mapping, one would do the obvious things:  For each group of targets with the same code create a single element having that code, creating a target for each element to which the members of the group belonged with a target code value equal to the original source code value, and reversing the equivalences as follows:


sourcetarget
narrowerwider
widernarrower
subsumesspecializes
specializessubsumes
The rest are essentially unchanged
equivalentequivalent
equalequal
inexactinexact
unmatchedunmatched
disjointdisjoint

Next up, looking at dependencies (and products).

Tuesday, November 27, 2018

It's not time ...

As I write this, I am preparing to head off to Chicago to see my good friend and colleague, Charles Parisot, and also do something I very rarely get to do, which is sit in a room with him for several hours while he listens to other people speak.  I'm second or third up on the roster to roast him, and we will have hours yet after I speak for others to say more about Charles, who he is, what he has done, and so on.  In fact, we have about as long as a normal post meeting conversation with Charles to say it all, which in fact will barely be enough.

Rather than talk to you about what Charles is though I will get to that, I want to start with a few things that he isn't.  First of all, he is not a planetary body.  Yes, Charles does have a gravity well (it's pretty deep), and he does have an orbit.  In fact, he mostly fits all of the modern characteristics defining a planet:

  1. He orbits the sun,
  2. He is not a satellite ... for anyone or anything,
  3. He has cleared his own orbit by repeatedly brushing aside all obstacles, and finally
  4. He does have sufficient mass to be mostly round.
He even fits the definition for the old Greek term, which essentially means wanderer, and he certainly is a wanderer.  But, he is not a planet.  The reason I know that Charles is not a planet is because he fails under one very conspicuous criteria, which is that he has an event horizon, and should you get too close, you will never escape it.  Any the only things known to date which have an event horizon are black holes, former suns or larger bodies which cannot, by definition, be planets.

He's also not Carmen San Diego.  Yes, you can find him wandering all over the world, but that's the point.  You CAN find him.  All you need do is listen closely and head towards the action, or at least the action as it relates to Healthcare IT.  When I used to be in more regular touch with Charles, often the first question I would need to ask, is where are you today, even if I spoke to him yesterday.  Twice, without even knowing beforehand, I simply asked hum which ministry call he was on this morning and twice he met my expectations, although in all fairness, it was only one of those days that he was testifying to Parliment somewhere.

Charles does not sleep, except perhaps on long-distance flights.  I know this because I've gotten e-mails from him at all times of day, and so have you.

Charles doesn't do any real work.  That's what his gravity well is for.  Should you happen to get sucked into it, you will do the work.  Charles will just sit back and do what he likes to do, which is talk, and argue.  Charles will talk for so long, you will agree to do just about anything for him just in order to get some peace.  But if he doesn't do any work, how does he get so much done?  See, that's just the point.  Charles doesn't create projects, he co-opts them, often several at a time.  Then he puts them into a big bucket, stirs them up, and watches as things magically arise from the bizarre concoction of ideas.  Charles doesn’t have a say-do ratio, in fact he completely destroys the concept of say-do ratio, because no matter how much he speaks, what comes out of it is clearly more than what went into it.  It’s more like the ratio of aleph null to aleph one.


Charles is neither a noun, or a verb, although he has been used in both senses.  You can pull a Charles, or Charles someone.  Charles is also not an unstoppable force, he can be moved, but his reaction to outside influences is quite confusing, more like a centrifuge or gyroscope.  When you try to push Charles in a particular direction, be very wary, because his response will often be at right angles to the direction of the applied force.  Be very wary when he agrees with you (especially completely), because that often means you are about to be the recipient of a perpendicular reaction that is completely unexpected.  This is what it means to have been Charles'd.

The last thing I will say about what Charles is not is that Charles is almost certainly not retired.  We here all know that he will be continuing to pop up in our lives, perhaps in even new and more interesting ways, now that he will soon be removed from the restraints placed upon him by his current employer.  I'm certain we will all continue to see him, because fortunately or not, we are all inside his event horizon.

OK, I lied.  That was not the last not.  Charles is also not a recipient of the Ad Hoc Harley award.  But as to what he is, and I did say I'd get to that, is certainly overdue for induction into 2018 class of the Lords and Ladies of the Ad Hoc Harley.


Charles Parisot
Semper et semper ascendens deinceps
(ever and ever riding forward)




Monday, November 26, 2018

Mapping Data Types in FHIR

Community social mapping by
Community Eye Health, on Flickr
One of the cool things about FHIR is the sheer amount of data about the standard that is available in computable (or nearly so) form.  For example, all the HL7 Version 2, Version 3 and CDA mappings.  One of my day to day challenges is converting things to and from FHIR, and so I've been thinking about the problem of how to handle conversion in a generalized way.  FHIR has a Mapping Language, but it requires expression of a large amount of information that I find to be somewhat repetitive.  It's essential to have all of the information it requires to get the mapping to work, but there should be an easier way to do this.

In thinking through this problem, I recall a tracker item I created for the ConceptMap translation operation structure that was related to how one might select a concept mapping based not just on a code, but also on other values (dependencies) that might be present in an instance that needs to be mapped.  ConceptMap has both dependsOn and product, which reflect additional data in translation.  A given mapping that uses dependsOn and product well can be made reversible, which is a REALLY nice feature to have laying around.  NOTE: I said "can be made", not "is".  You have to work at it, because mappings that generalize in one direction, will wind up specializing in another direction, which can be a bad thing.  It might be OK to generalize up a level for some things, but specializing down can often lead to incorrect conclusions.

The devil is in the details, but that is where dependsOn and product fields in a concept can help, because they can provide details to produce mappings that have only equivalents, instead of other less precise mappings.  So, if we can create a reversible concept mapping table, would it also be possible to create a reversible structure mapping table?  NOTE: Reversibility isn't a requirement of what I'm trying to do, but it would be nice if the outcome was something that could allow me to express a mapping that could be reversed.

The basic process of mapping takes one or more components (or perhaps zero or more if mapping to a fixed value, but I digress) from the source structure, and maps it, possibly through some transformation, to one or more components of a target structure.

I think that there are two kinds of mappings that I need to worry about: Type mappings, and instance mappings.  In a type mapping, I can say "this source type" can be mapped to "that target type".  I would express those as MSH -> MessageHeader.  Read that as "MSH produces MessageHeader".
In an instance mapping, I want to say that "this source element" is mapped to "that target element", or more directly: Bundle.entry.resource <= MSH(0).  Read this as Bundle.entry.resource takes the values produced by mapping MSH.

Some things might generate two or more objects when going from source to target.  For example, the V2 XCN data type should generate both a HumanName data type, as well as an Identifier Data type.  The XCN data type in question could be generating a Patient, Practitioner, or RelatedPerson, but from a mapping perspective, the mapping should reflect the specific level of detail we know.  Other context, such as where the XCN data type is used would then tell us which one of those resources is actually being produced.  This might be expressed in the form: XCN -> HumanName, Identifier.

In the previous example, there's really only one edge case in most HL7 messages where an XCN might be other than Practitioner (In TXA, where the document originator might be the patient or an authorized representative), so it's not a huge problem here.  For most uses of XCN, we'd just probably want to say something like: source-field -> destination-field, for example: PV1-7 -> Practitioner, and also PV1-7 -> Encounter.participant.individual.  But in this odd-ball case, we'd probably need something else to tell us that what we are generating is Patient or RelatedPerson.

Type specific mapping rules can handle certain cases, in the above for example, to address the case of referencing the generated practitioner in the case of PV1-7.

One thing can map to two items, but in some cases, the one thing has to map to two parts of the same item.  For example, CWE-1 to CWE-3 map to a single coding.  I might say that the compound {CWE-1, CWE-2, CWE-3} -> Coding.  Figuring out where to put this is sometimes complicated.  It might go into a coding element, a CodeableConcept, or be (concept) mapped to a FHIR code in the resulting structure.

I'm leaving a lot of details out of my mapping on purpose, because what I want to be able to do  is INFER a lot of the detail with the data I have, either from context, from more general rules, or from configuration.  I ought to be able do some of that inference based on data types and potential data type conversions.  To explain: If I say that CWE -> CodeableConcept, the system that interprets my mapping structures should know fairly well how to down-convert a codeable concept to a coding or a code, and the mapping context should be able to help.  That way, any time CWE  The same thing might also be true for certain HL7 data types which in some versions are simply strings, but in later versions are more complex data types where the value found in the earlier version is stored in the first component of the data type (e.g., compare for example, XCN-1 in HL7 2.3.1 vs. 2.5.1 where FN replaces ST, and thus, one could "down-convert" FN to ST by taking the value of its first component).

Done right, one might be able to express a mapping from one structure to another fairly concisely with some default rules (e.g., to handle various type conversions), in a way that could enable definition of a one-to-one and onto mapping that might well be reversible.

I'm still struggling with various parts of this, but I think I'm somewhat close to having something working.

   Keith

P.S.  Don't worry, I'll get back to that other exercise I'm doing on Risk Analysis, I just haven't had the time to do some of the additional research I need.

Wednesday, November 21, 2018

Happy Thanksgiving All

For those of us in the US, happy thanksgiving.  For those of you outside the US, happy day without having to deal with the rest of us here who will be off for the rest of the week.

As has been my tradition over many years, I'm posting the Engage with Grace slide again.  Consider having this discussion after dinner tomorrow.



-- Keith


Friday, November 16, 2018

A Risk Assessment Excercise in multiple parts: Threats

Villainc
Continuing my risk assessment from last post, I'd like first to report a missing item or three from the previous list of assets being protected:

  • The USB device itself (duh).
  • Other data on that device (personal or otherwise).
  • Anything that device could connect to
Having identified what needs protection, now we need to look at what we are protecting it from:
  • Theft
  • Damage (e.g., electrical hardware damage)
  • Data Corruption
  • Loss of sensitive information
  • Exposure of sensitive information
  • Infection by malware (virus, trojan, ransomware, other)
  • Denial of Service
There are a number of downstream consequences that might result from these core threats, but these threats get at most of the root causes.  I'll look at various potential mitigations for these issues next week.



Friday, November 9, 2018

A Risk Assessment Excercise in Several Parts

Guidelines of impact relevance for IHE profiles
from the IHE Security Cookbook

One of the challenges for anyone involved in activities in Healthcare IT standards development is being able to share documents, presentations, training and other materials used in the development of the standards.  Like many in this field, I have access to not just those materials which I need to be able to share, but also access to a lot of other things that shouldn't be shared and which needs to be protected.

I've been in settings where I'm creating or revising a document or presentation, where the fastest way to get it to somebody somewhere is via a USB memory device.  But if access to external storage is locked out, then I cannot share information, or accept information from devices that may be shared with me.  In some cases, it's been nearly the only way (ever try to get to wireless or WIFI at a very busy, yet under-provisioned conference setting ... sometimes it's just not possible).  I've been in presentation settings where the presenter system is owned by the organization, and for related reasons, is the only thing that can be used for presenting, so the only way to get content may well be a USB stick.  These are infrequent, yet USB is still the fastest way often.

Yet, USB sticks (and other devices) are a two way infection vector, and also a way to enable transfers of huge amounts of information that sometimes shouldn't be shared. Even in cases where it should be, may need its own set of protections (e.g., encryption and authentication for use) to prevent it from falling into the wrong hands.

So, I need a risk assessment and mitigation strategy if I'm to justify any sort of exception to a complete lock-down.  This post represents the first of several posts that walk through a risk assessment process.  We'll start first in this post with assets to protect, move on next to threats, then assessment and mitigation.

Here's a partial list of assets that need protection.
  • My Company Issued Laptop
  • My Data
    I have pictures on my laptop that are mine, which I might want to save, my company laptop has access to many web sites I use for both personal and professional reasons.  I may have personal data related to my work (e.g., Payroll, taxes, benefits, health insurance). I want to protect that content.
  • Infrastructure
    Anything my laptop (where the USB device would be used) can access, can subsequently be attacked by my laptop were it to be infected.
    • Corporate Infrastructure
    • Customer Infrastructure
  • Intellectual Property
    Anything I have access to via that laptop could potentially be a target, including:
    • Company IP
    • Partner IP
    • Customer IP
    • SDO IP
      Examples include presentations, training material, and draft content of specifications that I may be working on.  This is material I often need to share with others.
  • Individually Identifiable Data
    Various regulation requires additional safety around certain classes of data that might be available via my laptop, including:
    • Patient Data (PHI)
    • Data about other Individuals (PII)

Consequential to the threats to any of these assets, are threats to my reputation, and those of my employer, its partners and customers, and to the financial status of those organizations.  One simply need look at what happened last year with the NotPetya attacks to see how much damage can be done.

I invite your comments and feedback below!