diff --git a/apps/ccam/ccam.cpp b/apps/ccam/ccam.cpp index 8efde0e..bba45e6 100644 --- a/apps/ccam/ccam.cpp +++ b/apps/ccam/ccam.cpp @@ -1,343 +1,346 @@ //===-- apps/ccam/ccam.cpp --------------------------------------*- C++ -*-===// // // The RoSA Framework -- Application CCAM // //===----------------------------------------------------------------------===// /// /// \file apps/ccam/ccam.cpp /// /// \author Maximilian Goetzinger (maximilian.goetzinger@tuwien.ac.at) /// \author Benedikt Tutzer (benedikt.tutzer@tuwien.ac.at) /// /// \date 2019 /// /// \brief The application CCAM implements the case study from the paper: /// M. Goetzinger, N. TaheriNejad, H. A. Kholerdi, A. Jantsch, E. Willegger, /// T. Glatzl, A.M. Rahmani, T.Sauter, P. Liljeberg: Model - Free Condition /// Monitoring with Confidence //===----------------------------------------------------------------------===// #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Confidence.hpp" #include "rosa/agent/FunctionAbstractions.hpp" #include <iostream> #include "rosa/config/version.h" #include "rosa/agent/SignalStateDetector.hpp" #include "rosa/agent/SystemStateDetector.hpp" #include "rosa/deluxe/DeluxeContext.hpp" #include "rosa/support/csv/CSVReader.hpp" #include "rosa/support/csv/CSVWriter.hpp" #include <fstream> #include <limits> #include <memory> #include <streambuf> #include "configuration.h" using namespace rosa; using namespace rosa::agent; using namespace rosa::deluxe; using namespace rosa::terminal; const std::string AppName = "CCAM"; -using SignalStateTuple = - std::tuple<Optional<float>, Optional<unsigned int>, Optional<float>, - Optional<uint8_t>, Optional<unsigned int>, Optional<bool>, - Optional<bool>, Optional<bool>, Optional<bool>>; +using SignalStateTuple = DeluxeTuple<float, uint32_t, float, uint8_t, uint32_t, + bool, bool, bool, bool>; AgentHandle createSignalStateDetectorAgent( std::unique_ptr<DeluxeContext> &C, const std::string &Name, std::shared_ptr< SignalStateDetector<float, float, float, HistoryPolicy::FIFO>> SigSD) { (void)SigSD; - using Handler = std::function<SignalStateTuple(std::pair<float, bool>)>; + using Input = std::pair<DeluxeTuple<float>, bool>; + using Result = Optional<SignalStateTuple>; + using Handler = std::function<Result(Input)>; return C->createAgent( - Name, - Handler([&Name, &SigSD](std::pair<float, bool> I) -> SignalStateTuple { + Name, Handler([&Name, &SigSD](Input I) -> Result { LOG_INFO_STREAM << "\n******\n" << Name << " " << (I.second ? "<New>" : "<Old>") - << " value: " << I.first << "\n******\n"; - auto StateInfo = SigSD->detectSignalState(I.first); - - if (I.second) - return std::make_tuple( - Optional<float>(I.first), - Optional<unsigned int>(StateInfo.SignalStateID), - Optional<float>(StateInfo.SignalStateConfidence), - Optional<uint8_t>(StateInfo.SignalStateCondition), - Optional<unsigned int>( - StateInfo.NumberOfInsertedSamplesAfterEntrance), - Optional<bool>(StateInfo.SignalStateIsValid), - Optional<bool>(StateInfo.SignalStateJustGotValid), - Optional<bool>(StateInfo.SignalStateIsValidAfterReentrance), - Optional<bool>(StateInfo.SignalIsStable)); - return SignalStateTuple(); + << " value: " << std::get<0>(I.first) << "\n******\n"; + auto StateInfo = SigSD->detectSignalState(std::get<0>(I.first)); + + if (I.second) { + SignalStateTuple res = { + std::get<0>(I.first), + StateInfo.SignalStateID, + StateInfo.SignalStateConfidence, + (uint8_t)StateInfo.SignalStateCondition, + StateInfo.NumberOfInsertedSamplesAfterEntrance, + StateInfo.SignalStateIsValid, + StateInfo.SignalStateJustGotValid, + StateInfo.SignalStateIsValidAfterReentrance, + StateInfo.SignalIsStable}; + return Result(res); + } + return Result(); })); } int main(int argc, char **argv) { LOG_INFO_STREAM << '\n' << library_string() << " -- " << Color::Red << AppName << "app" << Color::Default << '\n'; if (argc < 2) { LOG_ERROR("Specify config File!\nUsage:\n\tccam config.json"); return 1; } std::string ConfigPath = argv[1]; if (!readConfigFile(ConfigPath)) { LOG_ERROR_STREAM << "Could not read config from \"" << ConfigPath << "\"\n"; return 2; } std::string InputFilePath, OutputFilePath; LOG_INFO("Creating Context"); std::unique_ptr<DeluxeContext> C = DeluxeContext::create(AppName); LOG_INFO("Creating sensors, SignalStateDetector functionalities and their " "Abstractions."); std::vector<AgentHandle> Sensors; std::vector<std::shared_ptr<PartialFunction<float, float>>> SampleMatchesFunctions; std::vector<std::shared_ptr<PartialFunction<float, float>>> SampleMismatchesFunctions; std::vector<std::shared_ptr<PartialFunction<float, float>>> SignalIsStableFunctions; std::vector<std::shared_ptr<PartialFunction<float, float>>> SignalIsDriftingFunctions; std::vector<std::shared_ptr<StepFunction<float, float>>> NumOfSamplesMatchFunctions; std::vector<std::shared_ptr<StepFunction<float, float>>> NumOfSamplesMismatchFunctions; - std::vector<SignalStateDetector<float, float, float, HistoryPolicy::FIFO>> + std::vector<std::shared_ptr< + SignalStateDetector<float, float, float, HistoryPolicy::FIFO>>> SignalStateDetectors; std::vector<AgentHandle> SignalStateDetectorAgents; for (auto SignalConfiguration : AppConfig.SignalConfigurations) { // // Create deluxe sensors. // Sensors.emplace_back(C->createSensor<float>(SignalConfiguration.Name)); // // Create functionalities for SignalStateDetector. // SampleMatchesFunctions.emplace_back(new PartialFunction<float, float>( { {{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound}, std::make_shared<LinearFunction<float, float>>( -SignalConfiguration.OuterBound, 0.f, -SignalConfiguration.InnerBound, 1.f)}, {{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound}, std::make_shared<LinearFunction<float, float>>(1.f, 0.f)}, {{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound}, std::make_shared<LinearFunction<float, float>>( SignalConfiguration.InnerBound, 1.f, SignalConfiguration.OuterBound, 0.f)}, }, 0)); SampleMismatchesFunctions.emplace_back(new PartialFunction<float, float>( { {{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound}, std::make_shared<LinearFunction<float, float>>( -SignalConfiguration.OuterBound, 1.f, -SignalConfiguration.InnerBound, 0.f)}, {{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound}, std::make_shared<LinearFunction<float, float>>(0.f, 0.f)}, {{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound}, std::make_shared<LinearFunction<float, float>>( SignalConfiguration.InnerBound, 0.f, SignalConfiguration.OuterBound, 1.f)}, }, 1)); SignalIsStableFunctions.emplace_back(new PartialFunction<float, float>( { {{-SignalConfiguration.OuterBoundDrift, -SignalConfiguration.InnerBoundDrift}, std::make_shared<LinearFunction<float, float>>( -SignalConfiguration.OuterBoundDrift, 0.f, -SignalConfiguration.InnerBoundDrift, 1.f)}, {{-SignalConfiguration.InnerBoundDrift, SignalConfiguration.InnerBoundDrift}, std::make_shared<LinearFunction<float, float>>(1.f, 0.f)}, {{SignalConfiguration.InnerBoundDrift, SignalConfiguration.OuterBoundDrift}, std::make_shared<LinearFunction<float, float>>( SignalConfiguration.InnerBoundDrift, 1.f, SignalConfiguration.OuterBoundDrift, 0.f)}, }, 0)); SignalIsDriftingFunctions.emplace_back(new PartialFunction<float, float>( { {{-SignalConfiguration.OuterBoundDrift, -SignalConfiguration.InnerBoundDrift}, std::make_shared<LinearFunction<float, float>>( -SignalConfiguration.OuterBoundDrift, 1.f, -SignalConfiguration.InnerBoundDrift, 0.f)}, {{-SignalConfiguration.InnerBoundDrift, SignalConfiguration.InnerBoundDrift}, std::make_shared<LinearFunction<float, float>>(0.f, 0.f)}, {{SignalConfiguration.InnerBoundDrift, SignalConfiguration.OuterBoundDrift}, std::make_shared<LinearFunction<float, float>>( SignalConfiguration.InnerBoundDrift, 0.f, SignalConfiguration.OuterBoundDrift, 1.f)}, }, 1)); NumOfSamplesMatchFunctions.emplace_back(new StepFunction<float, float>( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepUp)); NumOfSamplesMismatchFunctions.emplace_back(new StepFunction<float, float>( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepDown)); // // Create SignalStateDetector functionality // SignalStateDetectors.emplace_back( - std::numeric_limits<int>::max(), SampleMatchesFunctions.back(), - SampleMismatchesFunctions.back(), NumOfSamplesMatchFunctions.back(), - NumOfSamplesMismatchFunctions.back(), SignalIsDriftingFunctions.back(), - SignalIsStableFunctions.back(), SignalConfiguration.SampleHistorySize, - SignalConfiguration.DABSize, SignalConfiguration.DABHistorySize); + new SignalStateDetector<float, float, float, HistoryPolicy::FIFO>( + std::numeric_limits<int>::max(), SampleMatchesFunctions.back(), + SampleMismatchesFunctions.back(), NumOfSamplesMatchFunctions.back(), + NumOfSamplesMismatchFunctions.back(), + SignalIsDriftingFunctions.back(), SignalIsStableFunctions.back(), + SignalConfiguration.SampleHistorySize, SignalConfiguration.DABSize, + SignalConfiguration.DABHistorySize)); // // Create low-level deluxe agents // - // SignalStateDetectorAgents.push_back(createSignalStateDetectorAgent( - // C, SignalConfiguration.Name, SignalStateDetectors.back())); + SignalStateDetectorAgents.push_back(createSignalStateDetectorAgent( + C, SignalConfiguration.Name, SignalStateDetectors.back())); // // Connect sensors to low-level agents. // LOG_INFO("Connect sensors to their corresponding low-level agents."); C->connectSensor(SignalStateDetectorAgents.back(), 0, Sensors.back(), - "HR Sensor Channel"); + SignalConfiguration.Name); } std::shared_ptr<PartialFunction<float, float>> BrokenDelayFunction( new PartialFunction<float, float>( {{{0, AppConfig.BrokenCounter}, std::make_shared<LinearFunction<float, float>>( 0, 0.f, AppConfig.BrokenCounter, 1.f)}, {{AppConfig.BrokenCounter, std::numeric_limits<float>::max()}, std::make_shared<LinearFunction<float, float>>(1.f, 0.f)}}, 0)); std::shared_ptr<PartialFunction<float, float>> OkDelayFunction( new PartialFunction<float, float>( {{{0, AppConfig.BrokenCounter}, std::make_shared<LinearFunction<float, float>>( 0, 1.f, AppConfig.BrokenCounter, 0.f)}, {{AppConfig.BrokenCounter, std::numeric_limits<float>::max()}, std::make_shared<LinearFunction<float, float>>(0.f, 0.f)}}, 1)); std::shared_ptr< SystemStateDetector<float, float, float, HistoryPolicy::FIFO, 5, 5>> SystemStateDetectorF( new SystemStateDetector<float, float, float, HistoryPolicy::FIFO, 5, 5>( std::numeric_limits<uint32_t>::max(), BrokenDelayFunction, OkDelayFunction)); // // Create a high-level deluxe agent. // LOG_INFO("Create high-level agent."); // The new agent logs its input values and results in the the sum of them. /** AgentHandle BodyAgent = C->createAgent( "Body Agent", DeluxeAgent::D<uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t>( [](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}; })); */ // // Connect low-level agents to the high-level agent. // LOG_INFO("Connect low-level agents to the high-level agent."); /// C->connectAgents(BodyAgent, 0, HRAgent, "HR 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. /** AgentHandle LoggerAgent = C->createAgent( "Logger Agent", DeluxeAgent::D<unit_t, uint32_t>( [&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."); /// C->connectAgents(LoggerAgent, 0, BodyAgent, "Body Agent Channel"); // // Do simulation. // LOG_INFO("Setting up and performing simulation."); // // Initialize deluxe context for simulation. // // C->initializeSimulation(); // // Open CSV files and register them for their corresponding sensors. // // // Simulate. // /// C->simulate(NumberOfSimulationCycles); return 0; }