//////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2023 Dawson Dean // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //////////////////////////////////////////////////////////////////////////////// // // Online Calculator for Costa of Skipping Routine Labs in Hospitalized Patients // //////////////////////////////////////////////////////////////////////////////// // These are the main windows that we show/hide to expose different subgroups of funtions and outputs. var g_AboutWindowDivElement = null; var g_OutputWindowDivElement = null; var g_UserMsgWindowDivElement = null; var g_MainOutputElement = null; const NEWLINE_STR = "\n"; // These are generated by the Python code that did the initial analysis const AllAKISensitivityWithRandomSkipsArray = [0.8645, 0.7174, 0.58, 0.444, 0.3247, 0.2229, 0.1457, 0.0749, 0.0194]; const AKI1SensitivityWithRandomSkipsArray = [0.8655, 0.7167, 0.5847, 0.4483, 0.3288, 0.2316, 0.1575, 0.0797, 0.0224]; const AKI2SensitivityWithRandomSkipsArray = [0.8738, 0.7252, 0.5693, 0.4431, 0.3342, 0.2153, 0.1361, 0.0743, 0.0149]; const AKI3SensitivityWithRandomSkipsArray = [0.8289, 0.7039, 0.5592, 0.4013, 0.2566, 0.1513, 0.0461, 0.0263, 0.0]; //////////////////////////////////////////////////////////////////////////////// // // [TestClient_Init] // // This is called by the browser to initialize the entire UI. //////////////////////////////////////////////////////////////////////////////// function TestClient_Init() { // These are the main windows that we show/hide to expose different subgroups of funtions and outputs. g_AboutWindowDivElement = document.getElementById("AboutWindow"); g_UserMsgWindowDivElement = document.getElementById("UserMsgWindow"); g_OutputWindowDivElement = document.getElementById("OutputProgramWindow"); // The controls g_MainOutputElement = document.getElementById("MainOutputElement"); g_OutputWindowDivElement.style.display = "inline"; g_AboutWindowDivElement.style.display = "None"; g_UserMsgWindowDivElement.style.display = "inline"; g_MainOutputElement.value = ""; } // TestClient_Init //////////////////////////////////////////////////////////////////////////////// // // [TestClient_ShowWindow] // //////////////////////////////////////////////////////////////////////////////// function TestClient_ShowWindow(windowNameStr) { g_AboutWindowDivElement.style.display = "None"; g_UserMsgWindowDivElement.style.display = "None"; g_OutputWindowDivElement.style.display = "None"; //////////////////////////////////// if (windowNameStr == "Output") { g_OutputWindowDivElement.style.display = "inline"; //////////////////////////////////// } else if (windowNameStr == "About") { g_AboutWindowDivElement.style.display = "inline"; } } // TestClient_ShowWindow //////////////////////////////////////////////////////////////////////////////// // [TestClient_OnCloseChildWindow] //////////////////////////////////////////////////////////////////////////////// function TestClient_OnCloseChildWindow(button) { TestClient_ShowWindow("Output"); } // TestClient_OnCloseChildWindow //////////////////////////////////////////////////////////////////////////////// // [TestClient_ShowError] //////////////////////////////////////////////////////////////////////////////// function TestClient_ShowError(errMsg) { LogEvent("TestClient_ShowError. Error message: " + errMsg); } // TestClient_ShowError //////////////////////////////////////////////////////////////////////////////// // // [TestClient_StartTest] // //////////////////////////////////////////////////////////////////////////////// function TestClient_StartTest() { //LogEvent("TestClient_StartTest"); g_MainOutputElement.value = ""; /////////////////////////////////// // Get the inputs NumCBCPerYear = Util_GetInputNumber("CBCPerYear", -1); NumBMPPerYear = Util_GetInputNumber("BMPPerYear", -1); PercentLabReduction = Util_GetInputNumber("PercentLabReduction", -1); PercentAnemiaReduction = Util_GetInputNumber("PercentAnemiaReduction", -1); PercentTransfusionReduction = Util_GetInputNumber("PercentTransfusionReduction", -1); numExtraHospitalDayPerAKI = Util_GetInputNumber("ExtraHospitalDaysForAKI", 0); NumDollarsPerCBC = Util_GetInputNumber("DollarsPerCBC", -1); NumDollarsPerBMP = Util_GetInputNumber("DollarsPerBMP", -1); DollarsPerHospitalDay = Util_GetInputNumber("DollarsPerHospitalDay", -1); DollarsPerTransfusion = Util_GetInputNumber("DollarsPerTransfusion", -1); NumMildAnemiaPerYear = Util_GetInputNumber("MildAnemiaPerYear", -1); NumModAnemiaPerYear = Util_GetInputNumber("ModAnemiaPerYear", -1); NumSevereAnemiaPerYear = Util_GetInputNumber("SevereAnemiaPerYear", -1); HR12MonthMildAnemia = Util_GetInputNumber("HR12MonthMildAnemia", -1); HR12MonthModAnemia = Util_GetInputNumber("HR12MonthModAnemia", -1); HR12MonthSevereAnemia = Util_GetInputNumber("HR12MonthSevereAnemia", -1); NumTransfusionsPerYear = Util_GetInputNumber("TransfusionsPerYear", -1); NumKDIGO1PerYear = Util_GetInputNumber("NumKDIGO1PerYear", -1); NumKDIGO2PerYear = Util_GetInputNumber("NumKDIGO2PerYear", -1); NumKDIGO3PerYear = Util_GetInputNumber("NumKDIGO3PerYear", -1); /////////////////////////////////// // Print the header PrintStrToMainWin("Cost Calculator - Updated 8/5/2023"); PrintNumToMainWin("Num CBC per year: ", NumCBCPerYear); PrintNumToMainWin("Num BMP per year: ", NumBMPPerYear); PrintNumToMainWin("Num extra Days per AKI: ", numExtraHospitalDayPerAKI); PrintStrToMainWin("\n"); /////////////////////////////////// // Compute and Print Savings from Fewer Labs var fractionToSkip = PercentLabReduction / 100; var skippedBMPPerYear = NumBMPPerYear * fractionToSkip; var skippedCBCPerYear = NumCBCPerYear * fractionToSkip; PrintNumToMainWin("Num CBC Skipped per year: ", skippedCBCPerYear); PrintNumToMainWin("Num BMP Skipped per year: ", skippedBMPPerYear); var savingsBMPPerYear = skippedBMPPerYear * NumDollarsPerBMP; var savingsCBCPerYear = skippedCBCPerYear * NumDollarsPerCBC; var totalLabSavingsPerYear = savingsBMPPerYear + savingsCBCPerYear; PrintNumToMainWin("Cost Per BMP = ", NumDollarsPerBMP); PrintNumToMainWin("Cost Per CBC = ", NumDollarsPerCBC); PrintNumToMainWin("Savings In Skipped BMP Per Year = ", savingsBMPPerYear); PrintNumToMainWin("Savings In Skipped CBC Per Year = ", savingsCBCPerYear); PrintNumToMainWin("Total Lab Savings Per Year = ", totalLabSavingsPerYear); var fractionAnemiaAvoided = PercentAnemiaReduction / 100; var numMildAnemiaAvoidedPerYear = NumMildAnemiaPerYear * fractionAnemiaAvoided; var numModAnemiaAvoidedPerYear = NumModAnemiaPerYear * fractionAnemiaAvoided; var numSevereAnemiaAvoidedPerYear = NumSevereAnemiaPerYear * fractionAnemiaAvoided; PrintStrToMainWin(""); PrintNumToMainWin("Fraction Anemia Avoided = ", fractionAnemiaAvoided); PrintNumToMainWin("Num Mild Anemia Avoided Per Year = ", numMildAnemiaAvoidedPerYear); PrintNumToMainWin("Num Moderate Anemia Avoided Per Year = ", numModAnemiaAvoidedPerYear); PrintNumToMainWin("Num Severe Anemia Avoided Per Year = ", numSevereAnemiaAvoidedPerYear); var fractionTransfusionsAvoided = PercentTransfusionReduction / 100; var numTransfusionsAvoidedPerYear = NumTransfusionsPerYear * fractionTransfusionsAvoided; var dollarsSavedInTransfusionsPerYear = numTransfusionsAvoidedPerYear * DollarsPerTransfusion; var numAvoidedTransfusionReactionsPerYear = numTransfusionsAvoidedPerYear * 0.026; PrintStrToMainWin(""); PrintNumToMainWin("Num Transfusions Per Year = ", NumTransfusionsPerYear); PrintNumToMainWin("Fraction Transfusions Avoided = ", fractionTransfusionsAvoided); PrintNumToMainWin("Num Transfusions Avoided Per Year = ", numTransfusionsAvoidedPerYear); PrintNumToMainWin("Num Avoided Transfusion Reactions Per Year = ", numAvoidedTransfusionReactionsPerYear); PrintNumToMainWin("Savings In Transfusions Per Year = ", dollarsSavedInTransfusionsPerYear); totalDollarSavingsPerYear = totalLabSavingsPerYear + dollarsSavedInTransfusionsPerYear; PrintStrToMainWin(""); PrintNumToMainWin("Total Dollar Savings Per Year = ", totalDollarSavingsPerYear); PrintStrToMainWin(""); costInSemestersMedSchool = totalDollarSavingsPerYear / 44000.00; costInVancDoses = totalDollarSavingsPerYear / 20.00; costInDaysInpatient = totalDollarSavingsPerYear / 1687.00; PrintNumToMainWin("Total Dollar Savings Converted to Inpatient Days = ", costInDaysInpatient); PrintNumToMainWin("Total Dollar Savings Converted to Vanc Doses = ", costInVancDoses); PrintNumToMainWin("Total Dollar Savings Converted to Tuition Semesters = ", costInSemestersMedSchool); /////////////////////////////////// // Compute and Print Costs in Missed AKI PrintStrToMainWin(NEWLINE_STR + "================================"); PrintNumToMainWin("Num AKI-1 Per Year = ", NumKDIGO1PerYear); PrintNumToMainWin("Num AKI-2 Per Year = ", NumKDIGO2PerYear); PrintNumToMainWin("Num AKI-3 Per Year = ", NumKDIGO3PerYear); numMissedAKI1 = ComputeNumAKIsMissed(PercentLabReduction, AKI1SensitivityWithRandomSkipsArray, NumKDIGO1PerYear); numMissedAKI2 = ComputeNumAKIsMissed(PercentLabReduction, AKI2SensitivityWithRandomSkipsArray, NumKDIGO2PerYear); numMissedAKI3 = ComputeNumAKIsMissed(PercentLabReduction, AKI3SensitivityWithRandomSkipsArray, NumKDIGO3PerYear); PrintNumToMainWin("Num Missed AKI-1 = ", numMissedAKI1); PrintNumToMainWin("Num Missed AKI-2 = ", numMissedAKI2); PrintNumToMainWin("Num Missed AKI-3 = ", numMissedAKI3); totalNumMissedAKI = numMissedAKI1 + numMissedAKI2 + numMissedAKI3 PrintNumToMainWin("Num Missed AKI (all types) = ", totalNumMissedAKI); PrintStrToMainWin(""); ChertowCostForMissedAKI = totalNumMissedAKI * 8902.00; PrintNumToMainWin("Total Cost of Missed AKI using 8,902.00 dollars per AKI = ", ChertowCostForMissedAKI); PrintStrToMainWin(""); PrintNumToMainWin("Num Extra Hospital Days Per AKI = ", numExtraHospitalDayPerAKI); PrintNumToMainWin("DollarsPerHospitalDay = ", DollarsPerHospitalDay); var extraDaysForMissedAKI1 = numMissedAKI1 * numExtraHospitalDayPerAKI; var costForMissedAKI1 = extraDaysForMissedAKI1 * DollarsPerHospitalDay; PrintNumToMainWin("Extra Days For Missed AKI-1 = ", extraDaysForMissedAKI1); PrintNumToMainWin("Cost For Missed AKI-1 = ", costForMissedAKI1); var extraDaysForMissedAKI2 = numMissedAKI2 * numExtraHospitalDayPerAKI; var costForMissedAKI2 = extraDaysForMissedAKI2 * DollarsPerHospitalDay; PrintNumToMainWin("Extra Days For Missed AKI-2 = ", extraDaysForMissedAKI2); PrintNumToMainWin("Cost For Missed AKI-2 = ", costForMissedAKI2); var extraDaysForMissedAKI3 = numMissedAKI3 * numExtraHospitalDayPerAKI; var costForMissedAKI3 = extraDaysForMissedAKI3 * DollarsPerHospitalDay; PrintNumToMainWin("Extra Days For Missed AKI-3 = ", extraDaysForMissedAKI3); PrintNumToMainWin("Cost For Missed AKI-3 = ", costForMissedAKI3); totalCostForMissedAKI = costForMissedAKI1 + costForMissedAKI2 + costForMissedAKI3; PrintStrToMainWin(""); PrintNumToMainWin("Total Days For Missed AKI = ", (extraDaysForMissedAKI1 + extraDaysForMissedAKI2 + extraDaysForMissedAKI3)); PrintNumToMainWin("Total Cost For Missed AKI = ", totalCostForMissedAKI); } // TestClient_StartTest //////////////////////////////////////////////////////////////////////////////// // // [ComputeNumAKIsMissed] // //////////////////////////////////////////////////////////////////////////////// function ComputeNumAKIsMissed(percentLabReduction, sensitivityForEachSkippedPercent, numAKIPerYear) { // Subtract 1 because the array is 0-based and started with 10% at index 0 var AccuratePercentageIndex = (percentLabReduction / 10) - 1; var lowerIndex = Math.floor(AccuratePercentageIndex); var upperIndex = Math.ceil(AccuratePercentageIndex); var LowerSensitivity = sensitivityForEachSkippedPercent[lowerIndex]; var UpperSensitivity = sensitivityForEachSkippedPercent[upperIndex]; var DeltaSensitivity = UpperSensitivity - LowerSensitivity; var offsetIntoIndex = AccuratePercentageIndex - lowerIndex; var AKISensitivity = LowerSensitivity + (offsetIntoIndex * DeltaSensitivity); var numMissedAKI = numAKIPerYear * (1 - AKISensitivity); return(numMissedAKI); } // ComputeNumAKIsMissed //////////////////////////////////////////////////////////////////////////////// // // [PrintNumToMainWin] // //////////////////////////////////////////////////////////////////////////////// function PrintNumToMainWin(prefixStr, numValue) { numValue = numValue.toFixed(2); var numStr = numValue.toString(); // Insert commas - this is not a great idea outside the US. numStr = numStr.replace(/\B(?=(\d{3})+(?!\d))/g, ','); PrintStrToMainWin(prefixStr + numStr); } // PrintNumToMainWin //////////////////////////////////////////////////////////////////////////////// // // [PrintStrToMainWin] // //////////////////////////////////////////////////////////////////////////////// function PrintStrToMainWin(prefixStr) { g_MainOutputElement.value += prefixStr + NEWLINE_STR; } // PrintStrToMainWin