Mapping OpenMRS Order Frequencies FHIR

Yet another question about mapping medications and medication requests between OpenMRS and FHIR.

Currently, OpenMRS has a Order Frequency table that can be populated by individual implementations, but can have rows that looks like this:

| name                   | frequency_per_day   |
| OD (once daily)        |                   1 |
| BID (twice daily)      |                   2 |
| TID (thrice daily)     |                   3 |
| Q2H (every 2 hours)    |                  12 |
| Q4H (every 4 hours)    |                   6 |
| Q6H (every 6 hours)    |                   4 |
| Q12H (every 12 hours)  |                   2 |
| STAT (immediately)     |                NULL |

Currently, the FHIR API maps this to the appropriate FHIR as follows:

frequency: (frequency_per_day) period : 1 periodUnit: days

So, currently for instance, “twice daily” and “every 12 hours” would both be mapped to

frequency: 2 period: 1 periodUnit: days

While in the proper FHIR module the, “every 12 hours” would be recorded like this:

frequency: 1 period: 12 periodUnit: hours

A couple thoughts, questions:

  • Seems like long-term (or even mid or short-term?) we should expand the order frequency table to more closely match the FHIR module and allow us to distinguish between the different levels of granularity

  • In the short-term, would it make sense, when frequency > 1 to attempt to map to a period of hours?


if (frequency > 1 and 24 % frequency == 0) then
frequency = 1
period = 24 / frequency
periodUnits = hours

Thoughts @ibacher @mseaton @burke ?

Take care, Mark

+1. My opinion is that we should:

  • Modify the core order_frequency table/object to support the proper modeling
  • In the FHIR module, when running against the existing model, do what you suggest and at least try to convert to hours where possible.

FYI, technically twice daily and q12h are not the same thing. Clinically, q 12 hours is literally every 12 hours. Twice a day is typically less specific and can be two times during waking hours (breakfast and dinner, for example) which would not be exactly 12 hours. Therefore the documentation should be twice daily for one and once every 12 hours for the other.

It would be nicer if we had a defined concept set for this we could use for both the OpenMRS side and the FHIR side, ideally supporting something like this value set, that way we can unambiguously state things like BID and Q12H.

@mogoodrich As a short-term solution I think your proposal is fine, but it should look like this:

if frequency == 1:
   period = 1
   periodUnits = days
   period = 24 / frequency
   periodUnit = hours


@akanter @mseaton @ibacher agree that we should work in the short-to-mid term on expanding OpenMRS so that we distinguish between twice daily and every 12 hours, but also in the very short-term we translate both into “every 12 hours”. (Right now we translate both into “Twice day”… it seems “more dangerous” to translate “every 12 hours” into “twice a day” that “twice a day” into “every 12 hours”)

And, ack, thanks for catching the typo @ibacher , period units should be hours. And you are correct about frequent == 1, I hadn’t listed that part about my sudo code.

I also reconsidered my approach to not translating into hours if the frequency doesn’t divide properly into 24 hours and I like your example where we divide in all cases except where frequency = 1… this is because it looks like frequency must be an int, but it looks like period does not.

Take care, Mark

I started looking into implementing this today and wanted to circle back here with some questions. I’m not totally sure this approach will work out.

The main issue to address is whether or not we intend or need to do bidirectional mapping between the OpenMRS data model and FHIR. From what I can tell, what we currently support in the FHIR2 module is relatively limited, and many resources (eg. Dosage) is only currently mapped from OpenMRS → FHIR, not the other way around. Looking at the MedicationRequestTranslatorImpl, one can see that there are several properties (most notably Dosage Instructions) that are mapped out from OpenMRS → FHIR but not from FHIR → OpenMRS.

Assuming we need and want this bi-directional mapping, we really need to properly map between elements of the FHIR Dosage Timing (assuming this is the right element) and the OrderFrequency (as well as some other properties).

There is no way of knowing from the FHIR resources exactly which Order Frequency they map to, as several OrderFrequencies will be configured with the same “frequency_per_day” data.

Perhaps the most straightforward thing would be to add an orderFrequency extension to MedicationRequest, which can map to a Concept, preferably by SNOMED-CT mapping. This would allow us to exactly represent our OpenMRS data using FHIR. We could also add the frequency_per_day in addition to this, if useful for consumption by the frontend application, but this would not be the means to uniquely try to understand what this frequency represents.

@ibacher / @mogoodrich / @burke / @akanter thoughts?

I agree with leaning toward this FHIR value set, adding additional values as needed and using free text ordering when the desired frequency is not available.

“Frequency per day” can be a useful attribute of a frequency concept to use for calculations, but we’re never going to be able to go the other direction (i.e., you can’t represent the range and nuance of frequencies in a frequency_per_day field):

  • “12” is the correct frequency per day value for both “twice daily”, “every 12 hours”, “before breakfast and dinner”, “after breakfast and lunch”, … but those are not identical frequencies (as @akanter pointed out)
  • “0.5” would be a valid value frequency_per_day for “every other day” or “every Monday, Wednesday, and Friday” or “every Tuesday, Thursday, and Saturday”

So, I would abandon trying to devise a frequency from frequency_per_day other than as a temporary hack. Ideally, we’d have a concept set of order frequencies. Each frequency would be a concept, allowing us to leverage localization, preferred names to auto-convert to the safest versions (“twice daily” instead of “BID”), synonyms (let somebody enter “BID” and we convert it to “twice daily”), create UCUM mappings for FHIR use to-from FHIR, and use a concept attribute for “frequency_per_day” that, when defined, could be used to perform calculations.

That should probably be “Once” (a “frequency” meaning do this one time) and not “STAT”, which is an urgency, not a frequency. Any order with any frequency could be assigned the urgency of “STAT” to indicate the first instance should be done immediately.

1 Like

Ideally, we do want to support bi-directional mappings, though with MedicationRequest, it was not a priority largely because, IIUC, OpenMRS requires orders to have an OrderContext to be created and it wasn’t clear to me how we could derive that from the FHIR data. Hence, most of the medication stuff is currently just mapped from OpenMRS → FHIR. Basically, there’s little point in providing a bidirectional mapping on a resource if we can’t save the resulting OpenMRS object. (MedicationDispense changes the calculus somewhat and gives us a reason to support mapping FHIR → OpenMRS for the Dosage construct).

I agree with Burke’s suggestion that we’d ideally map this to a concept of some kind.

Thanks @burke for the helpful response.

We already have all this. This is what the current OpenMRS model represents, with an “order_frequency” table that maps a frequency Concept to a numeric frequency_per_day.

So the question is - if the right way to model this in FHIR is as a frequency concept - where in the FHIR model should this happen? @ibacher ?

Can we just populate Timing.code for this and not try to populate the Timing.repeat ?

In FHIR, it would go in Timing.code and we’d dispense with trying to fill in the other parts of the timing :grin:,

Thanks @mseaton for digging a lot deeper into this.

I haven’t reviewed the PR yet, but this sounds correct to me, and I like the idea of switching to just using a code… as @ibacher suggests, we will need bidirectional mappings once we start creating dispensing events via the Dispensing O3 app.

Take care, Mark

Would this be the direction to go for the order_frequency table?

concept Concept FHIR module would preferentially look for concept’s UCUM mapping
frequency_per_day double keep as deprecated column for backwards compatibility
frequency int Timing.repeat.frequency
period_unit enum Timing.repeat.periodUnit s | min | h | d | wk | mo | a - unit of time (UCUM)

I’d still leave period_unit as a concept, so we can map to CIEL’s DurationUnits set and from there to UCUM.

If we are going to have “period_unit”, don’t we also need to have “period”.


  • Four times daily = Frequency 4, Period 1, Period Unit = Day
  • Every 6 hours = Frequency 1, Period 6, Period Unit = Hour