Creado apartir del commit b888de6c92056de294456f581a56e25e734d4ab7 de develop
This commit is contained in:
@@ -0,0 +1,641 @@
|
||||
using adas_core.Application.Services.Interfaces;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.AppSettings;
|
||||
using adas_core.Domain.Models.Pumps;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Bson;
|
||||
using Serilog;
|
||||
|
||||
namespace adas_core.Application.Customizations.HPAZ;
|
||||
|
||||
public class CalculatedObservations(IServiceProvider serviceProvider) : ICalculatedObservations
|
||||
{
|
||||
private readonly Lazy<IAlarmService> _alarmService = serviceProvider.GetRequiredService<Lazy<IAlarmService>>();
|
||||
|
||||
|
||||
private readonly ApiSettings
|
||||
_apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>().Value; //apiSettings;
|
||||
|
||||
private readonly IConfigObservationService _configObservationService =
|
||||
serviceProvider.GetRequiredService<IConfigObservationService>(); //configObservationService;
|
||||
|
||||
private readonly ILogger<CalculatedObservations> _logger =
|
||||
serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||
|
||||
//Use GroupedObservation to avoid circular dependency with _observationService
|
||||
private readonly Lazy<IObservationService> _observationService =
|
||||
serviceProvider.GetRequiredService<Lazy<IObservationService>>(); //observationService;
|
||||
|
||||
private readonly List<string> _pressBloodArteryMean = ["TAm"];
|
||||
|
||||
|
||||
public Task CalculateActiveBolus(ObjectId patientId)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||
{
|
||||
return Task.FromResult<IEnumerable<PatientTreatment?>>(new List<PatientTreatment?>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps the obs to an event or alarm depending on its type and inserts it if needed
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type</typeparam>
|
||||
/// <param name="source">Observation</param>
|
||||
/// <param name="onlyByName">True if the observation needs to generate an alert</param>
|
||||
/// <returns>Mapped observation</returns>
|
||||
public async Task<T?> Map<T>(T source, bool onlyByName) where T : BasePatientObservation
|
||||
{
|
||||
_logger.LogDebug("Mapping {obsName} mode observation {obs}", source.Name, source);
|
||||
|
||||
if (source is not BasePatientObservationValue obs) return source;
|
||||
|
||||
var name = obs is PatientObservationAlarm obsAlarm ? obsAlarm.Event : obs.Name;
|
||||
name ??= string.Empty;
|
||||
|
||||
|
||||
//No generamos alertas si viene onlyByName
|
||||
if (name == "Resp_Mode")
|
||||
obs = CalculateVentilationMode(obs);
|
||||
|
||||
if (name is "Sattc" or "FiO2") await CalculateSf(obs, name);
|
||||
|
||||
if (name is "FiO2" or "P_VAM" or "PaO2_Tidal") await CalculateOxygenationIndex(obs, name);
|
||||
|
||||
if (name is "FiO2" or "PaO2_Tidal") await CalculatePf(obs, name);
|
||||
|
||||
if (name == "TEST_ALARMA") await _alarmService.Value.CalculateAlarmTest(obs, name);
|
||||
|
||||
obs = await CheckObsWithSameTimeExistsAndIncrementTime(obs);
|
||||
|
||||
if (obs is PatientObservation pobs)
|
||||
{
|
||||
pobs = await CheckAlarmConfig(pobs);
|
||||
return pobs as T;
|
||||
}
|
||||
|
||||
return obs as T;
|
||||
}
|
||||
|
||||
|
||||
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pumpObservation.Status is PumpEnum.Status.Alarm or PumpEnum.Status.Warning)
|
||||
{
|
||||
PatientObservation? patientObservation = null;
|
||||
string? name = null;
|
||||
|
||||
//La oclusión es para todos los tipos
|
||||
var volumetricAirOcclusionAlarm = _apiSettings.VolumetricAirOcclusionAlarm ?? null;
|
||||
|
||||
if (volumetricAirOcclusionAlarm != null && pumpObservation.AlarmType != null &&
|
||||
volumetricAirOcclusionAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||
{
|
||||
name = "VolumetricAirOcclusion";
|
||||
//alerta oclusión aire para bombas volumétricas
|
||||
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||
}
|
||||
|
||||
|
||||
var listInotropicMedicines = _apiSettings.InotropicMedicines ?? null;
|
||||
|
||||
if (listInotropicMedicines is { Count: > 0 } && pumpObservation.DrugName != null &&
|
||||
listInotropicMedicines.Contains(pumpObservation.DrugName)) //INOTRÓPICOS
|
||||
{
|
||||
var inotropicEndInfusionAlarm = _apiSettings.InotropicEndInfusionAlarm ?? null;
|
||||
|
||||
if (inotropicEndInfusionAlarm != null && pumpObservation.AlarmType != null &&
|
||||
inotropicEndInfusionAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||
{
|
||||
//Inotrópicos próxima a fin de infusión
|
||||
// Y
|
||||
//proximo fin de infusión, oclusión, y presencia aire….
|
||||
//Solo inotrópicos
|
||||
//Está en la línea 19 del excel y abarca la que hay en la línea 9
|
||||
// TODO: revisar en los logs que nombre de type (Buscar por crud xmlns)
|
||||
name = "InotropicEndInfusion";
|
||||
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var pumPressureAlarm = _apiSettings.PumPressureAlarm ?? null;
|
||||
|
||||
if (pumPressureAlarm != null && pumpObservation.AlarmType != null &&
|
||||
pumPressureAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||
{
|
||||
name = "Pressure";
|
||||
//alerta de presión(la alerta de la bomba se programa + -30mmHg por encima de la presión de la línea).
|
||||
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||
}
|
||||
|
||||
var endContinuousInfusionAlarm = _apiSettings.EndContinuousInfusionAlarm ?? null;
|
||||
|
||||
if (endContinuousInfusionAlarm != null && pumpObservation.AlarmType != null &&
|
||||
endContinuousInfusionAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||
{
|
||||
name = "EndContinuousInfusion";
|
||||
//próximo a fin de infusión /fin de infusión
|
||||
//información de bombas solo perfusión continua
|
||||
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||
}
|
||||
|
||||
var volumetricAirInLineAlarm = _apiSettings.VolumetricAirInLineAlarm ?? null;
|
||||
|
||||
if (volumetricAirInLineAlarm != null && pumpObservation.AlarmType != null &&
|
||||
volumetricAirInLineAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||
{
|
||||
name = "VolumetricAirInLine";
|
||||
//alerta aire para bombas volumétricas (burbujas de aire para la bomba)
|
||||
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (patientObservation != null && name != null)
|
||||
{
|
||||
_ = _observationService.Value.InsertObservation(patientObservation);
|
||||
_ = _alarmService.Value.SendAlarm(patientObservation, name, AlarmEnum.Name.Pump,
|
||||
AlarmEnum.Severity.None, AlarmEnum.Type.Auto);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error mapping alarm pump observation. Exception: {exMessage}", ex.Message);
|
||||
}
|
||||
|
||||
return pumpObservation;
|
||||
}
|
||||
|
||||
|
||||
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||
{
|
||||
if (string.IsNullOrEmpty(newObservation.Name))
|
||||
{
|
||||
_logger.LogError(
|
||||
"Error FixTimeInconsistencyWithLast new observation name is null or empty: {newObservation}.",
|
||||
newObservation);
|
||||
return newObservation;
|
||||
}
|
||||
|
||||
var lasObservations = await _observationService.Value.FindLastObservations(newObservation.PatientId, 1,
|
||||
[newObservation.Name]);
|
||||
var lastObservation = lasObservations.FirstOrDefault();
|
||||
|
||||
if (lastObservation != null && DateTime.Compare(
|
||||
new DateTime(lastObservation.Time.Year, lastObservation.Time.Month,
|
||||
lastObservation.Time.Day, lastObservation.Time.Hour,
|
||||
lastObservation.Time.Minute, lastObservation.Time.Second),
|
||||
new DateTime(newObservation.Time.Year, newObservation.Time.Month,
|
||||
newObservation.Time.Day, newObservation.Time.Hour,
|
||||
newObservation.Time.Minute, newObservation.Time.Second)
|
||||
) >= 0)
|
||||
newObservation.Time = lastObservation.Time.AddSeconds(1);
|
||||
|
||||
return newObservation;
|
||||
}
|
||||
|
||||
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToMap)
|
||||
{
|
||||
var mappedObsList = listToMap
|
||||
.Select(obs => obs.DeepCopy())
|
||||
.Select(obs => _configObservationService.Map(obs).Result)
|
||||
.Where(obs => obs != null)
|
||||
.ToList();
|
||||
|
||||
// mappedObsList contains observation mapped
|
||||
// Check blue code
|
||||
|
||||
_ = CalculateBlueCodeList(mappedObsList);
|
||||
|
||||
|
||||
return Task.FromResult(listToMap);
|
||||
}
|
||||
|
||||
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(alarmToInsert.EventId))
|
||||
obs.Code = alarmToInsert.EventId;
|
||||
|
||||
if (!string.IsNullOrEmpty(alarmToInsert.Event))
|
||||
obs.Name = alarmToInsert.Event;
|
||||
|
||||
obs.Value = alarmToInsert.Value;
|
||||
|
||||
return Task.FromResult(obs);
|
||||
}
|
||||
|
||||
Task ICalculatedObservations.SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
private async Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code, AlarmEnum.Type type)
|
||||
{
|
||||
await _alarmService.Value.SendAlarm(obs, name, code, AlarmEnum.Severity.None, type);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initial check to ignore old observations generating blue codes
|
||||
/// </summary>
|
||||
/// <param name="obs">Observation</param>
|
||||
/// <returns>True if it needs to be ignored</returns>
|
||||
private bool CheckIfObservationIsOlderAndShouldBeIgnored(PatientObservation obs)
|
||||
{
|
||||
if (obs.Time.ToUniversalTime().AddMinutes(_apiSettings.IgnoreCalcObservationsOlderInMinutesThan) <
|
||||
DateTime.UtcNow)
|
||||
{
|
||||
Log.Debug(
|
||||
"ignoring calc old observation: name:{obsName} obs_time:{obsTime} system_time {DateTimeNow} id:{obsId}",
|
||||
obs.Name ?? "null", obs.Time, DateTime.Now, obs.Id);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private async Task<PatientObservation> CheckAlarmConfig(PatientObservation pobs)
|
||||
{
|
||||
var configObs = await _configObservationService.Get(new PatientObservation
|
||||
{
|
||||
Name = pobs.Name,
|
||||
PatientId = pobs.PatientId
|
||||
});
|
||||
|
||||
pobs.Alarm = configObs?.Alarm ?? null;
|
||||
|
||||
return pobs;
|
||||
}
|
||||
|
||||
private static PatientObservation CreateAlarmObservation(string name, PatientObservation pobs)
|
||||
{
|
||||
return new PatientObservation
|
||||
{
|
||||
CodingSystem = "ADAS_ALARM",
|
||||
Code = name,
|
||||
Name = $"Alarm_{name}",
|
||||
Value = pobs.Value,
|
||||
PatientId = pobs.PatientId,
|
||||
Time = pobs.Time,
|
||||
Alarm = pobs.Alarm
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a blue code observation Lists needs to be generated and inserts it.
|
||||
/// </summary>
|
||||
/// <param name="obsList"></param>
|
||||
public async Task CalculateBlueCodeList(List<PatientObservation?>? obsList)
|
||||
{
|
||||
//Las 3 observaciones vienen siempre juntas en el mismo mensaje
|
||||
//Solo se comprueba si se cumplen 2 de las 3 condiciones
|
||||
|
||||
var condition = 0;
|
||||
var patientId = obsList?.FirstOrDefault()?.PatientId;
|
||||
if (patientId == null) return;
|
||||
|
||||
var fcObs = obsList?.FirstOrDefault(o => o is { Name: "FC" });
|
||||
var sattcObs = obsList?.FirstOrDefault(o => o is { Name: "Sattc" });
|
||||
var tamObs = obsList?.FirstOrDefault(o => o is { Name: "TAm" });
|
||||
|
||||
// FC < 60
|
||||
if (fcObs != null && !CheckIfObservationIsOlderAndShouldBeIgnored(fcObs) &&
|
||||
double.TryParse(fcObs.Value.ToString(), out var cardiacBeatRate) && cardiacBeatRate < 60)
|
||||
{
|
||||
Log.Debug("BlueCode condition: FC {fc} for patient: {obsPatientid} fc increase limit", cardiacBeatRate,
|
||||
fcObs.PatientId);
|
||||
condition++;
|
||||
}
|
||||
|
||||
// SpO2 < 80 (Sattc)
|
||||
if (sattcObs != null && !CheckIfObservationIsOlderAndShouldBeIgnored(sattcObs) &&
|
||||
double.TryParse(sattcObs.Value.ToString(), out var spO2Value) && spO2Value < 80)
|
||||
{
|
||||
Log.Debug("Blue code condition: SpO2 {sp} for patient: {obsPatientid} Sattc increase limit", spO2Value,
|
||||
sattcObs.PatientId);
|
||||
condition++;
|
||||
}
|
||||
|
||||
if (condition == 0) return;
|
||||
|
||||
// Early exit if 2 conditions are met
|
||||
if (condition == 2)
|
||||
{
|
||||
_ = SendBlueCode(fcObs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// TAm actual es un 50% por debajo de la medición de 30 seg antes
|
||||
if (tamObs != null && !CheckIfObservationIsOlderAndShouldBeIgnored(tamObs) &&
|
||||
double.TryParse(tamObs.Value.ToString(), out var tamObsValue))
|
||||
{
|
||||
// Buscamos el anterior
|
||||
var lastPressBloodObsList =
|
||||
await _observationService.Value.FindLastObservations(tamObs.PatientId, 1, _pressBloodArteryMean);
|
||||
var lastPressBloodObs = lastPressBloodObsList.FirstOrDefault();
|
||||
|
||||
// Diferencia entre la última observación es < 30 s
|
||||
if (lastPressBloodObs != null &&
|
||||
double.TryParse(lastPressBloodObs.Value.ToString(), out var lastPressBloodValue) &&
|
||||
(tamObs.Time - lastPressBloodObs.Time).TotalSeconds <= 35 &&
|
||||
tamObsValue <= lastPressBloodValue / 2)
|
||||
{
|
||||
Log.Debug("Blue code condition: TAm decrease limit over 30s for patient: {obsPatientid}",
|
||||
tamObs.PatientId);
|
||||
condition++;
|
||||
}
|
||||
}
|
||||
|
||||
if (condition >= 2) _ = SendBlueCode(tamObs);
|
||||
}
|
||||
|
||||
|
||||
private async Task SendBlueCode(PatientObservation? pobs)
|
||||
{
|
||||
if (pobs == null)
|
||||
return;
|
||||
|
||||
Log.Debug("Blue code Alarm for patient: {obsPatientid}", pobs.PatientId);
|
||||
|
||||
var blueCodeObservation = CreateAlarmObservation("BlueCode", pobs);
|
||||
|
||||
blueCodeObservation = await CheckAlarmConfig(blueCodeObservation);
|
||||
|
||||
_ = _observationService.Value.InsertObservation(blueCodeObservation);
|
||||
|
||||
_ = SendAlarm(blueCodeObservation, "BlueCode", AlarmEnum.Name.Blue, AlarmEnum.Type.Auto);
|
||||
}
|
||||
|
||||
|
||||
//PRVC : donde aparezca cambiar y mostrar en su lugar: VCRP
|
||||
//FLUJO ALTO: poner OAF en su lugar
|
||||
private BasePatientObservationValue CalculateVentilationMode(BasePatientObservationValue obs)
|
||||
{
|
||||
var value = obs is PatientObservationAlarm oAlarm ? oAlarm.Value
|
||||
: obs is PatientObservation o ? o.Value : null;
|
||||
|
||||
|
||||
if (value != null && value.ToString()!.Contains("PRVC"))
|
||||
obs.Value = value.ToString()!.Replace("PRVC", "VCRP");
|
||||
else if (value != null && value.ToString()!.Contains("FLUJ.ALTO")) obs.Value = "OAF";
|
||||
|
||||
_logger.LogDebug("Calculating patient id: {id} ventilation mode: {obsName}, value : {obsValue}", obs.PatientId,
|
||||
obs.Name, obs.Value);
|
||||
|
||||
return obs;
|
||||
}
|
||||
|
||||
//TODO duplicado con el calculated del 12o, sacar a un utils
|
||||
private async Task<BasePatientObservationValue> CheckObsWithSameTimeExistsAndIncrementTime(
|
||||
BasePatientObservationValue obs)
|
||||
{
|
||||
if (obs is not PatientObservation pobs) return obs;
|
||||
|
||||
var existObsWithSameTime =
|
||||
await _observationService.Value.FindAnyWithSameDate(pobs.PatientId, pobs.Time, pobs.Name);
|
||||
|
||||
if (existObsWithSameTime != null && existObsWithSameTime.Any()) pobs.Time = pobs.Time.AddSeconds(1);
|
||||
|
||||
return pobs;
|
||||
}
|
||||
|
||||
//S/F Calc ( craneal saturation / FiO2
|
||||
private async Task CalculateSf(BasePatientObservationValue obs, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
PatientObservation? saturation = null;
|
||||
PatientObservation? fio2 = null;
|
||||
|
||||
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["FiO2", "Sattc"]);
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "FiO2":
|
||||
fio2 = (PatientObservation)obs;
|
||||
saturation = values.FirstOrDefault(o => o.Name == "Sattc");
|
||||
break;
|
||||
|
||||
case "Sattc":
|
||||
saturation = (PatientObservation)obs;
|
||||
fio2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fio2 != null && saturation != null && !fio2.Expired &&
|
||||
double.TryParse(fio2.Value.ToString(), out var fio) && !saturation.Expired &&
|
||||
double.TryParse(saturation.Value.ToString(), out var sat) && sat <= 97)
|
||||
{
|
||||
if (fio == 0)
|
||||
{
|
||||
_logger.LogError("Error calculating SF. FiO2: {fio}", fio);
|
||||
return;
|
||||
}
|
||||
|
||||
var sfValue = sat / fio;
|
||||
|
||||
sfValue = Math.Round(sfValue, 4);
|
||||
|
||||
var sfObs = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Name = "Sattc_FiO2",
|
||||
CodingSystem = "ADAS",
|
||||
Value = sfValue,
|
||||
Time = obs.Time
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(sfObs);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error calculate S/F observation. Exception: {exMessage}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Oxygenation index is calculated => P_VAM x FiO2 x 100 / PaO2_Tidal
|
||||
/// the method is called when it receives P_VAM or FiO2 or PaO2_Tidal and tries to take the other values to perform the
|
||||
/// calculation if they are not
|
||||
/// in database then does nothing.
|
||||
/// </summary>
|
||||
public async Task CalculateOxygenationIndex(BasePatientObservationValue obs, string name)
|
||||
{
|
||||
var toSearchList = new List<string>();
|
||||
PatientObservation? pVam = null;
|
||||
PatientObservation? fiO2 = null;
|
||||
PatientObservation? paO2 = null;
|
||||
|
||||
toSearchList.AddRange(new List<string> { "P_VAM", "FiO2", "PaO2_Tidal" });
|
||||
|
||||
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
||||
|
||||
try
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "P_VAM":
|
||||
pVam = (PatientObservation)obs;
|
||||
fiO2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||
paO2 = values.FirstOrDefault(o => o.Name == "PaO2_Tidal");
|
||||
break;
|
||||
|
||||
case "FiO2":
|
||||
fiO2 = (PatientObservation)obs;
|
||||
pVam = values.FirstOrDefault(o => o.Name == "P_VAM");
|
||||
paO2 = values.FirstOrDefault(o => o.Name == "PaO2_Tidal");
|
||||
break;
|
||||
|
||||
case "PaO2_Tidal":
|
||||
paO2 = (PatientObservation)obs;
|
||||
fiO2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||
pVam = values.FirstOrDefault(o => o.Name == "P_VAM");
|
||||
break;
|
||||
}
|
||||
|
||||
//Controlar que FiO2 no haya expirada al recogerla
|
||||
if (fiO2 != null && paO2 != null && pVam != null &&
|
||||
int.TryParse(pVam.Value.ToString(), out var pvam) &&
|
||||
int.TryParse(fiO2.Value.ToString(), out var fio2) &&
|
||||
int.TryParse(paO2.Value.ToString(), out var pao2))
|
||||
{
|
||||
if (pao2 == 0)
|
||||
{
|
||||
_logger.LogError(
|
||||
"Error calculate Oxygenation Index observation. PaO2: {pao2}, observation: {obsName}", pao2,
|
||||
name);
|
||||
return;
|
||||
}
|
||||
|
||||
var oxygenationIndexValue = pvam * fio2 * 100 / pao2;
|
||||
|
||||
var oxygenationIndexObs = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Name = "Oxygenation_Index",
|
||||
CodingSystem = "ADAS",
|
||||
Value = oxygenationIndexValue,
|
||||
Time = obs.Time
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(oxygenationIndexObs);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error calculate Oxygenation Index observation. Exception: {exMessage}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
//P/F Calc ( PaO2_Tidal / FiO2
|
||||
private async Task CalculatePf(BasePatientObservationValue obs, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
PatientObservation? paO2 = null;
|
||||
PatientObservation? fio2 = null;
|
||||
|
||||
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
||||
["FiO2", "PaO2_Tidal"]);
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "FiO2":
|
||||
fio2 = (PatientObservation)obs;
|
||||
paO2 = values.FirstOrDefault(o => o.Name == "PaO2_Tidal");
|
||||
break;
|
||||
|
||||
case "PaO2_Tidal":
|
||||
paO2 = (PatientObservation)obs;
|
||||
fio2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fio2 != null && paO2 != null && !fio2.Expired && !paO2.Expired &&
|
||||
double.TryParse(paO2.Value.ToString(), out var pa) &&
|
||||
double.TryParse(fio2.Value.ToString(), out var fi))
|
||||
{
|
||||
if (fi == 0)
|
||||
{
|
||||
_logger.LogError("Error Calculating PF. FiO2 value is 0. Observation:{obs}", obs);
|
||||
return;
|
||||
}
|
||||
|
||||
var sfValue = pa / fi;
|
||||
|
||||
sfValue = Math.Round(sfValue, 4);
|
||||
|
||||
var sfObs = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Name = "PaO2_FiO2",
|
||||
CodingSystem = "ADAS",
|
||||
Value = sfValue,
|
||||
Time = obs.Time
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(sfObs);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error calculate P/F observation. Exception: {exMessage}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task<PatientObservation?> CreatePumpAlarmObservation(string name,
|
||||
PumpObservation pumpObservation)
|
||||
{
|
||||
var positionPump = pumpObservation.IsAux != null && !pumpObservation.IsAux.Value
|
||||
? $"Rack {pumpObservation.GatewayNumber} Bomba {pumpObservation.Number}"
|
||||
: $"Rack Aux {pumpObservation.GatewayNumber} Bomba {pumpObservation.Number}";
|
||||
|
||||
|
||||
|
||||
PatientObservation patientObservation = new()
|
||||
{
|
||||
CodingSystem = "ADAS_ALARM",
|
||||
Code = $"Pump_{name}",
|
||||
Name = $"Alarm_Pump_{name}",
|
||||
Value = pumpObservation.DrugName ?? positionPump,
|
||||
Time = pumpObservation.Time
|
||||
};
|
||||
|
||||
if (pumpObservation.PatientId != null)
|
||||
patientObservation.PatientId = pumpObservation.PatientId.Value;
|
||||
|
||||
return await CheckAlarmConfig(patientObservation);
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user