A core piece of this model is a class that right now I've called Concept‹T›, which is a parameterized class. Concept‹T› is abstract and has one defined method: Boolean contains(T object). This method returns true if the object implies the concept, or if the set of all instances of the concept can be said to contain the object.
So the very core becomes:
class SimpleMedicalRecord {
List‹ClinicalStatement› statements;
Person subject;
VMRImplementation implementation;
};
class Concept‹T› {
Boolean contains(T object);
};
class List‹T› {
int count;
T item(int index);
List‹T› extract(Concept‹T› concept);
};
class ClinicalStatement {
II id;
Code code;
List‹ClinicalStatement› has(Concept s);
MedicalRecord owner;
Person subject;
};
The Concept class is a critical abstraction in the VMR model. As you may recall, the purpose of the VMR model is to provide a representation of the clinical information used to reason with in Clinical Decision Support. A lot of clinical decision support can be boiled down to a pattern/action paradigm "if pattern X then action Y". The idea of patterns is that these are classifiers which identify items matching a set of rules. Look at the definition of Concept above. It has one method, which basically allows you to ask the question: Does X match the pattern embodied by this Concept?
The Concept‹T› class makes it possible to talk about and use a particular concept (e.g., Problem, Medication, Allergy, Immunization) without ever having to define what it is or how it is implemented. The VMR can operate regardless of how Concept‹T› is defined. It also makes it possible to extract from any clinical statement other clinical statements in a certain relationship to the original (e.g., Manifestations and Causes, Treatments and Reasons). But, it completely hides the mechanism by which these are implemented.
Take for example, problems. In past discussions of the VMR model, it has been clear that there needs to be a way to represent the list of problems for the patient. It's clear that the problems are themselves a type of clinical statement. What isn't clear is how the VMR makes the distinction between, let's say, a problem and more specifically an allergy; or between a medication and an immunization. The point of using Concept‹T› in the model is that it doesn't matter. Assuming you have the Concept named PROBLEM that is a feature of the VMRImplementation, you can always find anything that is a PROBLEM.
So, we can now define a method for MedicalRecord by which problems are returned (other methods might be more efficient, but this is one that is guaranteed to work).
Class MedicalRecord extends SimpleMedicalRecord {
List‹Problem› problems() {
return this.statements.extract(this.implementation.PROBLEMS);
}
};
We can also defined an algorithm that would support the List‹T› extract(Concept‹T›) operation on the List class. It simply creates a new list, iterates over the members of the original list, and if one of those members is contained within the concept, it is added to the new list, which is returned at the end of the iteration. In code it looks something like this:
List‹T› extract(Concept‹T› concept) {
List newList = new List‹T›();
for (int i = 0; i < this.count; i ++) if ( concept.contains(this.item(i)) ) newList.add(this.item(i)); return newList; }
These definitions are easy to implement and describe, even if they aren't the most efficient or best implementations. It makes it quite easy to create a functional test to verify that a VMR implementation is correct.
There are a number of benefits to Concept‹T› in the VMR. You can have a particular concept like "Blood Pressure" be defined as a set of clinical statements where one and only one of them contains a systolic measure, and one and only one other contains a dyastolic measure, and both are in pressure units. This is a detailed clinical model:
Class DetailedClinicalModel extends Concept‹ClinicalStatement› {
... properties and methods associated with a DCM ...
};
Another case could make use of value sets and clinical terminology services, as in the following rough-and-ready example:
Class CodedConcept‹CodedObject› extends Concept‹CodedObject› {
II valueSetId;
Boolean contains(CodedObject test) {
return CTS.getValueSet(valueSetId).contains(test.getCode());
}
};
The above implementation could instantiate a CodedConcept using a value set for all possible LOINC codes representing an HGA1C measure.
You can mix and match different types of Concepts and build larger concepts out of smaller ones. A Concept could represent "one of the last 3 Creatine Measures in the last six months". Using it, you could extract the measures that you wanted as follows:
measures = VMR.statements.extract(LAST3CREATINEMEASURESINLASTSIXMONTHS);
Some have pointed out that GELLO has a way to represent that. Indeed, and you could do the following:
Class GelloDefinedConcept extends Concept‹T› {
String GelloExpression;
Boolean contains(CodedObject test) {
return GelloEvaluator.evaluate(GelloExpression, this);
}
}
We talked on the call about the concept of persons having diabetes. This points out that while we've been discussing Concept‹ClinicalStatement› we can also have Concept‹Entity› or Concept‹Person›. The concept of persons with diabetes could be defined as Person where medical record contains diagnosis of diabetes in last 2 years, or use of injected insulin for more than three months or 3 HGCA1 measures > 7 in a 1 year period. The larger concept of Patient with Diabetes can be built on smaller concepts: HGAC1 Measures, Injected Insulin, and Diabetes Diagnosis.
The point is, the VMR DOESN'T care how concepts are implemented, and is in fact, unclear on the concept of Concept.
No comments:
Post a Comment