maintenance: title: Round Medication Dosage;; mlmname: SYS_ROUND_DOSAGE;; arden: version 2.5;; version: 18.4;; institution: Allscripts, System MLM;; author: Allscripts Healthcare Solutions, Inc.;; specialist: ;; date: 2018-10-26;; validation: testing;; /* P r o p r i e t a r y N o t i c e */ /* Unpublished (c) 2013 - 2018 Allscripts Healthcare, LLC. and/or its affiliates. All Rights Reserved. P r o p r i e t a r y N o t i c e: This software has been provided pursuant to a License Agreement, with Allscripts Healthcare, LLC. and/or its affiliates, containing restrictions on its use. This software contains valuable trade secrets and proprietary information of Allscripts Healthcare, LLC. and/or its affiliates and is protected by trade secret and copyright law. This software may not be copied or distributed in any form or medium, disclosed to any third parties, or used in any manner not provided for in said License Agreement except with prior written authorization from Allscripts Healthcare, LLC. and/or its affiliates. Notice to U.S. Government Users: This software is {{{SINGLE-QUOTE}}}Commercial Computer Software{{{SINGLE-QUOTE}}}. All product names are the trademarks or registered trademarks of Allscripts Healthcare, LLC. and/or its affiliates. */ /* P r o p r i e t a r y N o t i c e */ library: purpose: Rounds a medication dose to the appropriate value using the medication route; or within the limit of a maximum of 10% variation, regardless of route. ;; explanation: Implements rounding rules in one of three ways. The first two were developed by Eclipsys, and the third was developed at Johns Hopkins Hospital using an algorithm that limits the rounding so that it never exceeds 10% of the original dose amount. The Eclipsys rounding rules are designated as "Standard" and are the default function of this MLM. The third rule is designated as "10pctLimit" and can be selected by changing the RoundingRule flag in the Spelling and Flags section. The "Standard" rounding rules can be used when the route is supplied. An error message is returned if the Dose is NOT a string, or if the Route is NULL, or if the dose amount is smaller than 0.005: (1) The Parenteral Rounding Rules are used whenever the route matches the routes listed in the Parenteral_Route_List variable. (2) The Other Rounding Rules are used whenever a route exists and does NOT match the routes listed in the Parenteral_Route_List variable. PARENTERAL ROUNDING RULES For values < 0.005, return Error_Message For values <= 1, round to the nearest 0.01 For values > 1 and <= 5, round to the nearest 0.1 For values > 5 and <= 50, round to the nearest 1 (integer) For values > 50 and <= 100, round to the nearest 2 (even number) For values > 100 and <= 500, round to the nearest 10 (integer) For values > 500 and <= 2000, round to the nearest 50 (integer) For values > 2000, round to the nearest 100 (integer) OTHER ROUNDING RULES For values < 0.005, return Error_Message For values <= 1, round to the nearest 0.01 For values >= 1 and <= 10, round to the nearest 0.1 For values >= 10 and <= 50, round to the nearest integer For values > 50, round to the nearest 5 The "10pctLimit" rule implements the requirement that rounding shall not exceed 10% of the original amount. It rounds to values that are always within 1 log value of the dose, as in the chart below. It will not evaluate a Route nor return a route error message. To conform with the functional limits of the Sunrise application, it will return: 1) an error message and NULL for the rounded dose if the dose amount is less than 0.00005; 2) a warning message and a rounded dose that may exceed the 10% limit if 0.00005 <= dose < 0.0005; or 3) a NULL message and a rounded dose within the 10% limit for all other dose values. . . . . (error) any smaller <= Dose < 0.00005 -> return Error_Message 0.00005 <= Dose < 0.0005 -> Round to the nearest 0.0001, return warning_message 0.0005 <= Dose < 0.005 -> Round to the nearest 0.0001 0.005 <= Dose < 0.05 -> Round to the nearest 0.001 0.05 <= Dose < 0.5 -> Round to the nearest 0.01 (A) 0.5 <= Dose < 5 -> Round to the nearest 0.1 (B) 5 <= Dose < 50 -> Round to the nearest 1 50 <= Dose < 500 -> Round to the nearest 10 500 <= Dose < 5000 -> Round to the nearest 100 5000 <= Dose < 50000 -> Round to the nearest 1000 50000 <= Dose < 500000 -> Round to the nearest 10000 500000 <= Dose < 5000000 -> Round to the nearest 100000 5000000 <= Dose < 50000000 -> Round to the nearest 1000000 . . . METHOD: 1) The Dose is normalized by moving the decimal point so that 1 <= (normalized value) < 10. This is done by taking the log of the Dose. 2) Because the normalized Dose satisfies 1 <= (normalized Dose) < 10, we apply rule (A) above if the normalized Dose is < 5 and rule (B) above otherwise. 3) The decimal point is moved back to its former location (denormalized). A facility can modify this MLM if a different rounding is preferred. ;; keywords: ;; knowledge: type: data-driven;; data: /***************** Make Changes To Spelling And Flags In This Section ******************/ // The rounding rule type to be applied by the MLM. Current valid values are // "Standard" (the default) and "10pctLimit" RoundingRule := "Standard"; // The list of PARENTERAL ROUTES that will be used to round the // dose using the "Dose Rounding Rules for Parenteral Routes." // The strings must match entries in your Route Dictionary. // If there any entries that are NOT in your Route Dictionary, remove them. Parenteral_Route_List := ("IM", "IM or IV", "IV", "IV push", "IVPB", "SC", "Subcutaneous"); /* Set to true if logging is needed.*/ log_execution_info := false; /***************************************************************************************/ /*-----------*/ /* ARGUMENTS */ /*-----------*/ (dose, // A number that is the amount of the dose. route) // A string that is from the Route Dictionary. := Argument; /* Set Return Variables to NULL */ rounded_dose := NULL; error_message := NULL; /* Set Round, Dose and Route errors to blank */ round_error := ""; dose_error := ""; route_error := ""; /* Assume no errors to start */ fatal_error := false; minor_error := false; if dose is not number then /*------------------------------------------------------*/ /* Create Error Message for non-numerical dose argument */ /*------------------------------------------------------*/ fatal_error := true; dose_error := " the Dose is NOT a number."; else /*----------------------------------------------*/ /* proceed if we have numeric argument for dose */ /*----------------------------------------------*/ if (RoundingRule is null or RoundingRule = "Standard") then if not exist Route then fatal_error := true; route_error := " the Route is missing or invalid."; elseif dose < 0.005 then fatal_error := true; dose_error := " the Dose amount is less than the {{{SINGLE-QUOTE}}}Standard{{{SINGLE-QUOTE}}} rounding lower limit (0.005)."; else // process only if we have a route if route is in Parenteral_Route_List then /*---------------------------*/ /* PARENTERAL Rounding Rules */ /*---------------------------*/ if dose <=1 then /* For values <= 1, round to the nearest 0.01 */ rounded_dose:= (int((dose + 0.0051)*100))/100; elseif dose <= 5 then /* For values > 1 and <= 5, round to the nearest 0.1 */ rounded_dose:= (int((dose + 0.051)*10))/10; elseif dose <= 50 then /* For values > 5 and <= 50, round to the nearest 1 (integer) */ rounded_dose:= int(dose + 0.51); elseif dose <= 100 then /* For values > 50 and <= 100, round to the nearest 2 (even number) */ rounded_dose:= int((dose/2)+ 0.5)* 2; elseif dose <= 500 then /* For values > 100 and <= 500, round to the nearest 10 (integer) */ rounded_dose:= int((dose/10)+ 0.5)* 10; elseif dose <= 2000 then /* For values > 500 and <= 2000, round to the nearest 50 (integer) */ rounded_dose:= int((dose/50)+ 0.5)* 50; elseif dose > 2000 then /* For values > 2000, round to the nearest 100 (integer) */ rounded_dose:= int((dose/100)+ 0.5)* 100; endif; // dose ranges (Parenteral route) else /*---------------------------------------------*/ /* OTHER (non-parenteral Route) Rounding Rules */ /*---------------------------------------------*/ if dose <= 1 then /*For values <= 1, round to the nearest 0.01*/ rounded_dose:= (int((dose + 0.0051)*100))/100; elseif dose < 10 then /* For values >= 1 and <= 10, round to the nearest 0.1 */ rounded_dose:= (int((dose + 0.051)*10))/10; elseif dose <= 50 then /* For values >= 10 and <= 50, round to the nearest integer */ rounded_dose:= int(dose + 0.51); else /* For values > 50, round to the nearest 5 */ rounded_dose:= int((dose/5)+ 0.51)* 5; endif; // dose ranges (non-Parenteral route) endif; // Route is in parenteral list endif; // not exist Route (for Standard rounding) elseif RoundingRule = "10pctLimit" then /* the number of decimal places is found by the log base 10 */ decimal_offset := int(log10(dose)); /* shift decimal point to "normalize" dose */ dose_normalized := dose / (10**decimal_offset); /*-----------------------------------*/ /* now 1 <= dose_normalized < 10 */ /*-----------------------------------*/ if (dose < 0.00005) then fatal_error := true; dose_error := " the Dose amount is less than the {{{SINGLE-QUOTE}}}10pctLimit{{{SINGLE-QUOTE}}} " || "rounding lower limit (0.00005)."; elseif (0.00005 <= dose) and (dose < 0.0005) then rounded_dose := dose formatted with "%.4f"; rounded_dose := rounded_dose as number; if (abs(rounded_dose - dose) / dose) > 0.1 then minor_error := true; round_error := " rounded dose is outside the 10% limit " || "due to number of decimal places."; endif; // rounded dose is outside 10% else /* round value below 5 to nearest 10th */ if dose_normalized < 5 then rounded_dose_normalized := int((dose_normalized + 0.051)*10)/10; else /* or round to next higher integer */ rounded_dose_normalized := int(dose_normalized + 0.51); endif; /* restore decimal point */ rounded_dose := rounded_dose_normalized * (10**decimal_offset); endif; // (dose < 0.00005) (10pctLimit) /*----------------------------------*/ /* Insert other Rounding Rules here */ /*----------------------------------*/ endif; // Rounding Rule is Standard or 10pctLimit (or other) endif; /* dose is number */ ;; evoke: ;; logic: if fatal_error then error_message := "Unable to round dose because" || dose_error || route_error; elseif minor_error then error_message := "Warning: " || round_error; endif; /* Always conclude true to return a value */ conclude true; ;; action: return error_message, rounded_dose; ;; end: