FHIR Messaging: Clinical data from ADT Messages

In the last post, we started to think about how we might be able to capture clinically useful information (naturally as FHIR resources) from the HL7 v2 messages that are used within many hospitals. These messages are used to move information between the various components of a hospital such as the PAS (Patient Administration System), the RIS (Radiology Information System), the LIS (Laboratory Information System) and so forth.

A common pattern is that the ‘downstream’ systems (LIS, RIS) ‘subscribe’ to these messages emitted from the PAS – generally via an Integration Engine. So all we’ll do is add ourselves to the list of interested parties, and we’ll get a copy of each message as well.

And actually, there’s no real reason why we should confine our attentions to just one hospital – if there are multiple co-operating hospitals then there’s no reason why we can’t receive messages from all of them, though we do need to be careful with identifiers (patient and visit) as these might overlap between providers.

Here’s what it might look like, with the arrows representing the flow of v2 messages:

accumulator

The resources we identified that we could get from this data were:

  • Encounters (always useful to know when people have been – or are – in hospital)
  • Conditions – actually ‘Diagnoses’ relating to those encounters. Not as good as a formal problem list, but still helpful. (And, once we get the basics working, there are other Condition-related messages that we might tap into)
  • Allergies – good to know those! Of course, the provenance of allergies from ADT messages might not be as good as coming from clinical messages, but still useful.
  • Procedures – well, you would expect a hospital to know what procedures they are performing.
  • Observations. Not quite sure what these represent in the context of an ADT message, but let’s store them.

Now we’re said that we’re in a messaging paradigm now, but what does that actually mean?

Well, as the diagram above shows. we are receiving messages that have been sent by another system (generally the PAS) in response to real world events that occur as the patient is treated in the hospital. This has a couple of implications for us:

  • We need a way to link all the messages to the same patient (actually, the same encounter or visit for that patient). In fact, this extends to the actual model itself – there needs to be some link from each resource to the message that created it (or at least to the Encounter resource that represents it).
  • We need to think about what the impact each message type has on our data model, which will vary according to the event that it is describing.

(Actually, in real-life we also need to consider how to manage ‘out of order’ messages – what do we do when, say, a bed transfer message arrives after a discharge message? This is an implementation issue, and so we’re going to ignore it in this discussion, but if you’re doing this for real then you will need to decide what strategy you are going to follow – for example you could reject such messages and make the sender decide what to do, or you could make a decision based on the date of the message – or anything else, an exercise for the reader 🙂 )

So what does our model look like? Well, here’s a first draft:

message-model

Note that all the ‘clinical’ resources have a link back to the encounter where we got them from. We’re going to need this to be able to properly manage changes that might occur due to workflow issues, and also as a kind of ‘provenance’ – knowing the source of clinical information is always important. (Actually, there’s a formal Provenance resource that we could use if we wanted to).

In most of the resources there is a property that makes sense:

  • Condition: Encounter when condition first asserted. We’ll be setting the Condition.category to ‘diagnosis’, and creating a new Condition for each visit (as the diagnosis is about that visit).
  • Observation: The healthcare event where this observation is made
  • Procedure: The encounter when the procedure was performed
  • AllergyIntolerance: This needs to be an extension, as there is no encounter reference available. You could argue that this should be similar to Condition – i.e. that there should ‘encounter first asserted’ property – if you feel strongly about it, then raise a change request on the spec – we’ll just use an extension.

We haven’t indicated any Patient, which all of the resources will have a reference to. As we’re getting information from different sources which will have their own patient referencing systems, this is going to need some thought which we’ll go into in the next post.

OK, so we have the model – let’s think about what each message is going to do to our model (we’ll come back to the question of linking all messages to the same ‘encounter stream’ later on).

There are a lot of messages to consider – over 60 of them in the 2.4 spec (which is the version we’re using)! The actual messages that are used will be different in each implementation, and we don’t have space to consider them all, so we’ll pick a selection that will highlight the major factors that we are going to need to consider.

The table below lists some of these messages and the impact on our model. For readability, we’ve just included the event code, so A01 is actually ADT^A01.

Some of these messages are reasonably straight forward to process – and others are not!.

(btw – it’s a good idea to read this in conjunction with the v2.4 spec – it’s in chapter 3 – Patient Administration)

Message Purpose Has clinical data Description
A01 Admit/Visit Notification yes This is the message that is sent when a patient is admitted to the hospital – ie assigned to a bed. When received by the system it will create a new Encounter resource, along with any clinical data.
A02 Transfer a Patient No This occurs when a patient changes physical location – for example they are moved to a different ward. It will update the encounter resource, but not the clinical data.

Interestingly, the spec notes that if there is any clinical data that changes, then the A08 message should be sent.

A03 Discharge/End Visit some Sent when the patient is discharged. It will update the Encounter, and may include diagnosis & procedure information (but not allergy). Again, the recommendation is to use A08 if needed to update associated data
A04 Register Patient yes Similar to the A01, this indicates that the patient is at the hospital (eg in the EC – Emergency – department) rather than being formally admitted. We would create a new Encounter if we get this message.
A05 Pre-Admit a Patient Yes Will also create a new Encounter (and clinical data). Used during a pre-admission when the patient is examined before the actual date that they are admitted (this is common for planned – or ‘elective’ procedures).
A06 Change an Outpatient to an Inpatient yes Used when a patient who is being seen as an outpatient is admitted. For example someone is in a cardiology outpatient, and their condition is so serious that they are immediately admitted.

Interestingly, the spec stats that this may either change the existing encounter (the outpatient one) or create a new one. From our perspective, this raises the question of how to identify an encounter – which we will talk about soon. It also shows how the v2 spec is used in different ways for different implementations – you need to check these things!

A07 Change an Inpatient to an Outpatient yes I’m not quite sure when this would be used – a discharge would seem more logical, but I guess there are systems that do it this way. Like the A06, this might either change an existing encounter or create a new one.
A08 Update Patient Information yes This changes the information associated with the patient, but which doesn’t effect the encounter. For example a new allergy is discovered. The encounter resource will be unaffected, but the clinical resources may well be.
A11 Cancel Admit / Cancel Visit Notification no This cancels an admission (A01) or a registration (A04) – either because of error, or because a decision is changed.

We’ll set the status of the encounter accordingly – but an interesting question is what to do with the clinical data. Should we invalidate that as well?

A12 Cancel Transfer no When an A02 (transfer) is cancelled. The encounter status will be updated, but the clinical data we’ve extracted can remain.
A13 Cancel Discharge / Cancel End Visit yes Similar to the A12 event. The encounter only is updated
A28 Add Person or Patient Information yes This is similar to the A08, but is specifically intended to update patient related data between systems that may have different master patient databases. Like that event, the clinical data but not the encounter will be updated.
A31 Update Person Information yes This is specifically intended to update patient information in an Enterprise Master Patient Index ( EMPI). We can use these messages to update our patient store so we know who the patient identifiers refer to, though we could also extract the desired information from the PID segment of any of the messages.
A37 Unlink Patient Information no This is an ‘unlink’ message – see A40 for discussion. (There used to be an A36 – patient merge message that the A40 replaces)
A38 Cancel Pre-admit no Cancels an A05. The same considerations as for A11
A40 Merge Patient – Patient Identifier List no This event indicates that 2 patient identifiers are actually the same person, and we need to ‘merge’ them together. Patient identity is a really complicated topic that we’ve dodged so far, but this time we can’t. Having said that – how we manage it is going to be entirely dependent on how we implement patient identity.

  • If we have an architecture where, at read time, we take the supplied identifier, locate all the merged identifiers, and return all the data related to all those identifiers then we’re sweet.
  • If we only look up on the single identifier, then we need to go through existing data and change identifiers – in a way that will allow an ‘unmerge’ to work

Either way it needs careful thought, and the v2 spec has quite a lot to say about it.

A45 Move Visit Information no Another potentially tricky one. The spec states that this is a ‘move at the visit identifier level’ – where the ‘patient account’ associated with the visit has changed. In other words – the patient has changed for this visit.

For us, it probably just means that the Encounter.subject property needs to be switched to the correct patient, but anything that involves patient identity has ramifications that we’ll need to think through.

We also need to think about the effect on the clinical data we’re extracting: do we change the subject there as well? Or – do we assume/mandate that an A08 message will come though and change it? If we do, then we’re assuming that an A08 is able to change the identifier (which is not mentioned in the spec), so it may be safest to change the subject property there as well.

A50 Change Visit Number This actually changes the visit number – the identifier that indicates that a sequence of messages is about the same visit. The actual effect for us will simply be to update the encounter

So there’s a few things we’re going to need to give careful thought to – and these are likely to be ‘implementation dependant’ – i.e. they will vary between different hospitals.

  • How is a single ‘visit’ identified – i.e. when we receive a message, how can we identify the Encounter that this message is going to effect?
  • Which messages will create a new encounter, and which ones will update an existing one?
  • How is the patient associated with the visit? There’s both the concept of the ‘patient account’ and the ‘patient identifier’ to think about.
  • What do we do with the extracted clinical data when the patient identifier changes on the encounter? (A45)
  • What is our strategy for updating clinical data within a visit when there are updates, as quite a few of the messages have the capability to include clinical data?
    • Do we assume that each message has the complete set of data (i.e. a snapshot at a point in time), or are they updates? Suppose the A01 message has a particular diagnosis and an A02 doesn’t – do we remove it from the list of diagnoses for that visit?
    • Should we ‘accumulate’ data? E.g. if the A02 contains a diagnosis that wasn’t in the A01 do we just append it to the list
    • Do we update at all? Should we create a set of clinical data from the A01, and then assume/require that the source system send an A08 or A28 when the clinical data changes?

So there are a few things to think about (and I’m sure many others that we haven’t listed here). To keep things moving we’ll make the following assumptions (your assumptions may be different):

  • That the PV1-19 contains the visit identifier – that’s the formal way that we’ll recognise messages belonging to the same visit. We’ll also use a combination of the MSH-4 (sending facility) and MSH-3 (sending application) to recognise messages from different hospitals (and different applications from within those hospitals)
  • That the PID-3 holds all the patient identifiers.
  • That we’ll use the A01, A04 or A05 to create the clinical data, and require an A08 or A28 for updates to that data – and that the update will be a snapshot – it will replace the data that is already present for that visit.
  • That we’ll support multiple identifiers for a patient – but keep data against the identifier that was specified when we receive it. We’ll ‘resolve’ multiple identifiers for a patient at read-time. (ie when a querying system asks for data using an identifier, we’ll resolve all the identifiers for that person – using an EMPI – and return all the matching data).
  • If the patient changes as a result of an A45, we’ll assume that there will be an A08 message that will follow with updated clinical information. This message will be able to change the subject associated with these resources.
  • We’ll be tolerant of ‘out of order’ messages, but we’ll use the message time (MSH-7) to decide what action they will have. For example, if we’ve received a discharge message (A03) and so set the encounter.status to ‘finished’ and then we receive a bed transfer (A02) then the action will depend on the relative dates. If the transfer message is dated after the discharge then we’ll revert the status to ‘in-progress’, otherwise we’ll ignore the bed transfer (though we might update the status history).

In practice of course, we’d need to ensure that the source systems abide by these rules. If they don’t, then we’ll either need to change our system – or possibly use an Integration Engine to update messages from specific hospitals to make them compliant. For example, if a particular hospital does not emit A08, but does include a snapshot of clinical data in all update messages (like an A02) then the Integration Engine could create an additional A08.

So let’s take another look at our list of supported messages and what they are going do in our system.

Message Purpose Action in our system
A01 Admit/Visit Notification Create a new encounter and all related clinical data
A02 Transfer a Patient Update the Encounter properties
A03 Discharge/End Visit Update the Encounter properties
A04 Register Patient Create a new encounter and all related clinical data
A05 Pre-Admit a Patient Create a new encounter and all related clinical data
A06 Change an Outpatient to an Inpatient Update the Encounter properties
A07 Change an Inpatient to an Outpatient Update the Encounter properties
A08 Update Patient Information Update the clinical data associated with this encounter. Note that this can change the subject associated with those resources as well.
A11 Cancel Admit / Cancel Visit Notification Update the Encounter properties
A12 Cancel Transfer Update the Encounter properties
A13 Cancel Discharge / Cancel End Visit Update the Encounter properties
A28 Add Person or Patient Information Update the clinical data associated with this encounter
A31 Update Person Information Not quite sure about this one yet. It’s not really related to a particular encounter, so we’ll think about it a bit more when we start to consume other messages. For now, we’ll ignore it.
A37 Unlink Patient Information Our patient identity system will no longer assume that these two identifiers refer to the same person.
A38 Cancel Pre-admit Update the Encounter properties
A40 Merge Patient – Patient Identifier List Mark the two identifiers as being the same person. (The message contains the ‘surviving’ identifier). We won’t actually merge them – we’ll just link them together. That way we can ‘unmerge’ – A37 – them later.
A45 Move Visit Information Change the encounter.subject to reference the new patient identity
A50 Change Visit Number Change the encounter.identifier property. Of course, an encounter may have multiple identifiers so we’ll need to make sure to change the correct one!

That’s quite a chunk to think about! And hopefully explains why workflow is so important, and why this stuff can be so complicated! We’ve just looked at a small selection of messages – and all we’re really doing is to maintain a store of resources – imagine if we were writing a PAS ourselves!

In the next post we’ll delve into architectural issues and think about what we need in our FHIR server to support these messages. Oh, and if you disagree with anything in the post – feel free to make a comment!

About David Hay
I'm an independent contractor working with a number of Organizations in the health IT space. I'm an HL7 Fellow, Chair Emeritus of HL7 New Zealand and a co-chair of the FHIR Management Group. I have a keen interest in health IT, especially health interoperability with HL7 and the FHIR standard. I'm the author of a FHIR training and design tool - clinFHIR - which is sponsored by InterSystems Ltd.

6 Responses to FHIR Messaging: Clinical data from ADT Messages

  1. Pingback: The Architecture and the (FHIR) Message | Hay on FHIR

  2. Rene Spronk says:

    For FHIR connectathon #9 (Paris, May 2015) I started working on some challenging test cases, and immediately came up with the ‘update’ issue, in combination with the ‘snapshot’ nature of messaging. If we have one ADT message with 3 allergies, followed by an ADT message with 2 allergies, that just means that one allergy ahs been removed from the list. But which one? And how does one know that the remaining 2 allergies are the same as those in the prior list ? in HL7v2 allergies doesn’t have a unique id.

    In your scenario the intergration engine stores the clinical resoirces in a repository. Taking resources out of their context (be it a message or a document) to me means that one SHALL use a provenance resource. This is also useful if one has one message updating another one, you can at least find out what resources are involved/should be updated.

    The assumption that PV1-19 will always be populated depends on your context, in some countries it’s more or less mandatory, in others it’s not. Tackling the ‘identifier’ issue will be a big issue when transforming from v2 to FHIR .. againbecause of its impact on having the capability to do updates.

  3. Hi David,

    great article! Thats very helpful information!

    However I’m not sure I understand the reasoning behind linking AllergyIntolerance to the Encounter Resource. I’d expect such information to be in the scope of Patient.
    I’m thinking of a scenario in which the sending system always sends a snapshot of all known allergies.
    E.g. if a PAS system has a peanut allergy documented for a patient, I’d expect the system to export this information with the next ADT_A01 event even if the allergy has not been re-entered during the admission process.

    Or, if a patient has two different allergies reported in 2012 and one is added during a readmission in 2015, I’d expect the system to export three AL1-segments with the next ADT event, not just the one that has been logged in the context of the current encounter.

    My approach would be to link AllergyIntolerance to Patient and expect the server side implementation, to replace all previously reported AllergyIntolerance Resources submitted by the same source (here: the PAS) with every new ADT message.

    The reason being that there might be another system that has more detailed or more current knowledge about the patient’s allergies and have added additional Information (e.g. from a dermatology practitioner or a lab system). Since we cannot assume that the PAS has the same knowledge, we’d have to be sure not to touch these Resources during the processing of the PAS update.

    Although, I’d have no clue how to select the AllergyIntolerance resources based on the source system…

    This is a tough one 🙂

    • Oh, wait.

      AL1-segments don’t have identifiers, so the integration engine will have to assign them when generating the AllergyIntolerance resource from the message.
      So, the resource identifier’s system would be set to a URL/OID that identifies the integraton engine. Selecting a patient’s AllergyIntolerance resources by their identifier.system.value should make a clean update possible…

      Unless serveral systems are being routed over the same integration engine to the FHIR server, but then the engine could still use different URLs when assigning the identifiers.

      One day, Integration Engines are going to save the planet 🙂

      • David Hay says:

        Thanks! This is, indeed, a tricky area! My reasoning for linking the allergy to the encounter (as well as the patient – should have been explicit about that) was that the source of the allergy was an encounter, so needed to be updated by messages relating to that encounter – such as the A08. I’m also assuming that the updates are a snapshot for that encounter – but this too is an area to be discussed by the community I suspect. Hopefully, we’ll generate some fairly firm guidance about some of these issues, rather than making implementers work it all out themselves…

        I note that Rene has some rather nice ideas about using the Provenance resource to indicate this as well, so I suspect the model is due for an update soon!

        cheers…

  4. Great job David, as usual. It would be interesting to see a mapping from the ADT message to the applicable FHIR resources. Perhaps starting with an ADT message profile identifying which message elements are used.

Leave a Reply

%d bloggers like this: