library OMTKLogic version '3.0.0'
include OMTKData version '3.0.0' called OMTKData
include ConversionFactors version '3.0.0' called ConversionFactors
codesystem "RXNORM": 'http://www.nlm.nih.gov/research/umls/rxnorm'
parameter ErrorLevel String default 'Warning'
define function Msg(code String, errorLevel String, message String):
{
code: code,
errorLevel: errorLevel,
message: message
}
define function ToUCUM(unit String):
case unit
when 'MG' then 'mg'
when 'MG/ACTUAT' then 'mg/{actuat}'
when 'MG/HR' then 'mg/h'
when 'MG/ML' then 'mg/mL'
else Message(null, true, 'OMTKLogic.ToUCUM.UnknownUnit', ErrorLevel, 'Unknown unit ' & unit)
end
define function ToUCUM_Msg(unit String):
unit U
let result: ToUCUM(U)
return {
result: result,
message:
if result is null then
Msg('OMTKLogic.ToUCUM.UnknownUnit', ErrorLevel, 'Unknown unit' & unit)
else
null
}
define function ToDaily(frequency Integer, period Quantity):
case period.unit
when 'h' then frequency * (24.0 / period.value)
when 'min' then frequency * (24.0 / period.value) * 60
when 's' then frequency * (24.0 / period.value) * 60 * 60
when 'd' then frequency * (24.0 / period.value) / 24
when 'wk' then frequency * (24.0 / period.value) / (24 * 7)
when 'mo' then frequency * (24.0 / period.value) / (24 * 30)
when 'a' then frequency * (24.0 / period.value) / (24 * 365)
when 'hour' then frequency * (24.0 / period.value)
when 'minute' then frequency * (24.0 / period.value) * 60
when 'second' then frequency * (24.0 / period.value) * 60 * 60
when 'day' then frequency * (24.0 / period.value) / 24
when 'week' then frequency * (24.0 / period.value) / (24 * 7)
when 'month' then frequency * (24.0 / period.value) / (24 * 30)
when 'year' then frequency * (24.0 / period.value) / (24 * 365)
when 'hours' then frequency * (24.0 / period.value)
when 'minutes' then frequency * (24.0 / period.value) * 60
when 'seconds' then frequency * (24.0 / period.value) * 60 * 60
when 'days' then frequency * (24.0 / period.value) / 24
when 'weeks' then frequency * (24.0 / period.value) / (24 * 7)
when 'months' then frequency * (24.0 / period.value) / (24 * 30)
when 'years' then frequency * (24.0 / period.value) / (24 * 365)
else Message(null, true, 'OMTKLogic.ToDaily.UnknownUnit', ErrorLevel, 'Unknown unit ' & period.unit)
end
define function ToDaily_Msg(frequency Integer, period Quantity):
frequency F
let result: ToDaily(frequency, period)
return {
result: result,
message:
if result is null then
Msg('OMTKLogic.ToDaily.UnknownUnit', ErrorLevel, 'Unknown unit ' & period.unit)
else
null
}
define function GetIngredients(rxNormCode Code):
OMTKData.DrugIngredients DI
where DI.drugCode = ToInteger(rxNormCode.code)
return {
rxNormCode: Code { code: ToString(DI.drugCode), system: 'http://www.nlm.nih.gov/research/umls/rxnorm', display: DI.drugName },
doseFormCode: Code { code: ToString(DI.doseFormCode), system: 'http://www.nlm.nih.gov/research/umls/rxnorm', display: DI.doseFormName },
ingredientCode: Code { code: ToString(DI.ingredientCode), system: 'http://www.nlm.nih.gov/research/umls/rxnorm', display: DI.ingredientName },
strength: Quantity {
value: DI.strengthValue,
unit: ToUCUM(DI.strengthUnit)
}
}
define function GetMedicationCode(concept Concept):
First(
((concept.codes) C
where C.system = 'http://www.nlm.nih.gov/research/umls/rxnorm'
return singleton from (
OMTKData.DrugIngredients DI
where DI.drugCode = ToInteger(C.code)
return Code {
code: ToString(DI.drugCode),
system: 'http://www.nlm.nih.gov/research/umls/rxnorm',
display: DI.drugName
}
)
) X
where X is not null
)
define function GetMedicationConceptName(concept Concept):
if concept.display is null then
First(
(concept.codes) C
where C.system = 'http://www.nlm.nih.gov/research/umls/rxnorm'
return GetMedicationName(C)
)
else
concept.display
define function GetMedicationName(rxNormCode Code):
if rxNormCode.display is null then
singleton from (
OMTKData.DrugIngredients DI
where DI.drugCode = ToInteger(rxNormCode.code)
return DI.drugName
)
else rxNormCode.display
define function GetIngredientName(ingredientCode Code):
if ingredientCode.display is null then
singleton from (
OMTKData.DrugIngredients DI
where DI.ingredientCode = ToInteger(ingredientCode.code)
return DI.ingredientName
)
else ingredientCode.display
define function GetDoseFormName(doseFormCode Code):
if doseFormCode.display is null then
singleton from (
OMTKData.DrugIngredients DI
where DI.doseFormCode = ToInteger(doseFormCode.code)
return DI.doseFormName
)
else doseFormCode.display
define function StripPer(unit String):
unit X
let split: Split(unit, '/'),
splitCount: Count(split)
return
if splitCount > 1 then
Substring(unit, 0, Length(unit) - Length(split[splitCount - 1]) - 1)
else
unit
define function GetDailyDose(ingredientCode Code, strength Quantity, doseFormCode Code, doseQuantity Quantity, dosesPerDay Decimal):
case
when dosesPerDay is null or doseQuantity is null or strength is null or strength.value is null or strength.unit is null then
{
result: null as Quantity,
description: 'Missing doses per day, dose quantity, and/or strength'
}
when ToInteger(doseFormCode.code) = 316987 then
if ToInteger(ingredientCode.code) in { 1819, 4337 } then
(Quantity { value: dosesPerDay * doseQuantity.value * strength.value, unit: strength.unit }) dailyDose
return {
result: dailyDose,
description: GetIngredientName(ingredientCode) & ' patch: ' & ToString(doseQuantity.value) & ' * ' & ToString(dosesPerDay) & '/d * ' & ToString(strength) & ' = ' + ToString(dailyDose)
}
else
{
result: null as Quantity,
description: 'Unknown patch ingredient: ' & ingredientCode.code & ':' & ingredientCode.display
}
when doseQuantity.unit in { 'mg', 'ug' } then
(Quantity { value: dosesPerDay * doseQuantity.value, unit: doseQuantity.unit }) dailyDose
return {
result: dailyDose,
description: GetIngredientName(ingredientCode) + ' ' + GetDoseFormName(doseFormCode) + ': ' + ToString(dosesPerDay) + '/d * ' + ToString(doseQuantity) + ' = ' + ToString(dailyDose)
}
when doseQuantity.unit = 'mL' and (PositionOf('/mL', strength.unit) = Length(strength.unit) - 3) then
(Quantity { value: dosesPerDay * doseQuantity.value * strength.value, unit: StripPer(strength.unit) }) dailyDose
return {
result: dailyDose,
description: GetIngredientName(ingredientCode) + ' ' + GetDoseFormName(doseFormCode) + ': ' + ToString(dosesPerDay) + '/d * ' + ToString(doseQuantity) + ' * ' & ToString(strength) & ' = ' + ToString(dailyDose)
}
else
(Quantity { value: dosesPerDay * doseQuantity.value * strength.value, unit: StripPer(strength.unit) }) dailyDose
return {
result: dailyDose,
description: GetIngredientName(ingredientCode) + ' ' + GetDoseFormName(doseFormCode) + ': ' + ToString(dosesPerDay) + '/d * ' + ToString(doseQuantity) + ' * ' + ToString(strength) + ' = ' + ToString(dailyDose)
}
end
define function CalculateMMEs(medications List<Tuple { rxNormCode Code, doseQuantity Quantity, dosesPerDay Decimal }>):
Flatten(
medications M
let Ingredients: GetIngredients(M.rxNormCode)
return
Ingredients I
let
adjustedDoseQuantity: M.doseQuantity,
dailyDose: GetDailyDose(I.ingredientCode, I.strength, I.doseFormCode, adjustedDoseQuantity, M.dosesPerDay),
factor: ConversionFactors.GetConversionFactor(I.ingredientCode, dailyDose.result, I.doseFormCode, M.dosesPerDay)
return {
rxNormCode: M.rxNormCode,
doseFormCode: I.doseFormCode,
doseQuantity: adjustedDoseQuantity,
dosesPerDay: M.dosesPerDay,
ingredientCode: I.ingredientCode,
strength: I.strength,
dailyDose: dailyDose.result,
dailyDoseDescription: dailyDose.description & (' * factor: ' + Coalesce(ToString(factor), 'No conversion factor available')),
conversionFactor: factor,
mme: Quantity(
Round(dailyDose.result.value * factor, 1),
'{MME}/d'
)
}
)
define function Quantity(value Decimal, unit String):
if value is not null then
Quantity { value: value, unit: unit }
else
null
|