Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F386617
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Size
17 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment