Page MenuHomePhorge

No OneTemporary

Size
17 KB
Referenced Files
None
Subscribers
None
diff --git a/apps/sa-ews1/sa-ews1.cpp b/apps/sa-ews1/sa-ews1.cpp
index 0433e43..7fdf65b 100644
--- a/apps/sa-ews1/sa-ews1.cpp
+++ b/apps/sa-ews1/sa-ews1.cpp
@@ -1,326 +1,404 @@
//===-- apps/sa-ews1/sa-ews1.cpp --------------------------------*- C++ -*-===//
//
// The RoSA Framework -- Application SA-EWS1
//
// 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-ews1/sa-ews1.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2020
///
/// \brief The application SA-EWS1 implements the case study from the paper:
-/// M. Götzinger, N. Taherinejad, A. M. Rahmani, P. Liljeberg, A. Jantsch, and
-/// H. Tenhunen: Enhancing the Early Warning Score System Using Data Confidence
-/// DOI: 10.1007/978-3-319-58877-3_12
+/// M. Götzinger, A. Anzanpour, I. Azimi, N. TaheriNejad, and A. M. Rahmani:
+/// Enhancing the Self-Aware Early Warning Score System through Fuzzified Data
+/// Reliability Assessment. DOI: 10.1007/978-3-319-98551-0_1
//===----------------------------------------------------------------------===//
#include "rosa/agent/Abstraction.hpp"
#include "rosa/agent/Confidence.hpp"
#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-EWS1";
-/// Paths for the CSV files for simulation.
-///
-///@{
-const std::string HRCSVPath = "HR.csv";
-const std::string BRCSVPath = "BR.csv";
-const std::string SpO2CSVPath = "SpO2.csv";
-const std::string BPSysCSVPath = "BPSys.csv";
-const std::string BodyTempCSVPath = "BodyTemp.csv";
-const std::string ScoreCSVPath = "Score.csv";
-///@}
-
-/// How many cycles of simulation to perform.
-const size_t NumberOfSimulationCycles = 16;
-
/// Warning levels for abstraction.
enum WarningScore { No = 0, Low = 1, High = 2, Emergency = 3 };
+/// 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.
+/// values and setting its execution policy for decimation.
+///
+/// \todo Replace Confidence with Reliability and send abstracted value together
+/// with reliability value.
///
/// Received values are first validated for confidence. Values which the
/// validator does not mark confident are ignored. Confident values are
/// abstracted into a \c WarningScore value, which is the result of the
/// processing function.
///
/// \note The result, \c WarningScore, is returned as \c uint32_t because
/// enumeration types are not integrated into built-in types. Hence, a master
/// to these agents receives its input as \c uint32_t 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 CC confidence validator to use
/// \param A abstraction 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,
const Confidence<T> &CC,
const Abstraction<T, WarningScore> &A) {
using handler = std::function<Optional<uint32_t>(std::pair<T, bool>)>;
using result = Optional<uint32_t>;
- return App->createAgent(
+ AgentHandle Agent = App->createAgent(
Name, handler([&, Name](std::pair<T, bool> I) -> result {
LOG_INFO_STREAM << "\n******\n"
<< Name << " " << (I.second ? "<New>" : "<Old>")
<< " value: " << I.first << "\n******\n";
return (I.second && CC(I.first)) ? result(A(I.first)) : result();
}));
+ App->setExecutionPolicy(Agent, AppExecutionPolicy::decimation(Decimation));
+ return Agent;
}
-int main(void) {
+/// Helper function to print and 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[]) {
+ /// Paths for the CSV files for simulation.
+ ///
+ ///@{
+ std::string DataCSVPath;
+ std::string ScoreCSVPath;
+ ///@}
+
+ /// Decimation of sensors and agents.
+ size_t Decimation = 1;
+
+ /// How many cycles of simulation to perform.
+ size_t NumberOfSimulationCycles = 16;
+
+ // 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 fr the CSV file to write output scores",
+ cxxopts::value(ScoreCSVPath), "file")
+ ("d,decimation", "Decimation of sensors and agents",
+ cxxopts::value(Decimation)->default_value("1"))
+ ("c,cycles", "Number of simulation cycles to perform",
+ cxxopts::value(NumberOfSimulationCycles)->default_value("16"));
+
+ auto Args = Options.parse(argc, argv);
+ if (Args.count("data") == 0) {
+ throw std::invalid_argument("Argument --data must be defined.");
+ }
+ if (Args.count("score") == 0) {
+ throw std::invalid_argument("Argument --score must be defined.");
+ }
+ } catch (const cxxopts::OptionException &e) {
+ logErrorAndExit(e.what(), 1);
+ } catch (const std::invalid_argument &e) {
+ logErrorAndExit(e.what(), 1);
+ }
+
LOG_INFO_STREAM
<< '\n'
<< library_string() << " -- " << Color::Red << AppName << "app"
<< Color::Default << '\n'
<< Color::Yellow
<< "CSV files are read from and written to the current working directory."
<< Color::Default << '\n';
std::unique_ptr<Application> App = Application::create(AppName);
//
// 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 = App->createSensor<int32_t>("HR Sensor");
- AgentHandle BRSensor = App->createSensor<int32_t>("BR Sensor");
- AgentHandle SpO2Sensor = App->createSensor<int32_t>("SpO2 Sensor");
- AgentHandle BPSysSensor = App->createSensor<int32_t>("BPSys Sensor");
- AgentHandle BodyTempSensor = App->createSensor<float>("BodyTemp Sensor");
+ AgentHandle HRSensor = createSensor<int32_t>(App, "HR Sensor", Decimation);
+ AgentHandle BRSensor = createSensor<int32_t>(App, "BR Sensor", Decimation);
+ AgentHandle SpO2Sensor =
+ createSensor<int32_t>(App, "SpO2 Sensor", Decimation);
+ AgentHandle BPSysSensor =
+ createSensor<int32_t>(App, "BPSys Sensor", Decimation);
+ AgentHandle BodyTempSensor =
+ createSensor<float>(App, "BodyTemp Sensor", Decimation);
//
// Create functionalities.
//
LOG_INFO("Creating Functionalities for Agents.");
//
// Define confidence validators.
//
// Lower bounds are inclusive and upper bounds are exclusive.
Confidence<int32_t> HRConfidence(0, 501);
Confidence<int32_t> BRConfidence(0, 301);
Confidence<int32_t> SpO2Confidence(0, 101);
- Confidence<int32_t> BPSysConfidence(0,501);
+ Confidence<int32_t> BPSysConfidence(0, 501);
Confidence<float> BodyTempConfidence(-60,
nextRepresentableFloatingPoint(50.0f));
//
// Define abstractions.
//
RangeAbstraction<int32_t, WarningScore> HRAbstraction(
{{{0, 40}, Emergency},
{{40, 51}, High},
{{51, 60}, Low},
{{60, 100}, No},
{{100, 110}, Low},
{{110, 129}, High},
{{129, 200}, Emergency}},
Emergency);
RangeAbstraction<int32_t, WarningScore> BRAbstraction({{{0, 9}, High},
{{9, 14}, No},
{{14, 20}, Low},
{{20, 29}, High},
{{29, 50}, Emergency}},
Emergency);
RangeAbstraction<int32_t, WarningScore> SpO2Abstraction({{{1, 85}, Emergency},
{{85, 90}, High},
{{90, 95}, Low},
{{95, 100}, No}},
Emergency);
RangeAbstraction<int32_t, WarningScore> BPSysAbstraction(
{{{0, 70}, Emergency},
{{70, 81}, High},
{{81, 101}, Low},
{{101, 149}, No},
{{149, 169}, Low},
{{169, 179}, High},
{{179, 200}, Emergency}},
Emergency);
RangeAbstraction<float, WarningScore> BodyTempAbstraction(
{{{0.f, 28.f}, Emergency},
{{28.f, 32.f}, High},
{{32.f, 35.f}, Low},
{{35.f, 38.f}, No},
{{38.f, 39.5f}, High},
{{39.5f, 100.f}, Emergency}},
Emergency);
//
// Create low-level application agents with \c createLowLevelAgent.
//
LOG_INFO("Creating low-level agents.");
- AgentHandle HRAgent =
- createLowLevelAgent(App, "HR Agent", HRConfidence, HRAbstraction);
- AgentHandle BRAgent =
- createLowLevelAgent(App, "BR Agent", BRConfidence, BRAbstraction);
- AgentHandle SpO2Agent =
- createLowLevelAgent(App, "SpO2 Agent", SpO2Confidence, SpO2Abstraction);
+ AgentHandle HRAgent = createLowLevelAgent(App, "HR Agent", Decimation,
+ HRConfidence, HRAbstraction);
+ AgentHandle BRAgent = createLowLevelAgent(App, "BR Agent", Decimation,
+ BRConfidence, BRAbstraction);
+ AgentHandle SpO2Agent = createLowLevelAgent(App, "SpO2 Agent", Decimation,
+ SpO2Confidence, SpO2Abstraction);
AgentHandle BPSysAgent = createLowLevelAgent(
- App, "BPSys Agent", BPSysConfidence, BPSysAbstraction);
- AgentHandle BodyTempAgent = createLowLevelAgent(
- App, "BodyTemp Agent", BodyTempConfidence, BodyTempAbstraction);
+ App, "BPSys Agent", Decimation, BPSysConfidence, BPSysAbstraction);
+ AgentHandle BodyTempAgent =
+ createLowLevelAgent(App, "BodyTemp Agent", Decimation, BodyTempConfidence,
+ BodyTempAbstraction);
//
// 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.");
// The new agent logs its input values and results in the the sum of them.
+ // \todo Additionally calculate cross-reliability for the warning score and
+ // result a pair of those values.
AgentHandle BodyAgent = App->createAgent(
"Body Agent",
std::function<Optional<uint32_t>(
std::pair<uint32_t, bool>, std::pair<uint32_t, bool>,
std::pair<uint32_t, bool>, std::pair<uint32_t, bool>,
std::pair<uint32_t, bool>)>(
[](std::pair<uint32_t, bool> HR, std::pair<uint32_t, bool> BR,
std::pair<uint32_t, bool> SpO2, std::pair<uint32_t, bool> BPSys,
std::pair<uint32_t, bool> BodyTemp) -> Optional<uint32_t> {
LOG_INFO_STREAM << "\n*******\nBody Agent trigged with values:\n"
<< (HR.second ? "<New>" : "<Old>")
<< " HR warning score: " << HR.first << "\n"
<< (BR.second ? "<New>" : "<Old>")
<< " BR warning score: " << BR.first << "\n"
<< (SpO2.second ? "<New>" : "<Old>")
<< " SpO2 warning score: " << SpO2.first << "\n"
<< (BPSys.second ? "<New>" : "<Old>")
<< " BPSys warning score: " << BPSys.first << "\n"
<< (BodyTemp.second ? "<New>" : "<Old>")
<< " BodyTemp warning score: " << BodyTemp.first
<< "\n******\n";
return {HR.first + BR.first + SpO2.first + BPSys.first +
BodyTemp.first};
}));
+ 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, 0, HRAgent, "HR Agent Channel");
App->connectAgents(BodyAgent, 1, BRAgent, "BR Agent Channel");
App->connectAgents(BodyAgent, 2, SpO2Agent, "SpO2 Agent Channel");
App->connectAgents(BodyAgent, 3, BPSysAgent, "BPSys Agent Channel");
App->connectAgents(BodyAgent, 4, 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::CSVWriter<uint32_t> ScoreWriter(ScoreCSV);
// 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.
+ // \todo Print the pairs that are sent by BodyAgent into a multi-column CSV
+ // file.
AgentHandle LoggerAgent = App->createAgent(
"Logger Agent",
std::function<Optional<unit_t>(std::pair<uint32_t, bool>)>(
[&ScoreWriter](std::pair<uint32_t, bool> Score) -> Optional<unit_t> {
if (Score.second) {
// 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 CSVInt = csv::CSVIterator<int32_t>;
- using CSVFloat = csv::CSVIterator<float>;
-
- std::ifstream HRCSV(HRCSVPath);
- App->registerSensorValues(HRSensor, CSVInt(HRCSV), CSVInt());
-
- std::ifstream BRCSV(BRCSVPath);
- App->registerSensorValues(BRSensor, CSVInt(BRCSV), CSVInt());
-
- std::ifstream SpO2CSV(SpO2CSVPath);
- App->registerSensorValues(SpO2Sensor, CSVInt(SpO2CSV), CSVInt());
-
- std::ifstream BPSysCSV(BPSysCSVPath);
- App->registerSensorValues(BPSysSensor, CSVInt(BPSysCSV), CSVInt());
-
- std::ifstream BodyTempCSV(BodyTempCSVPath);
- App->registerSensorValues(BodyTempSensor, CSVFloat(BodyTempCSV), CSVFloat());
+ using CSVDataIterator =
+ CSVIterator<int32_t, int32_t, int32_t, int32_t, float>;
+ std::ifstream DataCSV(DataCSVPath);
+ auto [HRRange, BRRange, SpO2Range, BPSysRange, BodyTempRange] =
+ splitTupleIterator(CSVDataIterator(DataCSV), 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-diff
Expires
Thu, Jul 3, 10:50 PM (2 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
157406
Default Alt Text
(17 KB)

Event Timeline