Concept Ranges for different factors

Introduction

In order to make concepts ranges effective, it is crucial to implement factor-based reference ranges for key metrics like vital signs and laboratory results. For instance, if we consider a factor like age; patients of any age, from newborns to centenarians, may require care, and the normal versus abnormal ranges for this factor may vary significantly based on age.

Another example is blood pressure, which has distinct ranges depending on the age of the patient. A range that is normal for an adult could be life-threatening for a newborn. The following are details of blood glucose and blood pressure ranges:

  • Fasting Blood Glucose Ranges:

    • Infants:

      • Normal: 40-90 mg/dL

      • Critical: < 40 mg/dL or > 300 mg/dL

    • Patients > 2 years:

      • Normal: 70-110 mg/dL

      • Critical: < 54 mg/dL or > 400 mg/dL

  • Blood Pressure Ranges:

    • Newborn: 80/40 mmHg

    • 1-3 years: 94/64 mmHg

    • 10 years: 110/58 mmHg

    • Adult: 120/80 mmHg

In addition to age, other factors can influence what is considered a "normal" range for a given patient. These factors include:

  • sex/gender

  • ethnicity

  • renal function

  • pregnancy status

  • weight/BMI

  • time of day

OpenMRS Platform version

2.7.0

Absolute values

When evaluating with concept reference ranges, only absolute values are used. i.e. absolute low and absolute high values are the ones used for validation. The rest such as critical high/low, etc are only used for flagging values displayed in the user interface.


Creating Criteria Expressions

The criteria can be based on one or many factor combinations of the following :

  • Age (in years, months, weeks, or days)

  • Gender

  • Time of day

  • Observation boolean/text/numeric/coded values

The criteria enable precise and tailored validation of patient data, ensuring that the appropriate reference ranges are applied for each unique case.

Relational operations (used in criteria expressions)

  • < : Less than

  • > : Greater than

  • <= : Less than or equal to

  • >= : Greater than or equal to

  • == : Equal to

  • != : Not equal to

  • && : Logical AND. This operator returns true if both of the conditions or expressions it combines are true. If either condition is false, the overall result is false.

  • || : Logical OR. This operator returns true if at least one of the conditions or expressions it combines is true. If both conditions are false, the overall result is false.

Examples of Criteria Expressions

  1. Age:

    1. $patient.getAge() > 5 checks if the patient is older than 5 years.

    2. $patient.getAgeInMonths() < 3 checks if the patient is less than 3 months.

    3. $patient.getAgeInWeeks() < 12 checks if the patient is less than 12 weeks.

    4. $patient.getAgeInDays() < 10 checks if the patient is less than 10 days.

    5. $patient.getAge() > 18 && $patient.getAge() < 70 checks if the patient is between the age of 18 and 70 years.

  2. Gender:

    1. $patient.getGender().equals("M") checks if the patient is male.

    2. $patient.getGender().equals("M") || $patient.getGender().equals("F") checks if the patient is male OR female.

  3. Age & Gender:

    1. $patient.getGender().equals("F") && $patient.getAge() > 18 checks if the patient is a female older than 18 years.

    2. $patient.getGender().equals("M") || $patient.getAge() > 20 checks if the patient is either a male or is older than 20 years.

  4. Observation Value:

    1. $fn.getLatestObs("CIEL:1234").getValueText().equals("PREGNANT") checks if the patient has a recent observation indicating pregnancy.

    2. $fn.getLatestObs("2a86e48c-76ef-479f-815f-d7c1701e8fb7").getValueBoolean() == true checks if the patient
      Note:

      1. CIEL:1234 used in example a) is concept mapping while 2a86e48c-76ef-479f-815f-d7c1701e8fb7 used in example b) is concept’s uuid.

      2. The method called after getLatestObs() expression depends on the data type of the concept passed in the parameter. For instance in example a) above, the concepts data type is text while in example b) the data type is boolean.
        - $fn.getLatestObs("CIEL:1234").getValueNumeric() for value numeric
        - $fn.getLatestObs("CIEL:1234").getValueCoded() for value coded

  5. Time of the day:

    1. $fn.getCurrentHour() == 14 checks if the (current) time of the the day at the time of creating the Observation is the specified time in the criteria. In our example, the expression checks if the time of the day is 2pm. Note that getCurrentHour() returns the hour of the day in 24hr format.

  6. Person Attributes:
    Note that you person attributes need to be set. Therefore make sure that person attributes are set for the attribute expressions to work. Find more on how to manage person attributes here.

    1. $patient.getAttribute("Ethnicity").getValue() == "Maasai" check if there is the person is of Maasai ethnicity. The ‘Maasai’ in this example is the attribute value while the ‘Ethnicity’ is attribute type.

  7. Complex Criteria reference:

    1. ($patient.getGender().equals("F") && $patient.getAge() > 18) || ($patient.getGender().equals("M") && $patient.getAge() < 18) checks the patient is either a female older than 18 years or a male who is less than 18 years of age.

    2. $patient.getAge() >= 1 && $patient.getAge() <= 3 evaluates to true if the patient is one, two or 3 years old.

    3. You can come up with criteria expressions using the values of the current Obs. For example:-

      1. BMI - criteria expression would require the use of formula. If person’s weight and height are in kg and cm, then the formula would be weight/ ((1/100 x height) power 2) or weight/ ((1/100 x height) x (1/100 x height)). Here is an example of an expression that will return true if BMI is greater than 25.
        "($fn.getCurrentObs("c607c80f-1ea9-4da3-bb88-6276ce8868dd", $obs).getValueNumeric() / (($fn.getCurrentObs("a09ab2c5-878e-4905-b25d-5784167d0216", $obs).getValueNumeric() / 100) * ($fn.getCurrentObs("a09ab2c5-878e-4905-b25d-5784167d0216", $obs).getValueNumeric() / 100))) > 25"

        Note: c607c80f-1ea9-4da3-bb88-6276ce8868dd is the uuid(conceptRef) for weight concept and a09ab2c5-878e-4905-b25d-5784167d0216 is the uuid(conceptRef) for height concept.


Strict Ranges

In the case where multiple concept reference ranges are evaluated to true, then we use the strictest range.

For example:-

  • ConceptReferenceRange1 has absolute ranges of 60-140 and criteria $patient.getAge() > 5

  • ConceptReferenceRange2 has absolute ranges of 80-150 and criteria $patient.getAge() > 3

    -> Assuming the patient is 10 years old, then the criteria will evaluate to true for both reference ranges. Therefore, the highest lower bound and lowest higher bound is picked. Hence, ObsReferenceRange will be saved with ranges 80-140.


Current & Latest Obs Functions

getCurrentObs()

getCurrentObs(String conceptRef, Obs currentObs)

This function returns the most relevant observation (Obs) based on the provided concept reference (conceptRef) and the current observation (currentObs). If the currentObs has a valid value—such as coded, numeric, date, or text and the concept in the currentObs matches the supplied concept reference, it returns the currentObs. Otherwise, it fetches the most recent Obs that matches the supplied concept reference and the patient associated with the currentObs.

Key Points:

  • Current Obs Check: If currentObs has a valid value and its concept matches the provided conceptRef, the method directly returns this currentObs.

  • Fallback to Latest Obs: If the currentObs does not have a valid value or the concept does not match, the method retrieves the latest Obs for the provided conceptRef and patient.

For a practical example, refer to the criteria expressions for calculating BMI above.

getLatestObs()

This function returns the most recent obs, for the patient in subject & the provided concept, that was saved.

getLatestObs(String conceptRef, Person person)

This function retrieves the latest observation for a specified concept reference (conceptRef) and person (person). The conceptRef can be a concept UUID or a concept map's code and source name (e.g., "CIEL:1434"). The method returns the most recently saved Obs matching the provided criteria.

Key Points:

  • Concept Reference: The method accepts a concept UUID or a concept map's code and source name to identify the relevant concept.

  • Person: The latest Obs is retrieved for the current person/patient.

Example:

You can use getLatestObs to fetch the most recent weight observation like this:

$fn.getLatestObs('c607c80f-1ea9-4da3-bb88-6276ce8868dd', $patient).getValueNumeric()

This retrieves the most recent weight observation for the current patient.

 

For more examples, refer to the criteria expressions mentioned above.


Concept Numeric Ranges

If concept numeric ranges are still present (e.g., for legacy or historical reasons), the system will prioritize evaluating the concept reference ranges first before validating against the concept numeric ranges. This approach is adopted because concept reference ranges provide stricter validation criteria, ensuring that observations are assessed against the most precise and relevant standards first.

 


Why save new Obs Reference Ranges?

Saving new observation reference ranges is crucial for maintaining the integrity and relevance of historical data. By storing these ranges, clinicians can easily review the specific criteria used during each patient encounter. For example, if a patient receives prenatal care and later returns for postnatal care, the practitioner can quickly identify which reference ranges were applied during the pregnancy. This historical context enhances clinical decision-making by providing insights into the factors considered during past evaluations.

Another example might involve a pediatric patient whose reference range for a particular vital sign was set based on their age at the time of the encounter. As the patient grows older, the will change, rendering the criteria no longer evaluating to true. By saving the Obs reference ranges, it is possible to track these ranges and ensure that the patient’s historical data is accurately interpreted.

This approach also brings us closer to alignment with FHIR (Fast Healthcare Interoperability Resources), which already supports the inclusion of reference ranges in clinical observations.

 


Conclusion

The implementation of factor-based reference ranges in OpenMRS is a critical enhancement that ensures the applicability of ranges across various patient factors. By leveraging a flexible architecture that incorporates dynamic criteria expressions, OpenMRS can now provide accurate and relevant reference ranges for vital signs and lab results based on patient-specific factors.

 


Link to technical documentation

Concept Ranges For Different Factors - Technical