Implementation guide for interoperable medicines

This guidance is under active development by NHS England and content may be added or updated on a regular basis.

Dose to Product Translation

This page is in Experimental status.

Overview

This page describes an important functional requirement for many system implementations using Dose Syntax. Structured Dose Syntax information must be capable of being used to support dose-based and product-based prescribing, and there is a requirement to convert between the two - e.g. to convert a dose-based prescription to an actual product for dispensing within a pharmacy.

Details of the requirements for dosage format conversion are highly use-case dependent and will be addressed as work in specific use-case areas develops.

Background

When a prescriber uses a dose-based instruction (using a VTM), it will always need to be translated into a product-based instruction (using a VMP or AMP) to be supplied or dispensed. Today, this is a highly manual process performed by a clincian. For example;

A hospital pharmacist would translate dose-based orders coming from the ward into a products that is both in-stock and suitable to meet the patients’ needs.

A GP would translate dose-based medication requests within a discharge letter into product-based repeat prescriptions.


Translation Process

Important: The process described here is to create a suitable short list of products to fulfil the medication request

It is not intended to identify a single product. A local implementation may choose to further filter the list of products on factors like local availability (stock), local formulary or cost. The order of products listed may also be locally condfigured to promote or demote products based on licensing status or local needs such as paediatric use.

The translation process requires the use of the NHS Dictionary of Medicines and Devices (dm+d) plus a mapping table for UCUM units of measure that use different terms than dm+d.

For example; gram is a dm+d unit of measure with g is the equivalant within UCUM, and UCUM spells liter differently to the dm+d litre.

Step #1: Get child products (VMPs and AMPs) of the VTM

VMPs flagged within dm+d as invalid or where actual products are not available must be ignored.

Where the VMP has a Prescribing Status of 0004, 0006, 0007, 0008 or 0009 then include the valid and available AMPs. These codes identify VMPs flagged as Never valid to prescribe as a VMP and those flagged in various ways as VMP not recommended to prescribe or Caution - AMP level prescribing advised.

Where the dose-based instruction specifies a coded Route or coded Form then these are used in the query to return only VMPs for the given route and/or form.

If using dm+d data held in a relational database, the pseudo-SQL would be;

return vmp, vmp_prescribing_status
  where parent_vtm = {vtm_id}
    and vmp is valid
      and vmp has actual products available
        and vmp_form = {form_id} (if specified)
          and vmp_route = {route_id}  (if specified)

return amp, vmp, vmp_prescribing_status
  where parent_vtm = {vtm_id}
    and vmp is valid
      and vmp has actual products available
        and vmp has vmp_prescribing_status = 0004 or 0009
          and vmp_form = {form_id} (if specified)
            and vmp_route = {route_id}  (if specified)
              and parent_vmp = vmp

If using the NHS England Terminology Server then a two-step approach is required. First a call to return VMP concepts for the given VTM with optional Form and Route codes. Second, for any VMPs flagged to prescribe with an AMP, those flagged with a PRES_STATCD of 0004 or 0009, make an additional call to return AMPs.

To return VMPs;

curl --location 'https://ontology.nhs.uk/staging/fhir/ValueSet/$expand' \
--header 'Authorization: Bearer } { { OAuthToken } }' \
--header 'Content-Type: application/json' \
--data '{
"resourceType": "Parameters",
"parameter": [
  {
  "name": "valueSet",
    "resource": {
      "resourceType": "ValueSet",
      "compose": {
        "include": [
          {
          "system": "https://dmd.nhs.uk",
          "filter": [
            {
            "property": "parent",
            "op": "=",
            "value": "{vtm_id}"
            },
            {
            "property": "parent",
            "op": "=",
            "value": "VMP"
            },
            {
            "property": "INVALID",
            "op": "exists",
            "value": "false"
            },
            {
            "property": "FORMCD",
            "op": "in",
            "value": "{form1_id},{form2_id}"
            },
            {
            "property": "ROUTECD",
            "op": "=",
            "value": "{route_id}"
            }
          ]
          }
        ],
        "exclude": [
        {
          "system": "https://dmd.nhs.uk",
          "filter": [ 
          {
          "property": "NON_AVAILCD",
          "op": "=",
          "value": "1"
          }
          ]
        }
        ]
      }
    }
  }
]
}'

To return AMPs;

curl --location 'https://ontology.nhs.uk/staging/fhir/ValueSet/$expand' \
--header 'Authorization: Bearer { { OAuthToken } }' \
--header 'Content-Type: application/json' \
--data '{
"resourceType": "Parameters",
"parameter": [
{
  "name": "valueSet",
  "resource": {
    "resourceType": "ValueSet",
    "compose": {
      "include": [
        {
        "system": "https://dmd.nhs.uk",
        "filter": [
          {
          "property": "parent",
          "op": "in",
          "value": "{vpm1_id},{vpm2_id},{vpm3_id}"
          },
          {
          "property": "parent",
          "op": "=",
          "value": "AMP"
          },
          {
          "property": "INVALID",
          "op": "exists",
          "value": "false"
          }
          ]
        }
        ],
        "exclude": [
          {
          "system": "https://dmd.nhs.uk",
          "filter": [
          {
          "property": "AVAIL_RESTRICTCD",
          "op": "in",
          "value": "9"
          }
          ]
          }
        ]
      }
    }
  }
]
}'

Step #2: Calculate the required quantity of each VMP to fulfil the requested dose

Take the dose from the doseAndRate.doseQuantity or doseAndRate.doseRange.low structures. This will be a combination of a quantity and a coded unit of measure. If the unit of measure is using a UCUM unit then the SNOMED code needs to be looked-up from dm+d. This is where the addition mapping table applies.

This calculation at the VMP level will apply to all child AMPs.

Each VMP contains strength information for the active ingredients. It would not be expected to use a dose-based prescription for combination drugs (e.g. anything beginning “co-“) nor any VTM where some associated products contained multiple ingredents (e.g. Phosphate). In such cases translation from dose to products is not possible.

The strength of the ingredient may need to be converted into the same units as the requested dose for comparision purposes. For example, if the requested dose is 1gram but the VMP ingredient is expressed as 500mg then it would need to be converted into 0.5gram to calculate that the VMP is half the required strength. Whilst most dosage instructions would be expressed in terms of strength, the same conversion is required for volume (litre, millitre etc.) and length (metre, centimetre, etc.).

With all units of measure expressed in the same scaler terms, the amount of the VMP to fulfil the requested dose can be calculated as;

QUANTITY OF VMP = ( REQUESTED DOSE QUANTITY / VMP INGREDIENT STRENGTH ) / VMP UNIT DOSE FORM STRENGTH (where defined for the VMP)

Step #3 - Order the list of products in a clinically suitable order

This approach does not include where two or more products of different strengths may be used. For example a dose of 75mg requested and fulfilled by one 50mg product and one 25mg product.

Exclude VMPs flagged as Never valid to prescribe as a VMP.

This guidance suggests ordering by least divisibility.

  1. Whole products that can fulfil the request are listed above products that may have to be divided.

  2. Where the quantity calculated from Step 2 is not divisible by 1, hence the product has to be divided (e.g. 1.5 tablets) then push down the list.

  3. Where the quantity calculated from Step 2 is less than 1 (e.g. 0.5 tablets) then push lower in the list.

  4. In either case, when a product needs to be divided and if the product has a dose form that is not typically divisable then push even lower in the list.

  5. Products containing multiple active ingredents are pushed to the bottom of the list as the translation calculatation is not possible.


Data Requirements

dm+d

The dm+d data fields used for this process are;

VTM VMP VMP-VPI VMP-FORM VMP-ROUTE AMP
VTMID VTMID
VPID VPID VPID VPID VPID
NM NM NM
INVALID INVALID INVALID
PRES_STAT
NON_AVAILCD
UDFS
UDFS_UOMCD
UNIT_DOSE_UOMCD
STRNT_NMRTR_VAL
STRNT_NMRTR_UOMCD
STRNT_DNMTR_VAL
STRNT_DNMTR_UOMCD
FORMCD ROUTECD
AVAIL_RESTRICTCD

Together with the FORM, ROUTE, UNIT_OF_MEASURE and PRESCRIBING_STATUS vocabularies from the dm+d LOOKUP data.

When dm+d data is imported into a relational database, concepts marked as INVALID or VMP concepts flagged as no actual products available may be excluded from the import.

logical-dmd-erd

Mapping between UCUM and SNOMED/dm+d

The following mapping table needs to be available to the implementing system. It is required to identify the units of measure within the UCUM standard that use different different codes to the dm+d.

For example g is a UCUM code for "gram" and the equivalent within dm+d is gram|258682000 so a mapping is required to associate g with the SNOMED code 258682000. This mapping table may need to be extended within a local implementation depending on which UCUM units are to be expected.

SNOMED/dm+d code UCUM unit
258683005 kilogram
258682000 g
258684004 milligram
258686002 ng
258685003 ug
258773002 milliliter
258770004 liter
258770004 l

Detailed Logic for Step 1 - Get relevant child products of the VTM

TO DO. The SQL query needs to be extended to bring in relevant AMPs.

A suitable SQL query to return child VMPs for a VTM, with optional Route or Form constraints would be as follows. This assumes INVALID concepts and VMPs where no actual products are available has been excluded from the database.

SELECT vmp.vmpid AS vmpId
     , vmp.name AS vmpName
     , vmp.udfs_dose_uomcd AS unitDoseFormStrength
     , vpi.strnt_dnmtr_uomcd AS denominator
  FROM vtm
 INNER JOIN vmp 
    ON ( vtm.vtmid = vmp.vtmid )
 INNER JOIN vmpform 
    ON ( vmp.vmpid = vmpform.vmpid )
 INNER JOIN vmproute 
    ON ( vmp.vmpid = vmproute.vmpid )
 INNER JOIN vpi 
    ON ( vmp.vmpid = vpi.vmpid )
 WHERE vtm.vtmid = {insert_vtm_id}
   AND ( vmpform.formid = IN_form_id OR ISNULL(IN_form_id) )
   AND ( vmproute.routeid = IN_route_id OR ISNULL(IN_route_id) )


Detailed Logic for Step 2 - Calculate the required quantity of each VMP to fulfil the requested dose

Conversion between scaler units of measure, e.g. gram to milligram

A function is required to convert a VTM ingredient strength into the same units as the requested dose quantity.

For example, if a required dose quantity is 12.5 milligram, but a VMP for that drug is expressed with a strength in micrograms e.g. 500 microgram, then that strength needs to be expressed in milligrams before the mathematical function can be executed.

Thus 500 microgram would be converted into 0.5 milligram.

For example;

///
// Convert 500 micrograms into milligrams
// FNC_CONVERT_UNITS(vpi.strnt_nmrtr_val, vpi.strnt_nmrtr_uomcd, dose_uom_cd);
///

SELECT FNC_CONVERT_UNITS(500, 258685003, 258684004);

// returns `0.5`.

Within the dm+d, units of mass have the greatest range; kilogram, gram, milligram, microgram and nanogram.

Due to this range, the data type used within SQL must be a DECIMAL(30,12).

Conversion is required for the following units of measure.

Category Units SNOMED Code Scaler Conversion
Mass kilogram 258683005 10^3
gram 258682000 1
milligram 258684004 10^-3
microgram 258685003 10^-6
nanogram 258686002 10^-9
Volume litre 258770004 1
millilitre 258773002 10^-3
microlitre 258774008 10^-6
nanolitre 282113003 10^-9
Length metre 258669008 1
centimetre 258672001 10^-2
millimetre 258673006 10^-3

Function for quantity

A suitable SQL function to calculate the quantity of a given VMP to fulfil the requested dose quantity would be as follows.

FUNCTION FNC_CALC_QTY( doseQty DECIMAL(9,3)
                     , numerator DECIMAL(30,12)
                     , denominator DECIMAL(9,3)
                     , unitDoseFormStrength DECIMAL(9,3)
                     )
RETURNS DECIMAL(30,12)
BEGIN

    IF denominator = 0  
        THEN SET denominator = 1; 
    END IF;
    
    IF unitDoseFormStrength = 0
        THEN RETURN doseQty / ( numerator / denominator );
    END IF;
	
    RETURN ( doseQty / ( numerator / denominator ) ) / unitDoseFormStrength;

END

A description of each variable used in FNC_CALC_QTY is contained below.

Variable Description
doseQty the required dose quantity - e.g. 12.5
numerator the VMP strength numerator, but has to be expressed in the same units as the requested dose, e.g. both in milligrams
denominator the VMP strength denominator which may be 0 / NULL for some VMPs, so use a default value of 1
unitDoseFormStrength the VMP unit dose form strength value, which may be 0 / NULL

Detailed Logic for Step 3 - Order the list of products in a clinically suitable order

TO DO. These stored procedures need to be extended to show relevant AMPs and hide VMPs flagged as Never valid to prescribe as a VMP.

Function for ranking / ordering

Uses the FNC_CALC_QTY function from above then calculates a ranking value which can be used to order the overall SQL query.

FUNCTION FNC_CALC_RANK( doseQty DECIMAL(9,3)
                      , numerator DECIMAL(30,12)
                      , denominator DECIMAL(9,3)
                      , unitDoseFormStrength DECIMAL
                      , formId BIGINT UNSIGNED
                      )
RETURNS SMALLINT(5) UNSIGNED

BEGIN
	DECLARE v_qty DECIMAL(30,12) UNSIGNED;
	DECLARE v_rank SMALLINT UNSIGNED;
	DECLARE v_divisable BIGINT UNSIGNED;

	SET v_qty = FNC_CALC_QTY(doseQty, numerator, denominator, unitDoseFormStrength);

	IF ( v_qty < 1 ) 
            THEN SET v_rank = 3;
	ELSE IF ( ( v_qty % 1 ) != 0 )
            THEN  SET v_rank = 2;
	ELSE 
	   SET v_rank = 1;
	END IF;

	IF ( v_rank != 1 )
            THEN SELECT name
                   FROM lookup
                  WHERE valueset = "NOTDIVISABLE"
                    AND id = formid 
                   INTO v_divisable;
	
            IF ( NOT NULL(v_divisable) ) 
                THEN SET v_rank = 4; 
            END IF;
	END IF;

	RETURN v_rank;
END

Where formid is the dm+d code for the requested dose quantity unit of measure.

The rules for the ranking are best shown in a table.

Calculated Quantity Ranking Ranking Reason
Integer 1 Can be fulfilled by one or more complete doses
Decimal greater than 1 2 Requires a number of doses include part doses
Decimal less than 1 3 Requires part of a a single dose
Decimal using a dose form typically not divisable 4 Unlikely to the clinically safe to use this product

Identification of dose forms that are typically not divisable

The following dose forms are typically not divisible, however this is not always the case.

For example there are some modified-release tablets with a score along the centre to aid division, but in most cases, modified-release products should not be divided.

The same applies for products as capsules. These represent the more common dose forms used within dm+d concepts. Other non-divisible dose forms may exist but their use would be rare, but this reference table can be extended or customised as required for a local implementation.

SNOMED / dm+d code Dose Form
385049006 Capsule
385054002 Modified-release capsule
385061003 Modified-release tablet
421720008 Spray

Complete Stored Procedure

PROCEDURE PRC_VTM_TO_VMP( IN IN_vtm_id BIGINT UNSIGNED
                        , IN IN_dose_qty DECIMAL
                        , IN IN_dose_uom_cd BIGINT UNSIGNED
                        , IN IN_form_id BIGINT UNSIGNED
                        , IN IN_route_id BIGINT UNSIGNED
                        )
BEGIN
	SELECT DISTINCT vmp.vmpid
        , vmp.name
        , FNC_CALC_QTY( IN_dose_qty
                      , FNC_CONVERT_UNITS( vpi.strnt_nmrtr_val
                                         , vpi.strnt_nmrtr_uomcd
                                         , IN_dose_uom_cd
                                         )
                      , vpi.strnt_dnmtr_val,vmp.udfs
                      ) AS qty
        , vmp.udfs_dose_uomcd
        , vpi.strnt_dnmtr_uomcd
        , FNC_CALC_RANK( IN_dose_qty
                       , FNC_CONVERT_UNITS( vpi.strnt_nmrtr_val
                                          , vpi.strnt_nmrtr_uomcd
                                          , IN_dose_uom_cd
                                          )
                       , vpi.strnt_dnmtr_val
                       , vmp.udfs,vmpform.formid
                       ) AS rnk
	  FROM vtm 
	 INNER JOIN vmp 
       ON ( vtm.vtmid = vmp.vtmid )
	 INNER JOIN vmpform
       ON ( vmp.vmpid = vmpform.vmpid )
	 INNER JOIN vmproute
       ON ( vmp.vmpid = vmproute.vmpid )
	 INNER JOIN vpi
       ON ( vmp.vmpid = vpi.vmpid )
	 INNER JOIN lookup
       ON ( vpi.strnt_nmrtr_uomcd = lookup.id )
	 WHERE vtm.vtmid = IN_vtm_id
	   AND ( vmpform.formid = IN_form_id OR ISNULL(IN_form_id) )
	   AND ( vmproute.routeid = IN_route_id OR ISNULL(IN_route_id) )
	 ORDER BY rnk ASC, qty ASC;
END


Worked Examples

Example A

VTM = Oxytetracycline | 22969001

Dose = 250 milligram

Step 1: Get child products (VMPs and AMPs) of the VTM

There are five valid and available VMPs. None are flagged in a way that require additional AMPs to be listed.

dm+d concept Product
VMP Oxytetracycline 100mg/5ml oral suspension
VMP Oxytetracycline 125mg/5ml oral suspension
VMP Oxytetracycline 250mg tablets
VMP Oxytetracycline 250mg/5ml oral suspension
VMP Oxytetracycline 500mg/5ml oral suspension

Step 2: Calculate the required quantity of each VMP to fulfil the requested dose

dm+d concept Product Quantity Calculation Unit of Measure
VMP Oxytetracycline 100mg/5ml oral suspension 250 / (20/1) = 12.5 ml
VMP Oxytetracycline 125mg/5ml oral suspension 250 / (25/1) = 10 ml
VMP Oxytetracycline 250mg tablets 250 / (250) = 1 tablet
VMP Oxytetracycline 250mg/5ml oral suspension 250 / (50) = 5 ml
VMP Oxytetracycline 500mg/5ml oral suspension 250 / (100/1) = 2.5 ml

Step 3: Order the list of products in a clinically suitable order

Product Quantity (to fulfil 250 milligrams)
Oxytetracycline 250mg tablets 1 tablet
Oxytetracycline 250mg/5ml oral suspension 5 ml
Oxytetracycline 125mg/5ml oral suspension 10 ml
Oxytetracycline 500mg/5ml oral suspension 2.5 ml
Oxytetracycline 100mg/5ml oral suspension 12.5 ml

Example B

VTM = Salbutamol | 91143003

Dose = 200 micrograms

Route = Inhalation | 18679011000001101

Step 1: Get child products (VMPs and AMPs) of the VTM

There are two valid and available VMPs, but both are flagged as Caution - AMP level prescribing advised so we also query for valid and available AMPs.

dm+d concept Product
VMPSalbutamol 100micrograms/dose breath actuated inhaler CFC free
-- AMPAiromir 100micrograms/dose Autohaler (Teva UK Ltd)
-- AMPSalamol 100micrograms/dose Easi-Breathe inhaler (CST Pharma Ltd)
-- AMPSalamol 100micrograms/dose Easi-Breathe inhaler (Teva UK Ltd)
VMPSalbutamol 100micrograms/dose inhaler CFC free
-- AMPAiromir 100micrograms/dose inhaler (Teva UK Ltd)
-- AMPSalamol 100micrograms/dose inhaler CFC free (Teva UK Ltd)
--AMPVentolin 100micrograms/dose Evohaler (GlaxoSmithKline UK Ltd)

Step 2: Calculate the required quantity of each VMP to fulfil the requested dose

dm+d concept Product Quantity Calculation Unit of Measure
VMP Salbutamol 100micrograms/dose breath actuated inhaler CFC free 200 / (100) = 2 dose
-- AMPAiromir 100micrograms/dose Autohaler (Teva UK Ltd) 200 / (100) = 2 dose
-- AMPSalamol 100micrograms/dose Easi-Breathe inhaler (CST Pharma Ltd) 200 / (100) = 2 dose
-- AMPSalamol 100micrograms/dose Easi-Breathe inhaler (Teva UK Ltd) 200 / (100) = 2 dose
VMPSalbutamol 100micrograms/dose inhaler CFC free 200 / (100) = 2 dose
-- AMPAiromir 100micrograms/dose inhaler (Teva UK Ltd) 200 / (100) = 2 dose
-- AMPSalamol 100micrograms/dose inhaler CFC free (Teva UK Ltd) 200 / (100) = 2 dose
--AMPVentolin 100micrograms/dose Evohaler (GlaxoSmithKline UK Ltd) 200 / (100) = 2 dose

Step 3: Order the list of products in a clinically suitable order

As all products can be used with the same quantity, the order could be alphabetical or ordered as per any local formulary.

Product Quantity (to fulfil 200 micrograms)
Salbutamol 100micrograms/dose breath actuated inhaler CFC free
Note: Caution - AMP level prescribing advised
2 dose
Airomir 100micrograms/dose Autohaler (Teva UK Ltd) 2 dose
Salamol 100micrograms/dose Easi-Breathe inhaler (CST Pharma Ltd) 2 dose
Salamol 100micrograms/dose Easi-Breathe inhaler (Teva UK Ltd) 2 dose
Salbutamol 100micrograms/dose inhaler CFC free
Note: Caution - AMP level prescribing advised
2 dose
Airomir 100micrograms/dose inhaler (Teva UK Ltd) 2 dose
Salamol 100micrograms/dose inhaler CFC free (Teva UK Ltd) 2 dose
Ventolin 100micrograms/dose Evohaler (GlaxoSmithKline UK Ltd) 2 dose

Known Issues

Products (VMPs) where the VPI strength is expressed as an inaccurate decimal value

The vast majority of VMPs are defined with a Virtual Product Ingredient (VPI) strength as a whole number, e.g. numerator = 5 (mg) and denominator = 1 (ml). A small percentage of VMPs are defined with a numerator expressed as an incurate decimal value.

Two examples are;

  1. Oxybutynin 5mg/15ml bladder irrigation vials, VPI strength = 333.33 micrograms / 1 ml

  2. Methotrexate 25mg/3ml solution for injection pre-filled syringes, VPI strength = 8.333 mg / 1 ml

This inaccuracy of values like 333.33 or 8.333 not being mathmetically the same as one third of a milligram means the mathematics used in these calculations does not result in a whole number.

For example;

  • VMP = Oxybutynin 5mg/15ml bladder irrigation vials
  • Requested Dose = 10 milligram
  • Calculated Quantity = 2.002 vials

and

  • VMP = Methotrexate 25mg/3ml solution for injection pre-filled syringes
  • Requested Dose = 25 milligram
  • Calculated Quantity = 1.041667 pre-filled disposable injection

It would be unwise to add bespoke logic to round up to the nearest whole number in such cases as this would require an assumption that this is the intention of the prescriber.

A possible solution that will be discussed with the owners of the NHS dm+d would be to express the strength in a way that uses absolute values.

For example;

  1. Oxybutynon 5mg/15ml bladder irrigation vials, VPI strength = 1 mg / 3 ml
  2. Methotrexate 25mg/3ml solution for injection pre-filled syringes, VPI strength = 25 mg / 3 ml

back to top