Page MenuHomePhorge

sa-ews2.cpp
No OneTemporary

Size
35 KB
Referenced Files
None
Subscribers
None

sa-ews2.cpp

//===-- apps/sa-ews2/sa-ews2.cpp --------------------------------*- C++ -*-===//
//
// The RoSA Framework -- Application SA-EWS2
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file apps/sa-ews2/sa-ews2.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
/// Maximilian Goetzinger (maxgot@utu.fi)
///
/// \date 2020
///
/// \brief The application SA-EWS2 implements the case study from the paper:
/// M. Götzinger, A. Anzanpour, I. Azimi, N. TaheriNejad, A. Jantsch,
/// A. M. Rahmani, and P. Liljeberg: Confidence-Enhanced Early Warning Score
/// Based on Fuzzy Logic. DOI: 10.1007/s11036-019-01324-5
//===----------------------------------------------------------------------===//
#include "rosa/agent/RangeConfidence.hpp"
#include "rosa/agent/CrossCombinator.h"
#include "rosa/agent/ReliabilityConfidenceCombination.h"
#include "rosa/config/version.h"
#include "rosa/app/Application.hpp"
#include "rosa/support/csv/CSVReader.hpp"
#include "rosa/support/csv/CSVWriter.hpp"
#include "rosa/support/iterator/split_tuple_iterator.hpp"
#include "cxxopts/cxxopts.hpp"
#include <fstream>
using namespace rosa;
using namespace rosa::agent;
using namespace rosa::app;
using namespace rosa::terminal;
using namespace rosa::csv;
using namespace rosa::iterator;
const std::string AppName = "SA-EWS2";
/// Representation type of warning levels.
/// \note Make sure it suits all defined enumeration values.
using WarningScoreType = uint8_t;
/// Warning levels for abstraction.
///
/// \note Conversion functions \c feedbackFromSymbol(), \c feedbackToSymbol(),
/// and the master input handler generated by \c createLowLevelAgent() expect
/// enumeration values to constitute a consecutive range of non-negative
/// integers starting from \c 0.
enum WarningScore : WarningScoreType {
No = 0,
Low = 1,
High = 2,
Emergency = 3
};
/// Vector with all possible warning levels.
std::vector<WarningScoreType> warningScores = {No, Low, High, Emergency};
/// Type used to represent reliability values.
using ReliabilityType = double;
/// The result type of low-level functions.
using WarningValue = AppTuple<WarningScoreType, ReliabilityType>;
/// The helper struct used by the Likeliness Combinator to provide feedback.
using EWSSymbol = Symbol<WarningScoreType, ReliabilityType>;
/// All feedback calculated by Likelienss Combinator for one slave.
using EWSFeedback = std::vector<EWSSymbol>;
/// The feedback provided by master to a slave agent.
/// The tuple contains the reliability feedback for each warning level in order.
using FeedbackTuple = AppTuple<ReliabilityType, ReliabilityType,
ReliabilityType, ReliabilityType>;
/// Converts feedback calculated by Likeliness Combinator into a tuple that can
/// be sent between agents.
///
/// \param F calculated standard feedback
///
/// \return feedback tuple
FeedbackTuple feedbackFromSymbol(const EWSFeedback &F) {
// Fill a map with feedback for warning levels.
std::map<WarningScoreType, ReliabilityType> M;
std::for_each(F.cbegin(), F.cend(), [&M](const EWSSymbol &S) {
M.insert({S.Identifier, S.Likeliness});
});
// Expect feedback for all warning levels.
ASSERT(M.size() == warningScores.size());
return {M[No], M[Low], M[High], M[Emergency]};
}
/// Converts feedback tuple to standard format used by the Likeliness Combinator.
///
/// \param F feedback tuple
///
/// \return feedback in standard format
EWSFeedback feedbackToSymbol(const FeedbackTuple &F) {
return {{No, std::get<No>(F)},
{Low, std::get<Low>(F)},
{High, std::get<High>(F)},
{Emergency, std::get<Emergency>(F)}};
}
/// Helper function creating an application sensor and setting its execution
/// policy for decimation.
///
/// \note The sensors are created without defining a normal generator function,
/// which is suitable for simulation only.
///
/// \tparam T type of values for the sensor to generate
///
/// \param App the application to create the sensor in
/// \param Name name of the new sensor
/// \param Decimation the decimation parameter
///
/// \return handle for the new sensor
template <typename T>
AgentHandle createSensor(std::unique_ptr<Application> &App,
const std::string &Name, const size_t Decimation) {
AgentHandle Sensor = App->createSensor<T>(Name);
App->setExecutionPolicy(Sensor, AppExecutionPolicy::decimation(Decimation));
return Sensor;
}
/// Helper function creating an application agent for pre-processing sensory
/// values and setting its execution policy for decimation.
///
/// Received values are assessed for reliability and abstracted into a \c
/// WarningScore. The result of the processing function is a pair of assessed
/// reliability and abstracted values.
///
/// The agent also accepts feedback from its master, which is taken into account
/// for the pre-processing of later sensory values.
///
/// \note The result, \c WarningScore, is returned as \c WarningScoreType
/// because enumeration types are not integrated into built-in types. Hence, a
/// master to these agents receives its input as \c WarningScoreType values, and
/// may cast them to \c WarningScore explicitly.
///
/// \tparam T type of values to receive from the sensor
///
/// \param App the application to create the agent in
/// \param Name name of the new agent
/// \param Decimation the decimation parameter
/// \param R reliability/confidence combination to use
///
/// \return handle for the new agent
template <typename T>
AgentHandle
createLowLevelAgent(std::unique_ptr<Application> &App, const std::string &Name,
const size_t Decimation,
ReliabilityAndConfidenceCombination<T, WarningScoreType,
ReliabilityType> &R) {
using masterhandler = std::function<void(std::pair<FeedbackTuple, bool>)>;
using result = Optional<WarningValue>;
using input = AppTuple<T>;
using handler = std::function<result(std::pair<input, bool>)>;
AgentHandle Agent = App->createAgent(
Name, masterhandler([&, Name](std::pair<FeedbackTuple, bool> I) {
LOG_INFO_STREAM << "\n******\n"
<< Name << " " << (I.second ? "<New>" : "<Old>")
<< " master feedback: ["
<< PRINTABLE(std::get<No>(I.first)) << ", "
<< PRINTABLE(std::get<Low>(I.first)) << ", "
<< PRINTABLE(std::get<High>(I.first)) << ", "
<< PRINTABLE(std::get<Emergency>(I.first))
<< "]\n******\n";
const auto Feedback = feedbackToSymbol(I.first);
R.feedback(Feedback);
}),
handler([&, Name](std::pair<input, bool> I) -> result {
LOG_INFO_STREAM << "\n******\n"
<< Name << " " << (I.second ? "<New>" : "<Old>")
<< " value: " << PRINTABLE(std::get<0>(I.first))
<< "\n******\n";
const auto SensorValue = std::get<0>(I.first);
const auto AbstractedValue = R.bestSymbol(SensorValue);
return {WarningValue(AbstractedValue.Identifier,
AbstractedValue.Likeliness)};
}));
App->setExecutionPolicy(Agent, AppExecutionPolicy::decimation(Decimation));
return Agent;
}
/// Helper function to print an error message in red color to the terminal and
/// exit from the application.
///
/// \note The function never returns as it calles `exit()`.
///
/// \param Error error message
/// \param ExitCode exit code to return from the application
void logErrorAndExit(const std::string &Error, const int ExitCode) {
LOG_ERROR_STREAM << Color::Red << Error << Color::Default << std::endl;
exit(ExitCode);
}
int main(int argc, char *argv[]) {
LOG_INFO_STREAM << '\n'
<< library_string() << " -- " << Color::Red << AppName
<< " app" << Color::Default << '\n';
/// Paths for the CSV files for simulation.
///
///@{
std::string DataCSVPath;
std::string ScoreCSVPath;
///@}
/// Whether CSV files have header row at the beginning.
bool CSVHeader = false;
/// Delimiter character in CSV files.
char CSVDelimiter = ',';
/// Decimation of sensors and agents.
size_t Decimation = 1;
/// How many cycles of simulation to perform.
size_t NumberOfSimulationCycles = 128;
// Handle command-line arguments.
try {
cxxopts::Options Options(argv[0], library_string() + " -- " + AppName);
Options.add_options()("i,input",
"Path for the CSV file providing input data",
cxxopts::value(DataCSVPath), "file")
("o,output",
"Path for the CSV file to write output scores",
cxxopts::value(ScoreCSVPath), "file")
("header", "CSV files have header row",
cxxopts::value(CSVHeader)->default_value("false"))
("delimiter", "CSV delimiter character",
cxxopts::value(CSVDelimiter)->default_value(","), "char")
("d,decimation", "Decimation of sensors and agents",
cxxopts::value(Decimation)->default_value("1"), "int")
("c,cycles", "Number of simulation cycles to perform",
cxxopts::value(NumberOfSimulationCycles)->default_value("16"), "int")
("h,help", "Print usage");
auto Args = Options.parse(argc, argv);
if (Args.count("help")) {
LOG_INFO_STREAM << '\n' << Options.help() << std::endl;
exit(0);
}
if (Args.count("input") == 0) {
throw std::invalid_argument("Argument --input must be defined.");
}
if (Args.count("output") == 0) {
throw std::invalid_argument("Argument --output must be defined.");
}
} catch (const cxxopts::OptionException &e) {
logErrorAndExit(e.what(), 1);
} catch (const std::invalid_argument &e) {
logErrorAndExit(e.what(), 1);
}
std::unique_ptr<Application> App = Application::create(AppName);
//
// Relevant types and definitions.
//
using HRType = float;
using HRConfidence =
RangeConfidence<HRType, WarningScoreType, ReliabilityType>;
using HRParFun = PartialFunction<HRType, ReliabilityType>;
using HRLinFun = LinearFunction<HRType, ReliabilityType>;
using BRType = float;
using BRConfidence =
RangeConfidence<BRType, WarningScoreType, ReliabilityType>;
using BRParFun = PartialFunction<BRType, ReliabilityType>;
using BRLinFun = LinearFunction<BRType, ReliabilityType>;
using SpO2Type = int32_t;
using SpO2Confidence =
RangeConfidence<SpO2Type, WarningScoreType, ReliabilityType>;
using SpO2ParFun = PartialFunction<SpO2Type, ReliabilityType>;
using SpO2LinFun = LinearFunction<SpO2Type, ReliabilityType>;
using BPSysType = float;
using BPSysConfidence =
RangeConfidence<BPSysType, WarningScoreType, ReliabilityType>;
using BPSysParFun = PartialFunction<BPSysType, ReliabilityType>;
using BPSysLinFun = LinearFunction<BPSysType, ReliabilityType>;
using BodyTempType = float;
using BodyTempConfidence =
RangeConfidence<BodyTempType, WarningScoreType, ReliabilityType>;
using BodyTempParFun = PartialFunction<BodyTempType, ReliabilityType>;
using BodyTempLinFun = LinearFunction<BodyTempType, ReliabilityType>;
//
// Create application sensors.
//
LOG_INFO("Creating sensors.");
// All sensors are created without defining a normal generator function, but
// with the default value of the second argument. That, however, requires the
// data type to be explicitly defined. This is good for simulation only.
AgentHandle HRSensor = createSensor<HRType>(App, "HR Sensor", Decimation);
AgentHandle BRSensor = createSensor<BRType>(App, "BR Sensor", Decimation);
AgentHandle SpO2Sensor =
createSensor<SpO2Type>(App, "SpO2 Sensor", Decimation);
AgentHandle BPSysSensor =
createSensor<BPSysType>(App, "BPSys Sensor", Decimation);
AgentHandle BodyTempSensor =
createSensor<BodyTempType>(App, "BodyTemp Sensor", Decimation);
//
// Create functionalities.
//
LOG_INFO("Creating Functionalities for Agents.");
//
// Define reliabilities and confindences.
//
const size_t TimeStep = 1;
const size_t HistoryLength = 32;
using TimeParFun = PartialFunction<size_t, ReliabilityType>;
using TimeLinFun = LinearFunction<size_t, ReliabilityType>;
std::shared_ptr<Abstraction<size_t, ReliabilityType>> TimeConfidence(
new TimeParFun({{{std::numeric_limits<size_t>::lowest(), 0},
std::make_shared<TimeLinFun>(1, 0)},
{{0, HistoryLength},
std::make_shared<TimeLinFun>(0, 1, HistoryLength, 0)}},
0));
ReliabilityAndConfidenceCombination<HRType, WarningScoreType, ReliabilityType>
HRReliability;
HRReliability.setIdentifiers(warningScores);
HRReliability.setHistoryLength(HistoryLength);
HRReliability.setTimeStep(TimeStep);
HRReliability.setTimeFunctionForLikelinessFunction(TimeConfidence);
std::shared_ptr<HRConfidence> HRConf(new HRConfidence(
{{No, HRParFun({{{56.5f, 62.5f},
std::make_shared<HRLinFun>(56.5f, 0, 62.5f, 1)},
{{62.5f, 97.5f}, std::make_shared<HRLinFun>(1, 0)},
{{97.5f, 103.5f},
std::make_shared<HRLinFun>(97.5f, 1, 103.5f, 0)}},
0)},
{Low,
HRParFun(
{{{47.5f, 53.5f}, std::make_shared<HRLinFun>(47.5f, 0, 53.5f, 1)},
{{53.5f, 56.5f}, std::make_shared<HRLinFun>(1, 0)},
{{56.5f, 62.5f}, std::make_shared<HRLinFun>(56.5f, 1, 62.5f, 0)},
{{97.5f, 103.5f}, std::make_shared<HRLinFun>(97.5f, 0, 103.5f, 1)},
{{103.5f, 107.5f}, std::make_shared<HRLinFun>(1, 0)},
{{107.5f, 113.5f},
std::make_shared<HRLinFun>(107.5f, 1, 113.5f, 0)}},
0)},
{High,
HRParFun(
{{{36.5f, 42.5f}, std::make_shared<HRLinFun>(36.5f, 0, 42.5f, 1)},
{{42.5f, 47.5f}, std::make_shared<HRLinFun>(1, 0)},
{{47.5f, 53.5f}, std::make_shared<HRLinFun>(47.5f, 1, 53.5f, 0)},
{{107.5f, 113.5f},
std::make_shared<HRLinFun>(107.5f, 0, 113.5f, 1)},
{{113.5f, 126.5f}, std::make_shared<HRLinFun>(1, 0)},
{{126.5f, 132.5f},
std::make_shared<HRLinFun>(126.5f, 1, 132.5f, 0)}},
0)},
{Emergency,
HRParFun(
{{{36.5f, 42.5f}, std::make_shared<HRLinFun>(36.5f, 1, 42.5f, 0)},
{{42.5f, 126.5f}, std::make_shared<HRLinFun>(0, 0)},
{{126.5f, 132.5f},
std::make_shared<HRLinFun>(126.5f, 0, 132.5f, 1)}},
1)}}));
HRReliability.setConfidenceFunction(HRConf);
std::shared_ptr<Abstraction<HRType, ReliabilityType>> HRAbsRel(
new HRParFun({{{0.f, 200.f}, std::make_shared<HRLinFun>(1, 0)},
{{200.f, 300.f}, std::make_shared<HRLinFun>(200.f, 1, 300.f, 0)}},
0));
HRReliability.setAbsoluteReliabilityFunction(HRAbsRel);
std::shared_ptr<Abstraction<HRType, ReliabilityType>> HRRelSlope(new HRParFun(
{{{-200.f, -100.f}, std::make_shared<HRLinFun>(-200.f, 0, -100.f, 1)},
{{-100.f, 100.f}, std::make_shared<HRLinFun>(1, 0)},
{{100.f, 200.f}, std::make_shared<HRLinFun>(100.f, 1, 200.f, 0)}},
0));
HRReliability.setReliabilitySlopeFunction(HRRelSlope);
ReliabilityAndConfidenceCombination<BRType, WarningScoreType, ReliabilityType>
BRReliability;
BRReliability.setIdentifiers(warningScores);
BRReliability.setHistoryLength(HistoryLength);
BRReliability.setTimeStep(TimeStep);
BRReliability.setTimeFunctionForLikelinessFunction(TimeConfidence);
std::shared_ptr<BRConfidence> BRConf(new BRConfidence(
{{No,
BRParFun(
{{{7.5f, 9.5f}, std::make_shared<BRLinFun>(7.5f, 0, 9.5f, 1)},
{{9.5f, 13.5f}, std::make_shared<BRLinFun>(1, 0)},
{{13.5f, 15.5f}, std::make_shared<BRLinFun>(12.5f, 1, 15.5f, 0)}},
0)},
{Low,
BRParFun(
{{{13.5f, 15.5f}, std::make_shared<BRLinFun>(13.5f, 0, 15.5f, 1)},
{{15.5f, 19.5f}, std::make_shared<BRLinFun>(1, 0)},
{{19.5f, 21.5f}, std::make_shared<BRLinFun>(19.5f, 1, 21.5f, 0)}},
0)},
{High,
BRParFun(
{{{std::numeric_limits<BRType>::lowest(), 7.5f},
std::make_shared<BRLinFun>(1, 0)},
{{7.5f, 9.5f}, std::make_shared<BRLinFun>(7.5f, 1, 9.5f, 0)},
{{19.5f, 21.5f}, std::make_shared<BRLinFun>(19.5f, 0, 21.5f, 1)},
{{21.5f, 28.5f}, std::make_shared<BRLinFun>(1, 0)},
{{28.5f, 30.5f}, std::make_shared<BRLinFun>(28.5f, 1, 30.5f, 0)}},
0)},
{Emergency, BRParFun({{{std::numeric_limits<BRType>::lowest(), 28.5f},
std::make_shared<BRLinFun>(0, 0)},
{{28.5f, 30.5f},
std::make_shared<BRLinFun>(28.5f, 0, 30.5f, 1)}},
1)}}));
BRReliability.setConfidenceFunction(BRConf);
std::shared_ptr<Abstraction<BRType, ReliabilityType>> BRAbsRel(
new BRParFun({{{0.f, 40.f}, std::make_shared<BRLinFun>(1, 0)},
{{40.f, 60.f}, std::make_shared<BRLinFun>(40.f, 1, 60.f, 0)}},
0));
BRReliability.setAbsoluteReliabilityFunction(BRAbsRel);
std::shared_ptr<Abstraction<BRType, ReliabilityType>> BRRelSlope(
new BRParFun({{{-30.f, -20.f}, std::make_shared<BRLinFun>(-30.f, 0, -20.f, 1)},
{{-20.f, 20.f}, std::make_shared<BRLinFun>(1, 0)},
{{20.f, 30.f}, std::make_shared<BRLinFun>(20.f, 1, 30.f, 0)}},
0));
BRReliability.setReliabilitySlopeFunction(BRRelSlope);
ReliabilityAndConfidenceCombination<SpO2Type, WarningScoreType, ReliabilityType>
SpO2Reliability;
SpO2Reliability.setIdentifiers(warningScores);
SpO2Reliability.setHistoryLength(HistoryLength);
SpO2Reliability.setTimeStep(TimeStep);
SpO2Reliability.setTimeFunctionForLikelinessFunction(TimeConfidence);
std::shared_ptr<SpO2Confidence> SpO2Conf(new SpO2Confidence(
{{No, SpO2ParFun({{{93, 96}, std::make_shared<SpO2LinFun>(93, 0, 96, 1)},
{{96, std::numeric_limits<SpO2Type>::max()},
std::make_shared<SpO2LinFun>(1, 0)}},
0)},
{Low,
SpO2ParFun({{{88, 91}, std::make_shared<SpO2LinFun>(88, 0, 91, 1)},
{{91, 93}, std::make_shared<SpO2LinFun>(1, 0)},
{{93, 96}, std::make_shared<SpO2LinFun>(93, 1, 96, 0)}},
0)},
{High,
SpO2ParFun({{{83, 86}, std::make_shared<SpO2LinFun>(83, 0, 86, 1)},
{{86, 88}, std::make_shared<SpO2LinFun>(1, 0)},
{{88, 91}, std::make_shared<SpO2LinFun>(88, 1, 91, 0)}},
0)},
{Emergency,
SpO2ParFun({{{83, 86}, std::make_shared<SpO2LinFun>(83, 1, 86, 0)},
{{86, std::numeric_limits<SpO2Type>::max()},
std::make_shared<SpO2LinFun>(0, 0)}},
1)}}));
SpO2Reliability.setConfidenceFunction(SpO2Conf);
std::shared_ptr<Abstraction<SpO2Type, ReliabilityType>> SpO2AbsRel(
new SpO2ParFun(
{
{{0, 100}, std::make_shared<SpO2LinFun>(1, 0)},
},
0));
SpO2Reliability.setAbsoluteReliabilityFunction(SpO2AbsRel);
std::shared_ptr<Abstraction<SpO2Type, ReliabilityType>> SpO2RelSlope(
new SpO2ParFun({{{-8, -5}, std::make_shared<SpO2LinFun>(-8, 0, -5, 1)},
{{-5, 5}, std::make_shared<SpO2LinFun>(1, 0)},
{{5, 8}, std::make_shared<SpO2LinFun>(5, 1, 8, 0)}},
0));
SpO2Reliability.setReliabilitySlopeFunction(SpO2RelSlope);
ReliabilityAndConfidenceCombination<BPSysType, WarningScoreType, ReliabilityType>
BPSysReliability;
BPSysReliability.setIdentifiers(warningScores);
BPSysReliability.setHistoryLength(HistoryLength);
BPSysReliability.setTimeStep(TimeStep);
BPSysReliability.setTimeFunctionForLikelinessFunction(TimeConfidence);
std::shared_ptr<BPSysConfidence> BPSysConf(new BPSysConfidence(
{{No,
BPSysParFun({{{97.5f, 103.5f},
std::make_shared<BPSysLinFun>(97.5f, 0, 103.5f, 1)},
{{103.5f, 146.5f}, std::make_shared<BPSysLinFun>(1, 0)},
{{146.5f, 152.5f},
std::make_shared<BPSysLinFun>(146.5f, 1, 152.5f, 0)}},
0)},
{Low,
BPSysParFun({{{77.5f, 83.5f},
std::make_shared<BPSysLinFun>(77.5f, 0, 83.5f, 1)},
{{83.5f, 97.5f}, std::make_shared<BPSysLinFun>(1, 0)},
{{97.5f, 103.5f},
std::make_shared<BPSysLinFun>(97.5f, 1, 103.5f, 0)},
{{146.5f, 152.5f},
std::make_shared<BPSysLinFun>(146.5f, 0, 152.5f, 1)},
{{152.5f, 166.5f}, std::make_shared<BPSysLinFun>(1, 0)},
{{166.5f, 172.5f},
std::make_shared<BPSysLinFun>(166.5f, 1, 172.5f, 0)}},
0)},
{High,
BPSysParFun({{{66.5f, 72.5f},
std::make_shared<BPSysLinFun>(66.5f, 0, 72.5f, 1)},
{{72.5f, 77.5f}, std::make_shared<BPSysLinFun>(1, 0)},
{{77.5f, 83.5f},
std::make_shared<BPSysLinFun>(77.5f, 1, 83.5f, 0)},
{{166.5f, 172.5f},
std::make_shared<BPSysLinFun>(166.5f, 0, 172.5f, 1)},
{{172.5f, 176.5f}, std::make_shared<BPSysLinFun>(1, 0)},
{{176.5f, 182.5f},
std::make_shared<BPSysLinFun>(176.5f, 1, 182.5f, 0)}},
0)},
{Emergency,
BPSysParFun({{{66.5f, 72.5f},
std::make_shared<BPSysLinFun>(66.5f, 1, 72.5f, 0)},
{{72.5f, 176.5f}, std::make_shared<BPSysLinFun>(0, 0)},
{{176.5f, 182.5f},
std::make_shared<BPSysLinFun>(176.5f, 0, 182.5f, 1)}},
1)}}));
BPSysReliability.setConfidenceFunction(BPSysConf);
std::shared_ptr<Abstraction<BPSysType, ReliabilityType>> BPSysAbsRel(
new BPSysParFun(
{{{0.f, 260.f}, std::make_shared<BPSysLinFun>(1, 0)},
{{260.f, 400.f}, std::make_shared<BPSysLinFun>(260.f, 1, 400.f, 0)}},
0));
BPSysReliability.setAbsoluteReliabilityFunction(BPSysAbsRel);
std::shared_ptr<Abstraction<BPSysType, ReliabilityType>> BPSysRelSlope(
new BPSysParFun(
{{{-100.f, -50.f}, std::make_shared<BPSysLinFun>(-100.f, 0, -50.f, 1)},
{{-50.f, 50.f}, std::make_shared<BPSysLinFun>(1, 0)},
{{50.f, 100.f}, std::make_shared<BPSysLinFun>(50.f, 1, 100.f, 0)}},
0));
BPSysReliability.setReliabilitySlopeFunction(BPSysRelSlope);
ReliabilityAndConfidenceCombination<BodyTempType, WarningScoreType,
ReliabilityType>
BodyTempReliability;
BodyTempReliability.setIdentifiers(warningScores);
BodyTempReliability.setHistoryLength(HistoryLength);
BodyTempReliability.setTimeStep(TimeStep);
BodyTempReliability.setTimeFunctionForLikelinessFunction(TimeConfidence);
std::shared_ptr<BodyTempConfidence> BodyTempConf(new BodyTempConfidence(
{{No, BodyTempParFun(
{{{34.55f, 35.55f},
std::make_shared<BodyTempLinFun>(34.55f, 0, 35.55f, 1)},
{{35.55f, 37.55f}, std::make_shared<BodyTempLinFun>(1, 0)},
{{37.55f, 38.55f},
std::make_shared<BodyTempLinFun>(37.55f, 1, 38.55f, 0)}},
0)},
{Low, BodyTempParFun({}, 0)},
{High, BodyTempParFun(
{{{std::numeric_limits<BodyTempType>::lowest(), 34.55f},
std::make_shared<BodyTempLinFun>(1, 0)},
{{34.55f, 35.55f},
std::make_shared<BodyTempLinFun>(34.55f, 1, 35.55f, 0)},
{{37.55f, 38.55f},
std::make_shared<BodyTempLinFun>(37.55f, 0, 38.55f, 1)},
{{38.55f, 39.05f}, std::make_shared<BodyTempLinFun>(1, 0)},
{{39.05f, 40.05f},
std::make_shared<BodyTempLinFun>(39.05f, 1, 40.05f, 0)}},
0)},
{Emergency,
BodyTempParFun(
{{{std::numeric_limits<BodyTempType>::lowest(), 39.05f},
std::make_shared<BodyTempLinFun>(0, 0)},
{{39.05f, 40.05f},
std::make_shared<BodyTempLinFun>(39.05f, 0, 40.05f, 1)}},
1)}}));
BodyTempReliability.setConfidenceFunction(BodyTempConf);
std::shared_ptr<Abstraction<BodyTempType, ReliabilityType>> BodyTempAbsRel(
new BodyTempParFun(
{{{-70.f, -50.f},
std::make_shared<BodyTempLinFun>(-70.f, 0, -50.f, 1)},
{{-50.f, 40.f}, std::make_shared<BodyTempLinFun>(1, 0)},
{{40.f, 60.f}, std::make_shared<BodyTempLinFun>(40.f, 1, 60.f, 0)}},
0));
BodyTempReliability.setAbsoluteReliabilityFunction(BodyTempAbsRel);
std::shared_ptr<Abstraction<BodyTempType, ReliabilityType>> BodyTempRelSlope(
new BodyTempParFun(
{{{-0.1f, -0.05f},
std::make_shared<BodyTempLinFun>(-0.1f, 0, -0.05f, 1)},
{{-0.05f, 0.05f}, std::make_shared<BodyTempLinFun>(1, 0)},
{{0.05f, 0.1f},
std::make_shared<BodyTempLinFun>(0.05f, 1, 0.1f, 0)}},
0));
BodyTempReliability.setReliabilitySlopeFunction(BodyTempRelSlope);
//
// Create low-level application agents with \c createLowLevelAgent.
//
LOG_INFO("Creating low-level agents.");
AgentHandle HRAgent =
createLowLevelAgent(App, "HR Agent", Decimation, HRReliability);
AgentHandle BRAgent =
createLowLevelAgent(App, "BR Agent", Decimation, BRReliability);
AgentHandle SpO2Agent =
createLowLevelAgent(App, "SpO2 Agent", Decimation, SpO2Reliability);
AgentHandle BPSysAgent =
createLowLevelAgent(App, "BPSys Agent", Decimation, BPSysReliability);
AgentHandle BodyTempAgent = createLowLevelAgent(
App, "BodyTemp Agent", Decimation, BodyTempReliability);
//
// Connect sensors to low-level agents.
//
LOG_INFO("Connect sensors to their corresponding low-level agents.");
App->connectSensor(HRAgent, 0, HRSensor, "HR Sensor Channel");
App->connectSensor(BRAgent, 0, BRSensor, "BR Sensor Channel");
App->connectSensor(SpO2Agent, 0, SpO2Sensor, "SpO2 Sensor Channel");
App->connectSensor(BPSysAgent, 0, BPSysSensor, "BPSys Sensor Channel");
App->connectSensor(BodyTempAgent, 0, BodyTempSensor,
"BodyTemp Sensor Channel");
//
// Create a high-level application agent.
//
LOG_INFO("Create high-level agent.");
// Slave positions on BodyAgent.
enum SlaveIndex : rosa::id_t {
HRIdx = 0,
BRIdx = 1,
SpO2Idx = 2,
BPSysIdx = 3,
BodyTempIdx = 4
};
const ReliabilityType CrossLikelinessParameter = 1.5;
CrossCombinator<WarningScoreType, ReliabilityType> BodyCrossCombinator;
BodyCrossCombinator.setCrossLikelinessParameter(CrossLikelinessParameter);
using WarningLikelinessFun =
LikelinessFunction<WarningScoreType, ReliabilityType>;
std::shared_ptr<WarningLikelinessFun> BRCrossLikelinessFun(
new WarningLikelinessFun(0.6));
BodyCrossCombinator.addCrossLikelinessProfile(HRIdx, BRIdx,
BRCrossLikelinessFun);
BodyCrossCombinator.addCrossLikelinessProfile(BRIdx, HRIdx,
BRCrossLikelinessFun);
BodyCrossCombinator.addCrossLikelinessProfile(BRIdx, SpO2Idx,
BRCrossLikelinessFun);
BodyCrossCombinator.addCrossLikelinessProfile(BRIdx, BPSysIdx,
BRCrossLikelinessFun);
BodyCrossCombinator.addCrossLikelinessProfile(BRIdx, BodyTempIdx,
BRCrossLikelinessFun);
BodyCrossCombinator.addCrossLikelinessProfile(SpO2Idx, BRIdx,
BRCrossLikelinessFun);
BodyCrossCombinator.addCrossLikelinessProfile(BPSysIdx, BRIdx,
BRCrossLikelinessFun);
BodyCrossCombinator.addCrossLikelinessProfile(BodyTempIdx, BRIdx,
BRCrossLikelinessFun);
std::shared_ptr<WarningLikelinessFun> HRBPCrossLikelinessFun(
new WarningLikelinessFun(2.5));
BodyCrossCombinator.addCrossLikelinessProfile(HRIdx, BPSysIdx,
HRBPCrossLikelinessFun);
BodyCrossCombinator.addCrossLikelinessProfile(BPSysIdx, HRIdx,
HRBPCrossLikelinessFun);
// The new agent logs its input values, results in a pair of the sum of
// received warning scores and their cross-reliability as well as calculated
// cross-likeliness feedback for each of its slaves.
using BodyAgentInput = std::pair<WarningValue, bool>;
using BodyAgentOutput = Optional<WarningValue>;
using BodyAgentFeedback = Optional<FeedbackTuple>;
using BodyAgentResult =
std::tuple<BodyAgentOutput, BodyAgentFeedback, BodyAgentFeedback,
BodyAgentFeedback, BodyAgentFeedback, BodyAgentFeedback>;
using BodyAgentHandler = std::function<BodyAgentResult(
BodyAgentInput, BodyAgentInput, BodyAgentInput, BodyAgentInput,
BodyAgentInput)>;
AgentHandle BodyAgent =
App->createAgent(
"Body Agent",
BodyAgentHandler([&](BodyAgentInput HR, BodyAgentInput BR,
BodyAgentInput SpO2, BodyAgentInput BPSys,
BodyAgentInput BodyTemp) -> BodyAgentResult {
LOG_INFO_STREAM << "\n*******\nBody Agent trigged with values:\n"
<< (HR.second ? "<New>" : "<Old>")
<< " HR result: " << PRINTABLE(HR.first) << "\n"
<< (BR.second ? "<New>" : "<Old>")
<< " BR result: " << PRINTABLE(BR.first) << "\n"
<< (SpO2.second ? "<New>" : "<Old>")
<< " SpO2 result: " << PRINTABLE(SpO2.first) << "\n"
<< (BPSys.second ? "<New>" : "<Old>")
<< " BPSys result: " << PRINTABLE(BPSys.first)
<< "\n"
<< (BodyTemp.second ? "<New>" : "<Old>")
<< " BodyTemp result: " << PRINTABLE(BodyTemp.first)
<< "\n******\n";
using ValueType =
std::tuple<rosa::id_t, WarningScoreType, ReliabilityType>;
const std::vector<ValueType> SlaveValues{
{HRIdx, std::get<0>(HR.first), std::get<1>(HR.first)},
{BRIdx, std::get<0>(BR.first), std::get<1>(BR.first)},
{SpO2Idx, std::get<0>(SpO2.first), std::get<1>(SpO2.first)},
{BPSysIdx, std::get<0>(BPSys.first), std::get<1>(BPSys.first)},
{BodyTempIdx, std::get<0>(BodyTemp.first),
std::get<1>(BodyTemp.first)}};
const auto [crossReliability, feedbackValues] =
BodyCrossCombinator(SlaveValues);
struct ScoreSum {
void operator()(const ValueType &V) { ews += std::get<1>(V); }
WarningScoreType ews{0};
};
const ScoreSum scoreSum = std::for_each(
SlaveValues.cbegin(), SlaveValues.cend(), ScoreSum());
return {{WarningValue(scoreSum.ews, crossReliability)},
{feedbackFromSymbol(feedbackValues.at(HRIdx))},
{feedbackFromSymbol(feedbackValues.at(BRIdx))},
{feedbackFromSymbol(feedbackValues.at(SpO2Idx))},
{feedbackFromSymbol(feedbackValues.at(BPSysIdx))},
{feedbackFromSymbol(feedbackValues.at(BodyTempIdx))}};
}));
App->setExecutionPolicy(BodyAgent, AppExecutionPolicy::decimation(Decimation));
//
// Connect low-level agents to the high-level agent.
//
LOG_INFO("Connect low-level agents to the high-level agent.");
App->connectAgents(BodyAgent, HRIdx, HRAgent, "HR Agent Channel");
App->connectAgents(BodyAgent, BRIdx, BRAgent, "BR Agent Channel");
App->connectAgents(BodyAgent, SpO2Idx, SpO2Agent, "SpO2 Agent Channel");
App->connectAgents(BodyAgent, BPSysIdx, BPSysAgent, "BPSys Agent Channel");
App->connectAgents(BodyAgent, BodyTempIdx, BodyTempAgent,
"BodyTemp Agent Channel");
//
// For simulation output, create a logger agent writing the output of the
// high-level agent into a CSV file.
//
LOG_INFO("Create a logger agent.");
// Create CSV writer.
std::ofstream ScoreCSV(ScoreCSVPath);
csv::CSVTupleWriter<WarningScoreType, ReliabilityType>
ScoreWriter(ScoreCSV, CSVDelimiter);
if (CSVHeader) {
ScoreWriter.writeHeader({"EWS", "Reliability"});
}
// The agent writes each new input value into a CSV file and produces nothing.
// \note The execution of the logger is not subject to decimation.
using logger_result = AppTuple<unit_t>;
AgentHandle LoggerAgent = App->createAgent(
"Logger Agent",
std::function<Optional<logger_result>(std::pair<WarningValue, bool>)>(
[&ScoreWriter](
std::pair<WarningValue, bool> Score) -> Optional<logger_result> {
// The state of \p ScoreWriter is not checked, expecting good.
ScoreWriter << Score.first;
return {};
}));
//
// Connect the high-level agent to the logger agent.
//
LOG_INFO("Connect the high-level agent to the logger agent.");
App->connectAgents(LoggerAgent, 0, BodyAgent, "Body Agent Channel");
//
// Do simulation.
//
LOG_INFO("Setting up and performing simulation.");
//
// Initialize application for simulation.
//
App->initializeSimulation();
//
// Open CSV files and register them for their corresponding sensors.
//
// Type aliases for iterators.
using CSVDataIterator =
CSVIterator<HRType, BRType, SpO2Type, BPSysType, BodyTempType>;
const auto CSVHeaderInfo =
CSVHeader ? HeaderInformation::HasHeader : HeaderInformation::HasNoHeader;
std::ifstream DataCSV(DataCSVPath);
auto [HRRange, BRRange, SpO2Range, BPSysRange, BodyTempRange] =
splitTupleIterator(
CSVDataIterator(DataCSV, 0, CSVHeaderInfo, CSVDelimiter),
CSVDataIterator());
App->registerSensorValues(HRSensor, std::move(begin(HRRange)), end(HRRange));
App->registerSensorValues(BRSensor, std::move(begin(BRRange)), end(BRRange));
App->registerSensorValues(SpO2Sensor, std::move(begin(SpO2Range)),
end(SpO2Range));
App->registerSensorValues(BPSysSensor, std::move(begin(BPSysRange)),
end(BPSysRange));
App->registerSensorValues(BodyTempSensor, std::move(begin(BodyTempRange)),
end(BodyTempRange));
//
// Simulate.
//
App->simulate(NumberOfSimulationCycles);
return 0;
}

File Metadata

Mime Type
text/x-c++
Expires
Sun, Mar 1, 5:19 PM (6 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
287428
Default Alt Text
sa-ews2.cpp (35 KB)

Event Timeline