maintenance: title: Track the Average and Total Daily Doses ;; mlmname: STD_FUNC_DOSAGE_TRACKER;; arden: version 2.5;; version: 18.4;; institution: Allscripts, Standard 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: This MLM tracks the Average Daily Dose and the Total Daily Dose. ;; explanation: This MLM calculates the Average Daily Dose and the Total Daily Dose by using two approaches: 1. The CONVERSION FACTOR approach does the calculation by multiplying the single dose by a conversion factor that is based on the order{{{SINGLE-QUOTE}}}s frequency, or if Prescription. 2. The SUMMED DOSES approach uses the estimated dose administration times to sort the single doses into 24-hour intervals. Then each 24-hour interval is summed to calculate the Average and Total doses. ;; keywords: single dose; average daily dose; total daily dose; dosage range ;; knowledge: type: data-driven;; data: med_data_list := ARGUMENT; // Set to true if logging is needed. log_execution_info := false; //Declare MLMs that can be called calc_freqmult_daily := MLM {{{SINGLE-QUOTE}}}sys_calc_freqmult_daily{{{SINGLE-QUOTE}}}; calc_freqmult_average:= MLM {{{SINGLE-QUOTE}}}sys_calc_freqmult_average{{{SINGLE-QUOTE}}}; func_dosage_trim := MLM {{{SINGLE-QUOTE}}}std_func_dosage_trim{{{SINGLE-QUOTE}}}; func_calc_method := MLM {{{SINGLE-QUOTE}}}STD_FUNC_DOSAGE_CALC_METHOD{{{SINGLE-QUOTE}}}; //Declare the Dose_Tracker_Object Dose_Tracker_Object := OBJECT [ Med_Data_GUID, med_order_type, med_name, interval_begin_dtm, interval_end_dtm, num_doses_in_24hrs, // indicates how many number of doses should be in 24hr num_doses, // indicates how many doses would be administered in 24hr total_dose_low, total_dose_high, uom, route, start_date ]; //Declare the Sum_Tracker_Object Sum_Tracker_Object := OBJECT [interval_begin_dtm, interval_end_dtm, is_last_24hr_interval, has_full_24hrs_doses, med_order_type, med_name, route, total_dose_low, total_dose_high, uom, start_date ]; //Declare the Total_Tracker_Object Total_Tracker_Object := OBJECT [ sort_number, interval_begin_dtm_list, is_last_24hr_interval, has_full_24hrs_doses, med_order_type, med_name, route, total_dose_low, total_dose_high, uom, dose_calc_method_number, total_calc_med_dose_low, total_calc_med_dose_high, calc_text, retrieved_dose_range_data, found_total_daily_dose, missing_height, missing_weight, processed_missing_data_msg, met_criteria_under_24_hours, processed_for_printing, dose_range_check_method, outside_total_daily_dose, suppress_alert, alert_msg_for_total, met_criteria_has_shift_frequency, start_date ]; //Declare the Average_Tracker_Object Average_Tracker_Object := OBJECT [ sort_number, interval_begin_dtm_list, is_last_24hr_interval, has_full_24hrs_doses, med_order_type, med_name, route, average_dose_low, average_dose_high, uom, dose_calc_method_number, average_calc_med_dose_low, average_calc_med_dose_high, calc_text, retrieved_dose_range_data, found_average_daily_dose, processed_missing_data_msg, met_criteria_under_24_hours, processed_for_printing, irregular_schedule_used, user_scheduled_weekly_used, dose_range_check_method, outside_average_daily_dose, suppress_alert, alert_msg_for_average, met_criteria_has_shift_frequency, start_date ]; ;; evoke: ;; logic: // Initialize Variables dose_tracker_list := (); sum_tracker_list := (); total_tracker_list := (); average_tracker_list := (); Calculation_Method := call func_calc_method with med_data_list; if Calculation_Method = "CONVERSION" then for med_data in med_data_list do // Significant_date is important in several calculations and cannot // be NULL. Set it to be the first calculated admin time. if med_data.order_med_significant_date is null then med_data.order_med_significant_date := first med_data.admin_dtm_list; endif; //----------------------------- //Calculate Total Daily Dose //----------------------------- // Find the Total_Tracker_Object // The Med Order Type, Medication Name, and UOM must match // Route must match or both be NULL found_total_tracker := total_tracker_list where (total_tracker_list.med_order_type = med_data.med_order_type and total_tracker_list.med_name = med_data.order_med_name and (total_tracker_list.route = med_data.order_med_route or ((total_tracker_list.route is NULL) and (med_data.order_med_route is NULL))) and total_tracker_list.uom = med_data.order_med_units); //and total_tracker_list.start_date = med_data.order_med_significant_date ); if not exist found_total_tracker then //Calculate the Total Daily Dose for the Highs and Low Doses //Create a new object total_instance := new Total_Tracker_Object; total_tracker_list := total_tracker_list, total_instance; //Populate the data total_instance.dose_range_check_method := "Conversion Factor"; total_instance.med_order_type := med_data.med_order_type; total_instance.med_name := med_data.order_med_name; total_instance.route := med_data.order_med_route; total_instance.uom := med_data.order_med_units; total_instance.dose_calc_method_number := med_data.calc_dose_method; total_instance.calc_text := med_data.calc_text; total_instance.start_date := med_data.order_med_significant_date; if (med_data.is_order) then // Call an MLM to calculate the conversion factor for Total Daily Dose conversion_factor_ave := call calc_freqmult_daily with med_data.order_med_frequency, med_data.freq_from_time, med_data.freq_uom; else conversion_factor_ave := med_data.freq_multiplier; endif; // Calculate the Low and High Doses for Total Daily Dose // by multiplying the doses with the conversion factor // AND Store the Doses temp_total_dose_low := med_data.order_med_dose_low * conversion_factor_ave; temp_total_dose_high := med_data.order_med_dose_high * conversion_factor_ave; // Trim the Excess Decimals rounded_trim_numbers_list := call func_dosage_trim with med_data.order_med_dose_low, // a single number (temp_total_dose_high, temp_total_dose_low); // a list of numbers // Store Doses total_instance.total_dose_high := rounded_trim_numbers_list[1]; total_instance.total_dose_low := rounded_trim_numbers_list[2]; endif; //not exist found_total_tracker //----------------------------- //Calculate Average Daily Dose //----------------------------- // Find the Average_Tracker_Object // The Med Order Type, Medication Name, and UOM must match // Route must match or both be NULL found_average_tracker := average_tracker_list where (average_tracker_list.med_order_type = med_data.med_order_type and average_tracker_list.med_name = med_data.order_med_name and (average_tracker_list.route = med_data.order_med_route or ((average_tracker_list.route is NULL) and (med_data.order_med_route is NULL))) and average_tracker_list.uom = med_data.order_med_units ); if not exist found_average_tracker then //Calculate an Average for the Highs and Low Doses //Create a new object average_instance := new Average_Tracker_Object; average_tracker_list := average_tracker_list, average_instance; //Populate the data average_instance.dose_range_check_method := "Conversion Factor"; average_instance.med_order_type := med_data.med_order_type; average_instance.med_name := med_data.order_med_name; average_instance.route := med_data.order_med_route; average_instance.uom := med_data.order_med_units; average_instance.dose_calc_method_number := med_data.calc_dose_method; average_instance.calc_text := med_data.calc_text; average_instance.start_date := med_data.order_med_significant_date; // Call an MLM to calculate the conversion factor for Average Daily Dose conversion_factor_ave := call calc_freqmult_average with med_data.order_med_frequency, med_data.freq_from_time, med_data.freq_uom; // Calculate the Low and High Doses for Average Daily Dose // by multiplying the doses with the conversion factor // AND Store the Doses temp_average_dose_low := med_data.order_med_dose_low * conversion_factor_ave; temp_average_dose_high := med_data.order_med_dose_high * conversion_factor_ave; // no rounding for average dose for proper daily dose checking average_instance.average_dose_high := temp_average_dose_high; average_instance.average_dose_low := temp_average_dose_low; endif; //not exist found_average_tracker enddo; //for med_data //************************************************************** // Use the SUMMED-DOSE Dosage-Range Checking (newer approach ) //************************************************************** else //----------------------------------------- //Create and Populate Dose_Tracker_Objects //----------------------------------------- // Remove NULL from the Admin_Dtm_List before doing a MIN function temp_admin_dtm_list := (); for med_data in med_data_list do if exist med_data.admin_dtm_list then temp_admin_dtm_list := temp_admin_dtm_list, med_data.admin_dtm_list; endif; enddo; //for med_data //Get the Earliest Administration Date-Time for the Medication Order order_begin_dtm := MIN temp_admin_dtm_list; // Loop Through Each Med_Data Object for EE in med_data_list do // Significant_date is important in several calculations and cannot // be NULL. Set it to be the first calculated admin time. if EE.order_med_significant_date is null then EE.order_med_significant_date := first EE.admin_dtm_list; endif; // Only create Dose_Tracker_Objects if the medication has a dose. // If a medication has a dose, then the order_med_dose_low must have a value. // Medication orders such as IV-solutions and Master Complex Orders do not have doses. // So their order_med_dose_low is NULL. However, their components do have doses. if exist EE.order_med_dose_low then // Find the dose instance based on the med GUID and Name. dose_instance := last (dose_tracker_list where (dose_tracker_list.Med_Data_GUID = EE.med_data_guid and dose_tracker_list.order_med_name = EE.order_med_name)); dMultiplier := call calc_freqmult_average with EE.order_med_frequency, EE.freq_from_time, EE.freq_uom; num_doses_in_24hrs := 1; if dMultiplier is not null then num_doses_in_24hrs := int floor of dMultiplier; endif; // Use the Medication{{{SINGLE-QUOTE}}}s Administation Date to Put the Doses in the Correct Object. for admin_date in EE.admin_dtm_list do // If a instance doesn{{{SINGLE-QUOTE}}}t yet exist or the admin date is beyond // the current instance{{{SINGLE-QUOTE}}}s end date then create a new one. if not exists dose_instance OR (admin_date >= dose_instance.interval_end_dtm) then // Create a new Dose_Tracker_Object dose_instance := new Dose_Tracker_Object; //Add to the List of objects dose_tracker_list := dose_tracker_list, dose_instance; //Populate the new Dose_Tracker_Object with basic information dose_instance.Med_Data_GUID := EE.med_data_guid; dose_instance.med_order_type := EE.med_order_type; dose_instance.med_name := EE.order_med_name; dose_instance.uom := EE.order_med_units; dose_instance.route := EE.order_med_route; dose_instance.total_dose_low := 0; dose_instance.total_dose_high := 0; dose_instance.num_doses_in_24hrs := num_doses_in_24hrs; dose_instance.num_doses := 0; dose_instance.start_date := EE.order_med_significant_date; //Calculate the Begin and End Time Intervals //And Set Them length_of_time := admin_date - order_begin_dtm; multiplier := truncate (length_of_time / 24 hours) ; dose_instance.interval_begin_dtm := order_begin_dtm + (multiplier * 24 hours); dose_instance.interval_end_dtm := dose_instance.interval_begin_dtm + 24 hours; endif; //if exist found_dose_tracker //Populate Dose_Tracker with Doses if exist EE.order_med_dose_low then //use the low dose for dose low, //otherwise the dose is null and we do not add null to a number. dose_instance.total_dose_low := dose_instance.total_dose_low + (EE.order_med_dose_low as number) ; endif; if exist EE.order_med_dose_high then //use the high dose for dose high dose_instance.total_dose_high := dose_instance.total_dose_high + (EE.order_med_dose_high as number); elseif exist EE.order_med_dose_low then //use the low dose for dose high dose_instance.total_dose_high := dose_instance.total_dose_high + (EE.order_med_dose_low as number); endif; //if exist EE.order_med_dose_high // count the number of doses in 24 hr interval based on admin times. dose_instance.num_doses := dose_instance.num_doses + 1; enddo; //for admin_date endif; //if exist EE.order_med_dose_low enddo; //for EE //------------------------------------------------------------------------ // Sum the Dose for Each 24-Hour Interval Across OrderVariableComponents //------------------------------------------------------------------------ // Different Routes and UOMs must be summed separately // Loop Through Each Dose_Tracker_Object // And determine which Sum_Tracker_Object to Use for FF in dose_tracker_list do // Use the Interval_Begin_Dtm to Put the Doses in the Correct Object. // Find the Dose_Tracker_Object // The Medication Name, Date Intervals, and UOM must be the same // and the Routes must match or both be NULL. found_sum_tracker := sum_tracker_list where ((sum_tracker_list.route = FF.route or (sum_tracker_list.route is null) and (FF.route is null)) and sum_tracker_list.uom = FF.uom and sum_tracker_list.med_name = FF.med_name and sum_tracker_list.interval_begin_dtm = FF.interval_begin_dtm); if exist found_sum_tracker then // Use the Existing Sum_Tracker_Object sum_instance := last (found_sum_tracker); else //Otherwise Create a new Sum_Tracker_Object sum_instance := new Sum_Tracker_Object; //Add to the List of objects sum_tracker_list := sum_tracker_list, sum_instance; //Populate the new Sum_Tracker_Object with basic information sum_instance.med_order_type := FF.med_order_type; sum_instance.med_name := FF.med_name; sum_instance.interval_begin_dtm := FF.interval_begin_dtm; sum_instance.interval_end_dtm := FF.interval_end_dtm; sum_instance.uom := FF.uom; sum_instance.route := FF.route; sum_instance.total_dose_low := 0; sum_instance.total_dose_high := 0; sum_instance.start_date := FF.start_date; endif; //if exist found_sum_tracker if FF.num_doses_in_24hrs = FF.num_doses then sum_instance.has_full_24hrs_doses := true; else sum_instance.has_full_24hrs_doses := false; endif; if FF = last (dose_tracker_list) then sum_instance.is_last_24hr_interval := true; else sum_instance.is_last_24hr_interval := false; endif; //Populate Sum_Tracker with Doses sum_instance.total_dose_low := sum_instance.total_dose_low + FF.total_dose_low ; sum_instance.total_dose_high := sum_instance.total_dose_high + FF.total_dose_high ; enddo; //for FF //------------------------------ // Calculate Total Daily Dose //------------------------------ for GG in (1 seqto count sum_tracker_list) do // Find the Total_Tracker_Object // The Med Order Type, Medication Name, UOM, Dose Low, and Dose High must match // Route must match or both be NULL found_total_tracker := total_tracker_list where (total_tracker_list.med_order_type = sum_tracker_list[GG].med_order_type and total_tracker_list.med_name = sum_tracker_list[GG].med_name and (total_tracker_list.route = sum_tracker_list[GG].route or ((total_tracker_list.route is NULL) and (sum_tracker_list[GG].route is NULL))) and total_tracker_list.uom = sum_tracker_list[GG].uom and total_tracker_list.total_dose_low = sum_tracker_list[GG].total_dose_low and total_tracker_list.total_dose_high = sum_tracker_list[GG].total_dose_high); if exist found_total_tracker then //Use existing object total_instance := last found_total_tracker; //Add DTM to the list if exist total_instance.interval_begin_dtm_list then total_instance.interval_begin_dtm_list := total_instance.interval_begin_dtm_list, sum_tracker_list[GG].interval_begin_dtm; endif; //if exist total_instance.interval_begin_dtm_list else //Create a new object total_instance := new Total_Tracker_Object; //Add the total_instance to the list total_tracker_list := total_tracker_list, total_instance; //Populate Total_Tracker_Object total_instance.dose_range_check_method := "Summed Doses"; total_instance.med_order_type := sum_tracker_list[GG].med_order_type; total_instance.med_name := sum_tracker_list[GG].med_name; total_instance.route := sum_tracker_list[GG].route; total_instance.total_dose_low := sum_tracker_list[GG].total_dose_low; total_instance.total_dose_high := sum_tracker_list[GG].total_dose_high; total_instance.uom := sum_tracker_list[GG].uom; total_instance.dose_calc_method_number := sum_tracker_list[GG].dose_calc_method_number; total_instance.interval_begin_dtm_list := sum_tracker_list[GG].interval_begin_dtm; total_instance.is_last_24hr_interval := sum_tracker_list[GG].is_last_24hr_interval; total_instance.has_full_24hrs_doses := sum_tracker_list[GG].has_full_24hrs_doses; total_instance.start_date := sum_tracker_list[GG].start_date; endif; //if exist found_total_tracker // Set the Calc Method and Calc_Text temp_object := first (med_data_list where (med_data_list.med_order_type = total_instance.med_order_type and med_data_list.order_med_name = total_instance.med_name and (med_data_list.order_med_route = total_instance.route or ((med_data_list.order_med_route is NULL) and (total_instance.route is NULL))))); total_instance.dose_calc_method_number := temp_object.calc_dose_method; total_instance.calc_text := temp_object.calc_text; enddo; //for GG //----------------------------- //Calculate Average Daily Dose //----------------------------- for HH in (1 seqto count total_tracker_list) do // Find the Average_Tracker_Object // The Med Order Type, Medication Name, and UOM must match // Route must match or both be NULL found_average_tracker := average_tracker_list where (average_tracker_list.med_order_type = total_tracker_list[HH].med_order_type and average_tracker_list.med_name = total_tracker_list[HH].med_name and (average_tracker_list.route = total_tracker_list[HH].route or ((average_tracker_list.route is NULL) and (total_tracker_list[HH].route is NULL))) and average_tracker_list.uom = total_tracker_list[HH].uom ); //Find the Total_Tracker_Objects // The Med Order Type, Medication Name, and UOM must match // Route must match or both be NULL found_total_tracker := total_tracker_list where (total_tracker_list.med_order_type = total_tracker_list[HH].med_order_type and total_tracker_list.med_name = total_tracker_list[HH].med_name and (total_tracker_list.route = total_tracker_list[HH].route or ((total_tracker_list.route is NULL) and (total_tracker_list[HH].route is NULL))) and total_tracker_list.uom = total_tracker_list[HH].uom ); if found_total_tracker[1].med_order_type = "Complex Order" and not exist found_average_tracker then //Copy Total_Tracker data to the Average_Tracker //Do NOT calculate an Average for the Highs and Low Doses for JJ in (1 seqto count found_total_tracker) do //Create a new object average_instance := new Average_Tracker_Object; average_tracker_list := average_tracker_list, average_instance; //Populate the data average_instance.dose_range_check_method := "Summed Doses"; average_instance.med_order_type := found_total_tracker[JJ].med_order_type; average_instance.med_name := found_total_tracker[JJ].med_name; average_instance.route := found_total_tracker[JJ].route; average_instance.uom := found_total_tracker[JJ].uom; average_instance.dose_calc_method_number := found_total_tracker[JJ].dose_calc_method_number; average_instance.calc_text := found_total_tracker[JJ].calc_text; average_instance.interval_begin_dtm_list := found_total_tracker[JJ].interval_begin_dtm_list; average_instance.average_dose_low := found_total_tracker[JJ].total_dose_low; average_instance.average_dose_high := found_total_tracker[JJ].total_dose_high; average_instance.is_last_24hr_interval := found_total_tracker[JJ].is_last_24hr_interval; average_instance.has_full_24hrs_doses := found_total_tracker[JJ].has_full_24hrs_doses; average_instance.start_date := found_total_tracker[JJ].start_date; enddo; //for JJ elseif found_total_tracker[1].med_order_type is in ( "Regular", "IV-Additive") and not exist found_average_tracker then //Calculate an Average for the Highs and Low Doses //Create a new object average_instance := new Average_Tracker_Object; average_tracker_list := average_tracker_list, average_instance; //Populate the data average_instance.dose_range_check_method := "Summed Doses" ; average_instance.med_order_type := last found_total_tracker.med_order_type; average_instance.med_name := last found_total_tracker.med_name; average_instance.route := last found_total_tracker.route; average_instance.uom := last found_total_tracker.uom; average_instance.dose_calc_method_number := last found_total_tracker.dose_calc_method_number; average_instance.calc_text := last found_total_tracker.calc_text; average_instance.start_date := last found_total_tracker.start_date; //Calculate Average Daily for Low and High Doses temp_low := 0; temp_high := 0; temp_min_dtm := null; temp_max_dtm := null; for KK in (1 seqto count found_total_tracker) do temp_number_of_dates := count found_total_tracker[KK].interval_begin_dtm_list; temp_low := temp_low + (found_total_tracker[KK].total_dose_low * temp_number_of_dates); temp_high := temp_high + (found_total_tracker[KK].total_dose_high * temp_number_of_dates); // Get the Min and Max DTM from the CURRENT Total Tracker temp_min_dtm_in_tracker := min (found_total_tracker[KK].interval_begin_dtm_list); temp_max_dtm_in_tracker := max (found_total_tracker[KK].interval_begin_dtm_list); // Find the Minimum Dtm for the group of FOUND Total Trackers if not exist temp_min_dtm then temp_min_dtm := temp_min_dtm_in_tracker; elseif exist temp_min_dtm and temp_min_dtm_in_tracker < temp_min_dtm then temp_min_dtm := temp_min_dtm_in_tracker; endif; // Find the Maximum Dtm for the group of FOUND Total Trackers if not exist temp_max_dtm then temp_max_dtm := temp_max_dtm_in_tracker; elseif exist temp_max_dtm and temp_max_dtm_in_tracker > temp_max_dtm then temp_max_dtm := temp_max_dtm_in_tracker; endif; //if not exist temp_max_dtm enddo; //for KK //Store the entire list of dates from the found_total_tracker, not just the last one for LL in (1 seqto count found_total_tracker) do if exist average_instance.interval_begin_dtm_list then average_instance.interval_begin_dtm_list := average_instance.interval_begin_dtm_list, found_total_tracker[LL].interval_begin_dtm_list; else average_instance.interval_begin_dtm_list := found_total_tracker[LL].interval_begin_dtm_list; endif; //if LL enddo; //for LL //Calculate the Total Number of Days the Patient receives Medications // Since we are using the interval_begin_dtm_list // which are the beginning of the 24-hour interval, // we need to adjust the number of days by 24 hours // since the patient can receive medication until // the end of the 24-hour interval num_days_rounded_up := Truncate ((temp_max_dtm - temp_min_dtm + 24 hours )/ 1 day); //Calculate the Low and High Doses by dividing the doses with the number of days //AND Store the Doses temp_average_dose_low := temp_low / num_days_rounded_up; temp_average_dose_high := temp_high / num_days_rounded_up; // Find the Single Dose for the current Average_Tracker. found_med_data := med_data_list where (med_data_list.med_order_type = average_instance.med_order_type and med_data_list.order_med_name = average_instance.med_name and (med_data_list.order_med_route = average_instance.route or ((med_data_list.order_med_route is NULL) and (average_instance.route is NULL))) and med_data_list.order_med_units = average_instance.uom ); // Store Doses - no rounding for average dose for proper daily dose checking average_instance.average_dose_high := temp_average_dose_high; average_instance.average_dose_low := temp_average_dose_low; endif; //if found_total_tracker[1].med_order_type = "Complex Order" enddo; //for HH endif; //if med_data.med_order_type is in ("Regular", "IV-Additive") total_tracker_count := count total_tracker_list; total_tracker_list.sort_number := 1 seqto total_tracker_count; average_tracker_count := count average_tracker_list; average_tracker_list.sort_number := 1 seqto average_tracker_count; //Always Conclude True; Conclude True; ;; action: return total_tracker_list, average_tracker_list; ;; Urgency: 50;; end: