Page MenuHomePhorge

sa-ews1.cpp
No OneTemporary

Size
23 KB
Referenced Files
None
Subscribers
None

sa-ews1.cpp

//===-- 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)
/// Maximilian Goetzinger (maxgot@utu.fi)
///
/// \date 2017-2020
///
/// \brief The application SA-EWS1 implements the case study from the paper:
/// 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/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-EWS1";
/// Representation type of warning levels.
/// \note Make sure it suits all defined enumeration values.
using WarningScoreType = uint8_t;
/// Warning levels for abstraction.
enum WarningScore : WarningScoreType {
No = 0,
Low = 1,
High = 2,
Emergency = 3
};
/// Vector with all possible warning levels.
std::vector<WarningScore> 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>;
/// 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.
///
/// \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 A abstraction to use
/// \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, const Abstraction<T, WarningScore> &A,
ReliabilityAndConfidenceCombination<T, WarningScore, ReliabilityType> &R) {
using result = Optional<WarningValue>;
using input = AppTuple<T>;
using handler = std::function<result(std::pair<input, bool>)>;
AgentHandle Agent = App->createAgent(
Name, 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 WarningScoreType Score = A(SensorValue);
const ReliabilityType InputReliability =
R.getInputReliability(SensorValue);
return {WarningValue(Score, InputReliability)};
}));
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 = 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 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 = int32_t;
using HRParFun = PartialFunction<HRType, ReliabilityType>;
using HRLinFun = LinearFunction<HRType, ReliabilityType>;
using BRType = int32_t;
using BRParFun = PartialFunction<BRType, ReliabilityType>;
using BRLinFun = LinearFunction<BRType, ReliabilityType>;
using SpO2Type = int32_t;
using SpO2ParFun = PartialFunction<SpO2Type, ReliabilityType>;
using SpO2LinFun = LinearFunction<SpO2Type, ReliabilityType>;
using BPSysType = int32_t;
using BPSysParFun = PartialFunction<BPSysType, ReliabilityType>;
using BPSysLinFun = LinearFunction<BPSysType, ReliabilityType>;
using BodyTempType = float;
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 abstractions.
//
RangeAbstraction<HRType, 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<BRType, WarningScore> BRAbstraction({{{0, 9}, High},
{{9, 14}, No},
{{14, 20}, Low},
{{20, 29}, High},
{{29, 50}, Emergency}},
Emergency);
RangeAbstraction<SpO2Type, WarningScore> SpO2Abstraction(
{{{1, 85}, Emergency},
{{85, 90}, High},
{{90, 95}, Low},
{{95, 100}, No}},
Emergency);
RangeAbstraction<BPSysType, 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<BodyTempType, 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);
//
// Define reliabilities.
//
ReliabilityAndConfidenceCombination<HRType, WarningScore, ReliabilityType>
HRReliability;
HRReliability.setTimeStep(1);
std::shared_ptr<Abstraction<HRType, ReliabilityType>> HRAbsRel(
new HRParFun({{{0, 200}, std::make_shared<HRLinFun>(1, 0)},
{{200, 300}, std::make_shared<HRLinFun>(200, 1, 300, 0)}},
0));
HRReliability.setAbsoluteReliabilityFunction(HRAbsRel);
std::shared_ptr<Abstraction<HRType, ReliabilityType>> HRRelSlope(new HRParFun(
{{{-200, -100}, std::make_shared<HRLinFun>(-200, 0, -100, 1)},
{{-100, 100}, std::make_shared<HRLinFun>(1, 0)},
{{100, 200}, std::make_shared<HRLinFun>(100, 1, 200, 0)}},
0));
HRReliability.setReliabilitySlopeFunction(HRRelSlope);
ReliabilityAndConfidenceCombination<BRType, WarningScore, ReliabilityType>
BRReliability;
BRReliability.setTimeStep(1);
std::shared_ptr<Abstraction<BRType, ReliabilityType>> BRAbsRel(
new BRParFun({{{0, 40}, std::make_shared<BRLinFun>(1, 0)},
{{40, 60}, std::make_shared<BRLinFun>(40, 1, 60, 0)}},
0));
BRReliability.setAbsoluteReliabilityFunction(BRAbsRel);
std::shared_ptr<Abstraction<BRType, ReliabilityType>> BRRelSlope(
new BRParFun({{{-30, -20}, std::make_shared<BRLinFun>(-30, 0, -20, 1)},
{{-20, 20}, std::make_shared<BRLinFun>(1, 0)},
{{20, 30}, std::make_shared<BRLinFun>(20, 1, 30, 0)}},
0));
BRReliability.setReliabilitySlopeFunction(BRRelSlope);
ReliabilityAndConfidenceCombination<SpO2Type, WarningScore, ReliabilityType>
SpO2Reliability;
SpO2Reliability.setTimeStep(1);
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, WarningScore, ReliabilityType>
BPSysReliability;
BPSysReliability.setTimeStep(1);
std::shared_ptr<Abstraction<BPSysType, ReliabilityType>> BPSysAbsRel(
new BPSysParFun(
{{{0, 260}, std::make_shared<BPSysLinFun>(1, 0)},
{{260, 400}, std::make_shared<BPSysLinFun>(260, 1, 400, 0)}},
0));
BPSysReliability.setAbsoluteReliabilityFunction(BPSysAbsRel);
std::shared_ptr<Abstraction<BPSysType, ReliabilityType>> BPSysRelSlope(
new BPSysParFun(
{{{-100, -50}, std::make_shared<BPSysLinFun>(-100, 0, -50, 1)},
{{-50, 50}, std::make_shared<BPSysLinFun>(1, 0)},
{{50, 100}, std::make_shared<BPSysLinFun>(50, 1, 100, 0)}},
0));
BPSysReliability.setReliabilitySlopeFunction(BPSysRelSlope);
ReliabilityAndConfidenceCombination<BodyTempType, WarningScore,
ReliabilityType>
BodyTempReliability;
BodyTempReliability.setTimeStep(1);
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,
HRAbstraction, HRReliability);
AgentHandle BRAgent = createLowLevelAgent(App, "BR Agent", Decimation,
BRAbstraction, BRReliability);
AgentHandle SpO2Agent = createLowLevelAgent(App, "SpO2 Agent", Decimation,
SpO2Abstraction, SpO2Reliability);
AgentHandle BPSysAgent = createLowLevelAgent(
App, "BPSys Agent", Decimation, BPSysAbstraction, BPSysReliability);
AgentHandle BodyTempAgent =
createLowLevelAgent(App, "BodyTemp Agent", Decimation,
BodyTempAbstraction, 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
};
CrossCombinator<WarningScoreType, ReliabilityType> BodyCrossCombinator;
BodyCrossCombinator.setCrossLikelinessParameter(1.5);
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 and results in a pair of the sum of
// received warning scores and their cross-reliability.
AgentHandle BodyAgent = App->createAgent(
"Body Agent",
std::function<Optional<WarningValue>(
std::pair<WarningValue, bool>, std::pair<WarningValue, bool>,
std::pair<WarningValue, bool>, std::pair<WarningValue, bool>,
std::pair<WarningValue, bool>)>(
[&](std::pair<WarningValue, bool> HR,
std::pair<WarningValue, bool> BR,
std::pair<WarningValue, bool> SpO2,
std::pair<WarningValue, bool> BPSys,
std::pair<WarningValue, bool> BodyTemp)
-> Optional<WarningValue> {
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 ReliabilityType crossReliability =
BodyCrossCombinator.getOutputLikeliness(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)};
}));
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, Jun 8, 8:11 PM (23 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
150246
Default Alt Text
sa-ews1.cpp (23 KB)

Event Timeline