Monthly Archives: December 2011

Health Intersections is 1 year old

I’m back after a few days down following a hosting problem.The original host took my site down since it was occupying too much CPU time. I don’t know what the cause of that is, but we’ve taken the opportunity to migrate to a better host. I’ll be bringing the old site back piece by piece so that hopefully we can pin point the problem if there is one.

While we were down, the one year anniversary of the establishment of Health Intersections passed by. I’ve been much busier than I expected – actually, much busier than I wanted to be. The government’s putting the pressure on with the PCEHR implementation here, and that’s keeping me real busy. Still, I’ve been glad to work with all sorts of clients, and to keep my association with Kestral (previous employer) alive. As well as continuing to be tethered to reality through maintaining HL7Connect – a dinky little interface engine that does HL7 v2, CDA and (soon) DICOM. It’s not loaded with features, but it’s simple to use, and it’s price point is unmatched.

Perhaps the most significant thing I’ve done this year is drafting what I called “Resources for Health”, which HL7 has adopted with real interest as a way forward for HL7 standards. HL7 has proposed that it be renamed to Fast Healthcare Interoperability Resources, and so I’ve renamed my draft – which has had a little bit of work since the last meeting, though not as much as we hoped.

Everything you didn’t want to know about the GTS data type

Of all the HL7 / ISO 21090 data types, by far the most complex is the General Timing Specification (GTS). (Aside: I usually say that CD is the most complex data type, but it’s not; it’s just that people use CD as hard as they can, where as one glance at GTS convinces almost everybody to keep things as simple as they possibly can.)

GTS in Data types R2 / ISO 21090

It’s easier to consider GTS in R2, and then work backwards to explain what GTS is in data types R1 (CDA). In ISO 21090, a GTS is a QSET(TS) – a set of TS. This is a mathematical set – some type of expression that defines what times are “in the set”, rather than a computational set, which lists the values of the set. In the case of ISO 21090, the expression can be built by combining simple times and intervals of times with grouped and nested operations such as Union, Intersection, etc.

Formally, these are defined as a set of classes like this:

 

Type Basic Summary
QSET Abstract base type. Anywhere QSET(T) is specified, one of the types below must be used
IVL A simple interval from start time to end time (may be open and therefore continuing)
PIVL A simple interval of time that repeats regularly (the interval might be assumed, like as in “3 times a day” or explicit, such as “twice a day for half an hour”)
QSI The intersection of two other sets (a simple case: the intersection of 2 times a day for 10 minutes from 10-Aug 2011 to 10-Sept 2011)
QSU The union of two sets of times (perhaps, 3 times a day on week days, and twice a day on weekends)
QSD The difference between two sets of times
QSP The periodic hull of two sets of times:  )
QSH The convex hull of two sets of times:
QSS A list of times, where the time covered by the imprecision of the time is in the set (i.e. 24-April 2012 means all of that day is in the set). This is simpler to use than IVL where single days are covered
QSC A code that identifies a set of times. The codes are only those defined by HL7 or ISO members, and include common clinical codes, as well as holidays:

  • AM  Every morning at institution specified times.
  • PM  Every afternoon at institution specified times.
  • BID  Two times a day at institution specified time
  • TID  Three times a day at institution specified time
  • QID  Four times a day at institution specified time

(note: Alert HL7 readers might wonder where EIVL is. Since this is my blog, I get to send it off to Antarctica from where I’ll retrieve it when it’s a cold day in hell)

That’s pretty confusing – so let’s clarify slightly by an example:  “every other Tuesday in the season from the (US holidays) Memorial Day to Labor Day in the years 2002 and 2003”. This is built as an expression of the intersection between 3 sets:

  • every other Tuesday;
  • the years 2002 and 2003;
  • the season between Memorial Day and Labor Day.
<example xsi:type="QSI_TS"><!-- intersection, because it is a QSI -->
 <!-- every other Tuesday -->
 <term xsi:type='PIVL_TS' alignment='DW'>
  <phase lowClosed='true' highClosed='false'>
   <low value='20001202'/>
   <high value='20001203'/>
  </phase>
  <period value='2' unit='wk'/>
 </term>

 <!-- 2002 and 2003 -->
 <term xsi:type='IVL_TS' lowClosed='true' highClosed='false'>
  <low value='20020101'/>
  <high value='20040101'/>
 </term>
 <!-- season between Memorial Day and Labor Day -->
 <!-- periodic hull between Memorial day and Labor Day -->
 <term xsi:type='QSP_TS'>
  <low xsi:type="QSI_TS">
  <!-- memorial day: intersection of last week of May and mondays -->
   <term xsi:type='PIVL_TS'>
    <phase highClosed='false'>
     <low value='19870525'/>
     <high value='19870601'/>  
    </phase>
    <period value='1' unit='a'/>
   </term>
   <term xsi:type='PIVL_TS'>
    <phase highClosed='false'>
     <low value='19870105'/>
     <high value='19870106'/>
    </phase>
    <period value='1' unit='wk'/>
   </term>
  </low>
  <high xsi:type="QSI_TS">
   <!-- labor day :  intersection of first week of Sept and mondays -->
   <term xsi:type='PIVL_TS'>
    <phase highClosed='false'>
     <low value='19870901'/>
     <high value='19870908'/>
    </phase>
    <period value='1' unit='a'/>
   </term>
   <term xsi:type='PIVL_TS'>
    <phase highClosed='false'>
     <low value='19870105'/>
     <high value='19870106'/>
    </phase>
    <period value='1' unit='wk'/>
   </term>
  </high>
 </term>
</example>

For me, what this example clarifies is the following:

  • You can build any timing description you like from this.
  • There’s too much power to grapple with the general case here in a computable way
  • This is a bad way to communicate timing specifications between people

That’s a particularly nasty combination for me – from a computable view point, it’s too powerful. From a human view point – which is where we fall back if we can’t get to compute these things – it’s very clunky.

In practice, every use of the GTS data type that I’ve seen, people either use IVL, PIVL, or a bounded PIVL: a PIVL intersected with a IVL where the IVL serves as start and end dates. Anything else gives nearly everybody fits, and I’ve never seen it used (will be happy to hear real experience otherwise in comments).

R1 vs R2

GTS appears rather different in R1 than R2. Firstly, we completely rewrote how we describe GTS, so that it’s comprehensible (I know what GTS means in R1, but only because I wrote data types R2, and then wrote my R1 -> R2 implementation). We did also make some changes in the features of GTS too, by adding

  • QSC – a coded GTS
  • QSS – a list of times

Other than that, there’s no semantic change.

GTS in R1

I’m not even going to explain how GTS is specified in R1, it just hurts my head. The XML is kind of goofy (though it works). But it has one rather sad side effect that not many people realise. Let’s take that same example as above:

<effectiveTime xsi:type=’SXPR_TS’><!– memorial day –>

<comp xsi:type=’SXPR_TS’>

<comp xsi:type=’PIVL_TS’>

<phase>

<low value=’19870525’/>

<high value=’19870601′ inclusive=’false’/>

</phase>

<period value=’1′ unit=’a’/>

</comp>

<comp xsi:type=’PIVL_TS’ operator=’A’>

<phase>

<low value=’19870105’/>

<high value=’19870106′ inclusive=’false’/>

</phase>

<period value=’1′ unit=’wk’/>

</comp>

</comp>

<!– labor day –>

<comp xsi:type=’SXPR_TS’ operator=’P’>

<comp xsi:type=’PIVL_TS’>

<phase>

<low value=’19870901’/>

<high value=’19870908′ inclusive=’false’/>

</phase>

<period value=’1′ unit=’a’/>

</comp>

<comp xsi:type=’PIVL_TS’ operator=’A’>

<phase>

<low value=’19870105’/>

<high value=’19870106′ inclusive=’false’/>

</phase>

<period value=’1′ unit=’wk’/>

</comp>

</comp>

</effectiveTime>

<effectiveTime xsi:type=’PIVL_TS’ alignment=’DW’ operator=’A’>

<!– every other Tuesday –>

<phase>

<low value=’20001202′ inclusive=’true’/>

<high value=’20001203′ inclusive=’false’/>

</phase>

<period value=’2′ unit=’wk’/>

</effectiveTime>

<effectiveTime xsi:type=’IVL_TS’ operator=’A’>

<!– from 2002 and 2003 –>

<low value=’20020101′ inclusive=’true’/>

<high value=’20040101′ inclusive=’false’/>

</effectiveTime>

 

Rather than having QSX, there’s a single type SXPR_TS, and it has an operator on instead. That’s just syntactical sugar – it’s the same structure. The comp just maps to the various named attributes which are operands on the operations. And some of the attributes are renamed. So that’s not so bad.

But the real difference is the way the base operands are constructed – by tacking effectiveTime elements after each other with operators on them. This is legal, even when the cardinality on the effectiveTime attribute is 0..1, because that’s the cardinality of the GTS, not the cardinality of the effectiveTime element that builds the GTS. That’s a subtlety that not many people are aware of. Additionally, the GTS would mean that same thing if there was only one effective time with 3 components like this:

<effectiveTime xsi:type=’SXPR_TS’><comp xsi:type=’SXPR_TS’>

<!– memorial day –>

<comp xsi:type=’SXPR_TS’>

<comp xsi:type=’PIVL_TS’>

<phase>

<low value=’19870525’/>

<high value=’19870601′ inclusive=’false’/>

</phase>

<period value=’1′ unit=’a’/>

</comp>

<comp xsi:type=’PIVL_TS’ operator=’A’>

<phase>

<low value=’19870105’/>

<high value=’19870106′ inclusive=’false’/>

</phase>

<period value=’1′ unit=’wk’/>

</comp>

</comp>

<!– labor day –>

<comp xsi:type=’SXPR_TS’ operator=’P’>

<comp xsi:type=’PIVL_TS’>

<phase>

<low value=’19870901’/>

<high value=’19870908′ inclusive=’false’/>

</phase>

<period value=’1′ unit=’a’/>

</comp>

<comp xsi:type=’PIVL_TS’ operator=’A’>

<phase>

<low value=’19870105’/>

<high value=’19870106′ inclusive=’false’/>

</phase>

<period value=’1′ unit=’wk’/>

</comp>

</comp>

</comp>

<comp xsi:type=’PIVL_TS’ alignment=’DW’ operator=’A’>

<!– every other Tuesday –>

<phase>

<low value=’20001202′ inclusive=’true’/>

<high value=’20001203′ inclusive=’false’/>

</phase>

<period value=’2′ unit=’wk’/>

</comp>

< comp xsi:type=’IVL_TS’ operator=’A’>

<!– from 2002 and 2003 –>

<low value=’20020101′ inclusive=’true’/>

<high value=’20040101′ inclusive=’false’/>

</comp>

</effectiveTime>

Requirements for GTS

This doesn’t really stand as a full explanation of the GTS data type. I can’t be bothered providing one of those. The question I’m interested in is, what are we trying to do here? What are the real world requirements we need here? Here’s my list:

  • We need to support common things for medications – bid, etc, and simple bounded periodic intervals
  • Whatever we do has to be human readable as a fall back for when computing it is impossible
  • We need to be able to make repeating appointments in a form that calendars can process

Anything else?

Question: Australian Health Information Security Requirements

This report of a breach of personal health information has been doing the rounds lately – it’s a very well written, from a great blog, and it’s deservedly getting a lot of attention. I sent it to several contacts in Australian commercial vendors, and one of them came back to me with a question:

What best practice standards, and applicable regulations do I need to aware of here in Australia?

I don’t know the answer to this. Here’s some references:

Much of the information in that list or elsewhere on the internet is specifically about the new healthcare identifiers, and the question is much wider than that. I don’t think this is a good answer, and I suspect that most of the vendors don’t have anything better.

Have I missed anything? references?

 

Question: How do 13606 and CDA relate?

Question:

I am doing a report on how well CDA fits in with ISO 13606. I understand it was derived from the ISO 13606 standard but am struggling to find literature about the mapping, e.g. EHR extract – clinical document; folder – ?; composition – ? Can you help?

Answer:

Well, it turns out, to my surprise, that I can help. A few years ago the UK NHS Connecting For Health (CfH) commissioned a technical report entitled “Results of investigating the transformability between CEN/ISO 13606, openEHR and HL7 V3″ which investigated this subject. Though there’s several references to this report on the net, the source isn’t publicly available. Laura Sato (CfH) has very kindly provided me with a late copy of the document, though not the final version (there’s some lack of clarity where that is).

Here’s the document: hl7-openEHR-13606-v0.6

Dipak Kalra – editor of the 13606 specification, and one of the authors of the above document – is planning to revisit this subject, and hoping to do so by Christmas, so something new may be available later.

Update: Rene Spronk had a copy of the final version: HL7-openEHR-13606-Transformability_v1.0

 

Australian Extensions to HL7 v2 table 0396

HL7 v2 table 0396 is the list of known coding systems in HL7 v2. The table is very US centric, and most of the main Australian coding systems are not found in the HL7 international table 0396. Through the IT-14 sub-committees, HL7 Australia has long had the practice of extending this table, but there has been no systematic approach to doing so. We need a single list that gathers everything that is used together.

Note: The table below contains candidate mappings that need review, and the review will be done on the HL7 Australia wiki here: http://hl7-australia.wikispaces.com/Australian+Extensions+to+HL7+v2+table+0396 – see there for the updated copy.

The code goes in CE.3 or CE.6 (or CNE.3/CNE.6/CWE.3/CWE.6/CWE.12) to identify the code system. The code is the only valid way to represent the code system.

Code Name Source
Defined in HL7 International Standard:
SCT SNOMED-CT Clinical Terms NEHTANote: Existing Australian standards use Snomed-CT, but given HL7 defined SCT, IT-14-6-5 has decided to change to that
ICD10AM ICD-10 Australian
modification
UOW
ICDO International
Classification of
Diseases for Oncology
WHO
LN LOINC LOINC
ISO+ Extended ISO units No known formal definition
CVX CDC Vaccine Codes HL7 Intl. – should use HL70290?
MVX CDC Manufacturers of Vaccines HL7 Intl. – should use HL70227?
Defined in Australian Standards:
LB_ site-specific local billing codes N/A, but defined per intl std.
AUSNATA Nata lab identifier AS 4700.2 / HB 262
NATA#-Version# lab local test identifier AS 4700.2 / HB 262.
Version# is optional: NATAx{xxx}[-n{nnn}]
EAN “European article Number” AS 4700.3: actually, GTIN barcode
TGAAAN TGA
approved terminology for
medicines
??
ATC Anatomical Therapeutic Chemical (ATC) classification WHOCC
Additionally Needed:
DOCLE Doctor Command Language http://www.docle.com.au/
ANZSCO Australian and New Zealand Standard Classification of Occupations (ANZSCO) http://www.abs.gov.au/ausstats/abs@.nsf/mf/1220.0
AMT Australian Medicines Terminology AMT HomeNote: this is for versions 1 and 2. Version 3 code TBA.

Note: Some users are using variations ( AMT-MP?? AMT-MPP or AMT-IT) – rationale yet to be described

METEOR-NNNNNN Code lists defined in METeOR NNNNNN is the METeOR identifier for the attribute under which the codes are defined. i.e. 291036 for Indigenous status (which is NHDD 000001 in AS 4700.1, and 270307 which is NHDD 000132)Note: subsumes NHDD and AIHW codes
ASCL Australian Standard
Classification of Languages
ABS
ICPC2+ International Classification of Primary Care 2, Australian Modication FMRC
MIMS MIMS drug codes www.mims.com.au
PBS Prescribing Benefits Codes http://www.pbs.gov.au/pbs/home
PBSM Prescribing Benefits Codes – Manufacturers http://www.pbs.gov.au/pbs/home
MBS Medicare Benefits Schedule MBS Home
Defined in Australian Standards: but deprecated
AUSPRQ AUSTPATH pathology request code set http://www.ahml.com.au/austpath.php
but use LN instead – this is a value set
AUSPRP constrained LOINC pathology report code set http://www.ahml.com.au/austpath.php
but use LN instead – this is a value set

Extending this list

Under the rules of the coding system, you can’t extend this list on a site specific basis (actually, we – HL7 Australia – are not really supposed to extend this list either). If you have your own local coding system, you have to use some code beginning with L to indicate the code system. I don’t know whether there’s any interest or point in defining a method for generating unique values in that space or not.

Discussion Form

There’s been some discussion lately that there’s no real discussion forum for healthcare interoperability here in Australi. A couple of people suggested that my blog is the default place as it is – but a blog is not a good place for a community forum.

We tried to have a technical discussion (all right, argument) on the HL7 Australia mailing list, but that wasn’t popular on the list – it’s a lot of years since we used it like that. Hence, that fell through.

So I’e set up a forum here on the site. The URL is http://www.healthintersections.com.au/forum and any one can post on the forum.  Because of the prevalence of spam and bots etc, you have to register to post, and I moderate registration.

I’m not sure how the forum’s going to go – it’s kind of a trial thing. I suspect that it’s going to be a problem, because most employers and jurisdictions won’t allow their employees to “make public statements on behalf of the organisation” (foolish, but common). One possible solution to this is to close the forum so that only registered users can see the contents; this has obvious advantages and disadvantages.

I’m open to suggestions about how the forum could/should be run.

Question: Are v2 codes case sensitive?

Question:

I have been unable to find any normative statements about the case sensitivity of values in HL7 tables, or even case sensitivity in HL7 messages and documents more broadly. Is ‘adt’ a valid message type? Is ‘msh’ a valid segment name?  Is ‘ft’ a valid datatype? Is ‘m’ a valid administrative sex code [table 0001]? Is ‘base64’ a valid encoding type [table 0299]? Could you please clarify or point to relevant documentation that might help. – thanks!!

Answer:

The codes are all case sensitive, except for one specific exemptions that is noted in the standard itself. The v2 standard doesn’t explicitly say this anywhere – it’s just taken for granted. The exception is the case of ED components 3 and 4 which e noted as case insensitive : “Note that the MIME media type values are case-insensitive, in accordance with RFC 2045”.

In practice, I have occasionally seen codes in segments other than MSH where the codes are lower case – but this is not right. HL7 wouldn’t define two codes that have different meaning, and only differ in case, so it’s not wrong to do case insensitive comparison as a receiver, but the correct case should always be sent.

Question: Interoperability vs Integration

A regular Chinese correspondent asks:

What is the difference between the terms interoperability and integration when it comes to healthcare or health information exchange? I am often embarressed when other asked me, I realize I could find a good point to explain these two. Could you give me some help?

This is a very good question, and it’s not surprising that it’s hard to differentiate the two – after all, see here, here, and here. (and that’s in English. I don’t know how it translates into Chinese).

My take is that integration is something you do with systems leading to an achievement – getting them to exchange data. Interoperability is a property of the systems that makes it easy (or easier) to do integration. I’ve heard several other HL7 leaders offer similar definitions as well.

Note that by this definition, HL7 is about interoperability, not integration – HL7 offers standards that applications can adopt to make integration easier, where as IHE is about “integration” (it’s in their name) – they define actual exchanges (at least, that’s the theory).

 

 

Data types and irrelevant features

There’s been quite a bit of criticism of the ISO 21090 data types because they include features that aren’t relevant in every case where they are used, and it’s annoying to have to deal with the features when they don’t apply to the use case at hand. See here for an example, or the comments here, and there was more less-informed criticism of this at the CIMI meeting yesterday.

The trouble with this criticism is that it doesn’t make sense in principle.

The data types are nothing more than basic re-usable patterns that occur throughout healthcare. The whole point of defining a re-usable type is that you choose a set of features that commonly re-occur, and have some inherent behavioral complexity. Then you define a model that represents these things and use it everywhere else. The cost of using the more complex re-usable type is saved many times over by the fact that you get to re-use it nearly for free every where.

So it follows that there’s going to be trade-off between the cost of using the type, and the amount of times you can re-use it – as the features on the type grow, it becomes more useful. So the fact that a type carries features that aren’t used in *all* cases is evidence that it’s worth spending more time getting it right.If you only defined types that perfectly fit their re-use context, then you hardly get any reuse at all – and people have said this to me (“Death to datatypes.  Stick to UML primitives” to quote someone from yesterday).

Data types that include features that aren’t applicable everywhere are a good thing to have.

Of course, you can take it to far, and create a monster that no longer is in a sweet spot because there’s just too much in it. So the question isn’t “why do data types have this extra stuff that I don’t need in my context?”, but “How do you judge the sweet spot when trading between useability and re-use”. We actually have some consensus on that across the various frameworks (hl7 v2, 13606, openEHR, v3/CDA, etc), but some people seem to think that this is part of the problem, not the solution, and want to revisit the whole question.

p.s. Tom’s FOPP principle, which I referenced above, is actually trying to answer my right question (what’s the sweet spot?), but I couldn’t find good examples of the less-informed thinking to link to.