Monday, July 11, 2011

Smells like I dunno...

One of the persistent questions in HL7 Structured Documents on the CDA Consolidation guide is how to say I don't know.  HL7 has flavors of NULL, and in IHE I jokingly discussed "Colors" of None (it became a section on "Distinctions of None" in the PCC TF).  Well, for this, I think we have to work with smells of unknown because the current situation stinks.

The challenge here is the distinction between Boolean logic which you learn in high school, and three-valued logic which geeks like me might have learned in college, or encountered in their first more than simple SQL query.

For medications and problems, IHE solved the challenge of unknown for medications and problems using SNOMED CT.  IHE suggested the use of "Drug Treatment Unknown" from SNOMED CT in the substanceAdministration code element for medications.  For problems it suggested that the observation value element use "Past Medical History Unknown" from SNOMED CT.  But for allergies there is no such code.  The CDA Consolidation project decided that the codes were part of the problem and that this should be manageable using the RIM.

The CDA Consolidation project has now embarked upon looking for a consistent solution using the HL7 RIM.  Ideally such a solution would also be consistent with positive and negative assertions around problems, allergies and medications.

negationInd
All acts in HL7 Version 3 had at one time a "negation indicator" which could negate the act.  So, you could readily say:  I did this or I did not do that.  This has since been subdivided because some acts (the all pervasive Observation) have both an act and a value, and sometimes you want to say that the observation wasn't performed, and other times you want to say that the value wasn't observed.  So now there is an "Action negation indicator" and a value negation indicator.  For CDA, we are still using the original negation indicator until Release 3 when we absorb the new RIM and Data Types.

The Negation Indicator (and its replacements) are indicated to be of the BL type, which supports true, false and NULL.  However, in XML representations where the BL type is used and appears as an attribute, it can ONLY have the values true or false.  So they really aren't of the BL type, rather they are of the BN (Boolean Non-NULL) type in what they can represent.  So even though BL supports three-valued reasoning with unknowns, it doesn't for structural attributes like negationInd.

I'm not sure whether that restriction was intentional (it seems to have been).  It does mean that there are things you can say in the RIM that you cannot say in an XML representation.  In the RIM you can say "I don't know whether this action occurred or did not".  But it cannot be implemented using the XML Implementation Technology specification (ITS) because that specification restricts negationInd to be only true or false and doesn't allow NULL values.  One could argue that the presence of the nullFlavor attribute on the RIM classes in the XML ITS addresses this issue, but it fails to provide a complete representation. In the RIM, you can say, I don't know if the patient received any medication between January 1 and January 12th of 2011, or you can say, I don't know if they received blood thinners between those dates, or at just about any level of detail (just like you can with negation).  I'm not clear on the way nullFlavor works on classes, but it would seem to restrict use of attributes on the class, so you cannot be "broadly uncertain" on the class.

Because the XML ITS doesn't support a nullFlavor on negationInd, CDA doesn't support it either.  So an alternate representation is needed.

uncertaintyCode
There is an alternative supported by all Act classes in the RIM to represent degrees of uncertainty.  Alas that code system only allows for statements of normal, and uncertain statements, and doesn't really get into any real quantification of uncertainty (perfect uncertainty = a true unknown).  But CDA didn't use it (probably because it didn't have much utility as specified), so that isn't even a choice, even if it had a better code system.

extensions
Extensions are right out because the rule about extensions is this:  
These extensions should not change the meaning of any of the standard data items, and receiving applications must be able to safely ignore these elements.
And adding an extension to say that X should be interpreted as being unknown would change the meaning of X, and that it couldn't safely be ignored.

Developing an Alternative
So, lets look at various kinds of I dunno...
  1. It isn't known whether the patient has any diseases.
  2. Patient is known to have a disease, but the identity of the disease is unknown.
  3. It isn't known whether the patient has (or has had) _____. (e.g., Chicken pox).
  4. It's not known whether the patient has any allergies.
  5. Patient is known to have an allergy, but the identity of the allergen is unknown.
  6. It's not known whether the patient is allergic to ____.
  7. It isn't known whether or not the patient is taking any medications.
  8. The patient is known to be on a medication, but that medication is not known.
  9. It isn't known whether a patient has taken medication _____.
There is a pattern here.
  1. I know that a disease/allergy/medication exists, but I don't know what it is.
  2. I don't know whether a specified disease/allergy/medication exists.
  3. I know nothing about diseases/allergies/medications.
Pattern #1
This is relatively easy to represent in CDA using codes.  You need to be able to indicate the type of observation produced an unknown result for problems and allergies.  For meds, that really isn't necessary because the classCode for substanceAdministration tells you that you are dealing with the administration of a substance, and the manufacturedLabledDrug indicates you are talking about a drug.

An unknown Problem
<entry>
  <observation classCode="OBS" moodCode="EVN">
    <code code="64572001" displayName="Disease" 
      codeSystem="2.16.840.1.113883.6.1"/>
    <value xsi:type="CD" nullFlavor="ASKU"/>
  </observation>
</entry>

An unknown Medication
<entry>
  <substanceAdministration moodCode="EVN" classCode="SBADM">
    <consumable>
        <manufacturedProduct>
          <manufacturedLabeledDrug>
            <code nullFlavor="ASKU"/>
          </manufacturedLabeledDrug>
        </manufacturedProduct>
      </consumable>
    </substanceAdministration>
</entry>

An unknown Allergy
<entry>
  <observation classCode="OBS" moodCode="EVN">
    <code code="106190000" displayName="Allergy" 
      codeSystem="2.16.840.1.113883.6.1"/>
    <value xsi:type="CD" nullFlavor="ASKU"/>
    <participant typeCode='CSM'>
      <participantRole classCode='MANU'>
        <playingEntity classCode='MMAT'>
          <code nullFlavor="ASKU"/>
        </playingEntity>
      </participantRole>
    </participant>
  </observation>
</entry>

Pattern #2
This is much more difficult. We want to be able to say that the "status" of the observation is unknown.  This is similar to saying it was negated.  There is a nullFlavor attribute that can be used with the observation.

A Specific Problem is unknown
<entry>
  <observation classCode="OBS" moodCode="EVN" nullFlavor="ASKU">
    <code code="64572001" displayName="Disease" 
      codeSystem="2.16.840.1.113883.6.96"/>
    <value xsi:type="CD" code="38341003" displayName="Hypertensive Disorder" 
codeSystem="2.16.840.1.113883.6.96" codeSystemName="SNOMED CT"/>
</observation>
</entry>

A Specified Medication is Unknown
<entry>
  <substanceAdministration moodCode="EVN" classCode="SBADM" nullFlavor="ASKU">
<consumable>
<manufacturedProduct>
        <manufacturedLabeledDrug>
          <code code="81839001" displayName="anticoagulant drug"
codeSystem="2.16.840.1.113883.6.96" codeSystemName="SNOMED CT"/>
</manufacturedLabeledDrug>
      </manufacturedProduct>
    </consumable>
  </substanceAdministration>
</entry>

A specified Allergy is Unknown
<entry>
  <observation classCode="OBS" moodCode="EVN" nullFlavor="ASKU">
    <code code="106190000" displayName="Allergy" 
       codeSystem="2.16.840.1.113883.6.1"/>
    <value xsi:type="CD" code="300916003" displayName="Latex Allergy"
codeSystem="2.16.840.1.113883.6.96" codeSystemName="SNOMED CT"/>
    <participant typeCode='CSM'>
      <participantRole classCode='MANU'>
        <playingEntity classCode='MMAT'>
          <code code="111088007" displayName="latex"
codeSystem="2.16.840.1.113883.6.96" codeSystemName="SNOMED CT"/>
</playingEntity> </participantRole> </participant> </observation> 
</entry>

Pattern #3
Now that we've solved pattern #2, this one is easy.  We just make the disease, allergen or medication very general to say that we don't know about diseases, medications, or allergies/allergens.

Nothing is known about Problems
<entry>
  <observation classCode="OBS" moodCode="EVN" nullFlavor="ASKU">
    <code code="64572001" displayName="Disease" 
      codeSystem="2.16.840.1.113883.6.96"/>
    <value xsi:type="CD" code='64572001' displayName='Disease'
      codeSystem='2.16.840.1.113883.6.96' codeSystemName='SNOMED CT'/>
</observation>
</entry>

Nothing is known about Medications
<entry>
  <substanceAdministration moodCode="EVN" classCode="SBADM" nullFlavor="ASKU">
<consumable>
       <manufacturedProduct>
         <manufacturedLabeledDrug>
           <code code='410942007' displayName='Drug or Medicament' 
codeSystem='2.16.840.1.113883.6.96' codeSystemName='SNOMED CT'/>
</manufacturedLabeledDrug>
       </manufacturedProduct>
     </consumable>
  </substanceAdministration>
</entry>

Nothing is Known about Allergies
<entry>
  <observation classCode="OBS" moodCode="EVN" nullFlavor="ASKU">
    <code code="106190000" displayName="Allergy" 
      codeSystem="2.16.840.1.113883.6.1"/>
    <value xsi:type="CD" nullFlavor="NA"/>
    <participant typeCode='CSM'>
      <participantRole classCode='MANU'>
        <playingEntity classCode='MMAT'>
          <code code='413477004' displayName='Allergen or Pseudoallergen' 
codeSystem='2.16.840.1.113883.6.96' codeSystemName='SNOMED CT'/>
        </playingEntity>
      </participantRole>
    </participant>
  </observation> 
</entry> 

Now we appear to have solved this problem.  The trick was recognizing that the nullFlavor attribute on the class was essentially where the missing nulls for negationInd disappeared to.  It appears that I managed to sniff out a solution ;-)  ... and it doesn't stink.  In fact, it works pretty consistently across all classes.  I could easily see how to extend it to say that it is unknown whether a patient had a particular procedure or encounter, or even family history of any particular disease.

  -- Keith

P.S.  All the XML Validates against the CDA Schema


This post was updated on July 18th to reflect adjustments made by the HL7 Structured Documents Workgroup based on feedback from Grahame Grieve. The key change was in using a general code rather than unknown for pattern 3.  A similar change was made for How to say No...

14 comments:

  1. negationInd didn't allow null flavors because it was erroneously believed to be structural. I.e. You couldn't possibly have an object instance where it wasn't known. We corrected this issue at the same time we split negationInd into valueNegationInd and actionNegationInd. Unfortunately, this doesn't much help CDA which uses a version of the RIM that doesn't have access to the new attributes.

    A few other comments:
    - Not sure about having a CSM participation on an allergy observation. That would mean the subject consumed the substance as part of the observation, which is true for allergy testing, but not for other allergy assessments. Usually we just use Observation.value whether dealing with Allergy tests or other allergy assertions.

    No issues otherwise, though I think using null flavor on actionNegationInd is better than having it on the base act is cleaner for models where it's available. They type of action is completely known. It's merely whether it occurred or didn't occur that's unknown.

    ReplyDelete
  2. Several comments:

    - attributes that are booleans can't have a nullFlavor, but they can still be null - simply by being missing. That isn't what you say

    - classes that have nullFlavors - I'll take that up on my blog and explain.

    - you don't describe the case "the patient has no known allergies". This is different to your cases #2 and #3, though it can be hard to know how different

    ReplyDelete
  3. Agree that Cases 1-3 above do not include the Use Case where a patient has actually asserted that they are unaware that they have any allergies...this is probably covered by SNOMED-CT 160244002 No known allergies

    ReplyDelete
  4. Anonymous: "No known X" is covered in today's post on how to say no.

    Also, see this stream for more comments on THIS post.

    ReplyDelete
  5. Hi Keith, as a clinician, while I might want to say some of those things it would be quite rare. It's much more likely that I want to record the following things unambiguously.

    I have asked this patient if they are on any medications and they said that they aren't i.e. This patient is on no medications.
    I have asked this patient if they have any allergies and they said no. i.e. This patient has no allergies.
    I asked this patient if they had any previous diseases/problems/procedures and they said no i.e. This person has no significant past history.

    I also want to make positive statements about NOT having particular conditions. i.e. this patient has no history of ischaemic heart disease, or no history of diabetes, or no Family history of diabetes etc.

    These are the important clinical statements the we need to make and the thing about them is that they are actually POSITIVE clinical statements - using flavours of null and negation indicators is only useful if we can unambiguously always know what the clinician was trying to say.

    Terminology may help here, but as always terminology is useless without proper information models

    ReplyDelete
  6. Keith, even though this is a year after the post, I just came back to this today (July 30, 2012) because I noticed that Consolidated CDA doesn't include an example of Pattern #3, "Nothing is known about allergies" for example. So rediscovering your post with its examples was very helpful. Thanks!
    David

    ReplyDelete
  7. Hi Keith,

    Great article ... very informative and succinct..

    Rashid A. Khan

    ReplyDelete
  8. In pattern #2 above why is allowed?

    The HL7 Implementation Guide for CDA® Release 2:
    IHE Health Story Consolidation, DSTU Release 1.1
    (US Realm)
    Draft Standard for Trial Use
    July 2012

    states (pdf bottom page 40): Any SHALL conformance statement may use nullFlavor, unless the attribute is
    required or the nullFlavor is explicitly disallowed. SHOULD and MAY
    conformance statement may also use nullFlavor.

    Both classCode and moodCode are required attributes.

    Thanks

    ReplyDelete
  9. Pattern #2 is necessary when you want to say something about the fact that you tried to ascertain the allergy status, and that the answer you got was "I don't know". This could be relevant when asking whether a patient is allergic to latex for example. The patient (or their representative) might simply not know. In that particular case, you might want to take precautions in caring for the patient until you are able to determine a better answer to the question.

    ReplyDelete
    Replies
    1. Not my question. My question is, why is pattern #2 allowed when the spec says otherwise?

      Delete
    2. Furthermore, what is the meaning of the statement in the HL& spec:

      "Any SHALL conformance statement may use nullFlavor, unless the attribute is
      required or the nullFlavor is explicitly disallowed. SHOULD and MAY
      conformance statement may also use nullFlavor."

      Should this read:

      "Any element with a SHALL conformance statement may use nullFlavor unless it has a attribute with a SHALL conformance statement or the nullFlavor is explicitly disallowed by another constraint. Elements with SHOULD and MAY
      conformance statement may use nullFlavor in the same way as above."

      Delete
    3. Apparently I missed in Problem Observation

      10. SHALL contain exactly one [1..1] value with @xsi:type="CD", where the @code
      SHOULD be selected from ValueSet Problem
      2.16.840.1.113883.3.88.12.3221.7.4 DYNAMIC (CONF:9058).
      a. This value MAY contain zero or one [0..1] @nullFlavor
      (CONF:10141).
      i. If the diagnosis is unknown or the SNOMED code is
      unknown, @nullFlavor SHOULD be “UNK”. If the code is
      something other than SNOMED, @nullFlavor SHOULD be
      “OTH” and the other code SHOULD be placed in the translation
      element (CONF:10142).

      So DSTU should actually read

      Any element with a SHALL conformance statement may use nullFlavor unless it has a attribute with a SHALL conformance statement or the nullFlavor is explicitly disallowed or allowed by another constraint. Elements with SHOULD and MAY
      conformance statement may use nullFlavor in the same way as above.

      Delete