Commit bc9a6047 authored by fmg005's avatar fmg005

Added support for multiple pumps, controllers and patients

parent 758440e3
......@@ -4,22 +4,18 @@ project(CMD_SIM)
# header files
include_directories(include)
# source files directory -> handle multiple controllers
set(CMD_SRC_DIR src)
# source files
set(MY_SOURCE_FILES
src/SimEngine.cpp
src/Monitor.cpp
src/Controller.cpp
src/Pump.cpp
src/SimulationLogger.cpp
src/MedicalDevice.cpp
include/Environment.h
include/PhysiologyData.h
include/SimulationLogger.h
include/Monitor.h
include/Pump.h
include/Controller.h
include/MedicalDevice.h
${CMD_SRC_DIR}/SimEngine.cpp
${CMD_SRC_DIR}/Monitor.cpp
${CMD_SRC_DIR}/Controller.cpp
${CMD_SRC_DIR}/Pump.cpp
${CMD_SRC_DIR}/SimulationLogger.cpp
${CMD_SRC_DIR}/MedicalDevice.cpp
)
......@@ -71,4 +67,3 @@ endforeach()
add_custom_command(TARGET HowToDriver POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${INSTALL_BIN}/${CONFIGURATION}${EX_CONFIG}
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:HowToDriver> ${INSTALL_BIN}/${CONFIGURATION}${EX_CONFIG})
......@@ -9,6 +9,7 @@
#include <limits>
#include <math.h>
#include <cmath>
#include <map>
#include <stdlib.h> // srand()
#include <ctime>
......@@ -26,6 +27,7 @@
using namespace std;
using namespace libconfig;
class Pump;
class Controller {
private:
......@@ -43,14 +45,18 @@ class Controller {
unsigned input_period;
static vector<PhysiologyData> patient_state;
Environment* m_env;
CMD::Environment* m_env;
PhysiologyData* m_data;
std::map<string, Pump*> m_pumps;
//function variable for functions to set pump rates
//void pumpSetRate; // assuming dictionary
public:
// Constructor
Controller(Environment*, PhysiologyData*);
Controller(CMD::Environment*, PhysiologyData*, std::map<string, Pump*>&);
Controller();
// Device logic will go in here
......
......@@ -4,25 +4,34 @@
#define ENVIRONMENT_H
#include <memory>
#include <vector>
#include "SimulationLogger.h"
namespace CMD {
struct Environment {
struct Environment {
double engine_timestep; // engine period
double simulation_time; // grab from config file in seconds
unsigned long simulation_timesteps; // how long should simulation run
unsigned long time_index; // track engine advancement time
unsigned long vector_index; // track size of vector used to pass data between objects ie. vector<PhysiologyData>
double engine_timestep; // engine period
double simulation_time; // grab from config file in seconds
unsigned long simulation_timesteps; // how long should simulation run
unsigned long time_index; // track engine advancement time
unsigned long vector_index; // track size of vector used to pass data between objects ie. vector<PhysiologyData>
unsigned long pump_index;
double simulation_injury_start;
double simulation_injury_stop;
std::shared_ptr<SimulationLogger> logger;
unsigned long simulation_injury_start_timestep;
unsigned long simulation_injury_stop_timestep;
vector<string> patients;
};
unsigned long pump_index;
std::shared_ptr<SimulationLogger> logger;
#endif
};
}
#endif
......@@ -35,20 +35,21 @@ class Monitor : public MedicalDevice {
bool BloodPressure;
double output_rate_Hz;
double m_rate_Hz;
double time_step;
double heart_rate;
unsigned int input_period;
unsigned int output_period;
Environment* m_env;
CMD::Environment* m_env;
PhysiologyData* m_data;
public:
// Constructor
Monitor();
Monitor(Environment*, PhysiologyData*);
Monitor(CMD::Environment*, PhysiologyData*);
// Device logic will go in here
// This function uses the engine object to query required info
......
......@@ -38,10 +38,15 @@ class Pump : public MedicalDevice {
unsigned long period;
int pump_rate;
static vector< pair<int, unsigned long> > pump_data;
bool LOG_INITIAL_PUMP_RATE;
Environment* m_env;
// rate, time_index
vector< pair<int, unsigned long> > pump_data;
CMD::Environment* m_env;
PhysiologyData* m_data;
string m_substance;
SESubstanceCompoundInfusion* m_infusion;
......@@ -53,9 +58,9 @@ class Pump : public MedicalDevice {
//Default Constructor
Pump();
//Overload Constructor
Pump(Environment*, PhysiologyData*);
Pump(CMD::Environment*, PhysiologyData*, string);
static void ChangePumpRate(int, unsigned long);
void ChangePumpRate(int, unsigned long);
// Device logic will go in here
// This function uses the engine object to query required info
......
#ifndef SIMENGINE_H
#define SIMENGINE_H
#include<string>
void Simulation(const std::string);
void Simulation();
void Global_LoadConfig(std::unique_ptr<PhysiologyEngine>&, Config*, const char*, Environment*);
void Global_LoadConfig(std::unique_ptr<PhysiologyEngine>&, const std::shared_ptr<Config>&, const char*, CMD::Environment*);
vector<string> get_global_patients(const char*, const std::shared_ptr<Config>& );
#endif
......@@ -7,6 +7,7 @@
#include <fstream>
#include <string>
#include <typeinfo>
#include<utility>
#include "PhysiologyData.h"
......@@ -17,7 +18,7 @@ class SimulationLogger {
private:
const char* m_filename;
const string m_filename;
ofstream m_out_file;
......@@ -26,8 +27,8 @@ class SimulationLogger {
SimulationLogger();
//Overload constructor
SimulationLogger(const char*);
SimulationLogger(const string);
void LogData(double, string, string, string, PhysiologyData&);
void LogRate(double, string, string, string, int);
......
......@@ -7,15 +7,16 @@ Controller::Controller(): MAX_RATE_Hz(50.0) {
// Overloard Constructor
Controller::Controller(Environment* env, PhysiologyData* data) : m_env(env),
m_data(data), MAX_RATE_Hz(50.0) {
Controller::Controller(CMD::Environment* env, PhysiologyData* data, std::map<string, Pump*>& pumps ) : m_env(env),
m_data(data), m_pumps(pumps), MAX_RATE_Hz(50.0) {
srand(time(0)); // seed values using system time
// initialise array from which rates will be picked randomly
array_rate[0] = 200;
array_rate[1] = 250;
array_rate[2] = 300;
array_rate[3] = 150;
array_rate[0] = 300;
array_rate[1] = 350;
array_rate[2] = 200;
//array_rate[3] = 50;
}
......@@ -43,37 +44,69 @@ void Controller::update(std::unique_ptr<PhysiologyEngine>& engine) {
patient_state.at(m_env->vector_index-1)
);
/*
// why cant't I compare using patient value
//double p = patient_state.at(m_env->vector_index-1).pressure;
//cout <<p<<endl;
if ( m_env->time_index % 32 == 0/* p < 94.0 doesn't work*/) {
double p = patient_state.at(m_env->vector_index-1).pressure;
double value = (int)(p*100 + .5);
double v = (double)value / 100;
bool x = (p > 95.07);
cout <<x<<endl;
*/
//if ( x) doesn't work if x is not true for first loop
new_rate = array_rate[rand() % 4];
if ( m_env->time_index % 96 == 0 ) {
new_rate = array_rate[rand() % 3];
m_env->logger->LogRate(
engine->GetSimulationTime(TimeUnit::s),
"Controller",
"RATE_CHANGE",
"Controller sends Command to Pump",
"Controller sends Command to saline Pump",
new_rate
);
cout<< "Command SENT to PUMP: "<< engine->
cout<< "Command SENT to saline PUMP: "<< engine->
GetSimulationTime(TimeUnit::s)<<"s\n";
//Send information to pump (rate, time index)
//Pump::pump_data.push_back(make_pair(200, m_env->time_index));
SetRate(new_rate, m_env->time_index);
//SetRate(new_rate, m_env->time_index);
//cout << "Invoking Change Pump rate command" << endl;
//cout << "new rate " << new_rate << endl;
//cout << "Controller time index " << m_env->time_index << endl;
//m_env->pump_index++;
}
m_pumps["saline"]->ChangePumpRate(new_rate, m_env->time_index);
/*
cout<< "Command SENT to bpdrug PUMP: "<< engine->
GetSimulationTime(TimeUnit::s)<<"s\n";
}
m_env->logger->LogRate(
engine->GetSimulationTime(TimeUnit::s),
"Controller",
"RATE_CHANGE",
"Controller sends Command to bpdrug Pump",
new_rate
);
//m_pumps["bpdrug"]->ChangePumpRate(new_rate, m_env->time_index);
//pumpSetRate['saline'](salinerate);
//pumpSetRate['BPdrug'](bprate);
*/
//m_env->pump_index++;
}
} // End check input rate condition
};
}; // End Controller update()
void Controller::LoadConfig(std::unique_ptr<PhysiologyEngine>& engine, const char* file_path) {
......@@ -119,11 +152,7 @@ void Controller::LoadConfig(std::unique_ptr<PhysiologyEngine>& engine, const cha
// Activate patient variables Physiology Data
m_data->HeartRate = (find(p_data.begin(), p_data.end(), "HeartRate") != p_data.end()) ? true : false;
m_data->BloodVolume = (find(p_data.begin(), p_data.end(), "BloodVolume") != p_data.end()) ? true : false;
m_data->BloodPressure = (find(p_data.begin(), p_data.end(), "BloodPressure") != p_data.end()) ? true : false;
......@@ -131,11 +160,10 @@ void Controller::LoadConfig(std::unique_ptr<PhysiologyEngine>& engine, const cha
time_step = engine->GetTimeStep(TimeUnit::s);
//MAX_RATE_Hz = 1/time_step;
// integer input rate for controller
input_period = (1/controller_rate_Hz) / time_step;
is_input_multiple = fmod(MAX_RATE_Hz, controller_rate_Hz) == 0.0;
//is_input_multiple = fmod(MAX_RATE_Hz, controller_rate_Hz) == 0.0;
is_input_multiple = ((int)(MAX_RATE_Hz*1000)) % ((int)(controller_rate_Hz*1000)) == 0;
if(controller_rate_Hz > MAX_RATE_Hz) {
......@@ -227,7 +255,7 @@ void Controller::Stop() {
void Controller::SetRate(int rate, unsigned int time_index) {
Pump::ChangePumpRate(rate, m_env->time_index );
// Pump::ChangePumpRate(rate, m_env->time_index );
}
......
......@@ -8,7 +8,7 @@ Monitor::Monitor() {
//Overload Constructor
Monitor::Monitor(Environment* env, PhysiologyData* data): m_env(env), m_data(data) {
Monitor::Monitor(CMD::Environment* env, PhysiologyData* data): m_env(env), m_data(data) {
//cout << endl << className << endl;
//className = typeid(*this).name();
......@@ -87,15 +87,16 @@ void Monitor::LoadConfig(std::unique_ptr<PhysiologyEngine>& engine, const char*
m_rate_Hz = m_cfg.lookup("monitor.input_rate");
output_rate_Hz = m_cfg.lookup("monitor.output_rate");
// Get engine time step/period
time_step = engine->GetTimeStep(TimeUnit::s);
/*Had issues with fmod*/
// Check if rate provided in config file is multiple of MAX_RATE_Hz
is_input_multiple = fmod(MAX_RATE_Hz, m_rate_Hz) == 0.0;
is_output_multiple = fmod(MAX_RATE_Hz, output_rate_Hz) == 0.0;
//is_input_multiple = fmod(MAX_RATE_Hz, m_rate_Hz) == 0.0;
//is_output_multiple = fmod(MAX_RATE_Hz, output_rate_Hz) == 0.0;
is_input_multiple = ((int)(MAX_RATE_Hz*1000)) % ((int)(m_rate_Hz*1000)) == 0;
is_output_multiple = ((int)(MAX_RATE_Hz*1000)) % ((int)(output_rate_Hz*1000)) == 0;
// Convert frequence to integer period
//i.e. freq:25Hz period:0.04 int_period: (0.04/time_step) = 2
......
......@@ -9,8 +9,9 @@ Pump::Pump()
//Overload Constructor
Pump::Pump(Environment* env, PhysiologyData* data): m_env(env), m_data(data),
pump_rate(100) {
Pump::Pump(CMD::Environment* env, PhysiologyData* data, string substance): m_env(env), m_data(data),
m_substance(substance), pump_rate(0), LOG_INITIAL_PUMP_RATE(true), pump_data{make_pair(0,0ul)} {
//pump_data = {make_pair(0,0ul)};
}
......@@ -18,11 +19,13 @@ Pump::Pump(Environment* env, PhysiologyData* data): m_env(env), m_data(data),
void Pump::update(std::unique_ptr<PhysiologyEngine>& engine) {
if(m_env->time_index == 0) {
if(LOG_INITIAL_PUMP_RATE /*m_env->time_index == 0*/) {
m_env->logger->LogRate(
engine->GetSimulationTime(TimeUnit::s),
"Pump",
"Pump "+m_substance,
"RATE_CHANGE",
"Initial Pump rate",
pump_rate
......@@ -30,13 +33,18 @@ void Pump::update(std::unique_ptr<PhysiologyEngine>& engine) {
}
LOG_INITIAL_PUMP_RATE = false;
//cout << "Time index " << m_env->time_index << endl;
//cout << "Time index passed to pump " << pump_data.back().second << endl;
if(m_env->time_index - pump_data.back().second == delay_period) {
// update pump rate
SetInfusionRate(engine, pump_data.back().first);
m_env->logger->LogRate(
engine->GetSimulationTime(TimeUnit::s),
"Pump",
"Pump "+m_substance,
"RATE_CHANGE",
"EXECUTE Command from Controller",
pump_rate
......@@ -81,9 +89,7 @@ void Pump::LoadConfig(std::unique_ptr<PhysiologyEngine>& engine, const char* fil
// integer input rate for controller
input_period = (1/pump_rate_Hz) / time_step;
delay_period = (pump_delay/ time_step);
period = input_period + delay_period;
is_input_multiple = fmod(MAX_RATE_Hz, pump_rate_Hz) == 0.0;
......@@ -102,8 +108,8 @@ void Pump::LoadConfig(std::unique_ptr<PhysiologyEngine>& engine, const char* fil
}
// instatiate indusion compound
SESubstanceCompound* saline = engine->GetSubstanceManager().GetCompound("Saline");
// instatiate infusion compound
SESubstanceCompound* saline = engine->GetSubstanceManager().GetCompound(m_substance);
m_infusion = new SESubstanceCompoundInfusion(*saline);
//the total volume in the bag of Saline
......@@ -118,13 +124,13 @@ void Pump::SetInfusionRate(std::unique_ptr<PhysiologyEngine>& eng, int infusion_
pump_rate = infusion_rate;
//The rate to admnister the compound in the bag in this case saline
m_infusion->GetRate().SetValue(pump_rate, VolumePerTimeUnit::mL_Per_min);
m_infusion->GetRate().SetValue(pump_rate, VolumePerTimeUnit::mL_Per_hr);
eng->ProcessAction(*m_infusion);
// Can't get curent BAG volume : returns the inital set volume ie 500
//cout << "CURRENT BAG Volume" << m_infusion->GetBagVolume().GetValue(VolumeUnit::mL)<< endl;
cout<<"Pump rate changed to: " << pump_rate <<endl;
cout<< m_substance+"_Pump rate changed to: " << pump_rate <<endl;
cout<<"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
}
......@@ -144,9 +150,11 @@ void Pump::Stop() {
throw "Error";
}
//To be used later
//bool Pump::command = false;
bool Pump::command = false;
vector< pair<int, unsigned long> > Pump::pump_data;
//Nolonger static variable
//vector< pair<int, unsigned long> > Pump::pump_data;
// Destructor
......
This diff is collapsed.
......@@ -7,7 +7,7 @@ SimulationLogger::SimulationLogger() {
//Overload Constructor
SimulationLogger::SimulationLogger(const char* filename) : m_filename(filename) {
SimulationLogger::SimulationLogger(const string filename) : m_filename(move(filename)) {
// open file
m_out_file.open(m_filename);
......
#include "Controller.h"
//Default constructor
Controller::Controller(): MAX_RATE_Hz(50.0) {
}
// Overloard Constructor
Controller::Controller(CMD::Environment* env, PhysiologyData* data, std::map<string, Pump*>& pumps ) : m_env(env),
m_data(data), m_pumps(pumps), MAX_RATE_Hz(50.0) {
srand(time(0)); // seed values using system time
// initialise array from which rates will be picked randomly
array_rate[0] = 300;
array_rate[1] = 350;
array_rate[2] = 200;
//array_rate[3] = 50;
}
void Controller::update(std::unique_ptr<PhysiologyEngine>& engine) {
// check controller input rate
if (m_env->time_index % input_period == 0) {
cout<<"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
cout<<"Controller receives data from Monitor at: "<<engine->
GetSimulationTime(TimeUnit::s)<<"s\n";
// Gets data from Monitor
GetData();
m_env->logger->LogData(
engine->GetSimulationTime(TimeUnit::s),
"Controller",
"RECEIVE",
"Received data from Monitor BP",
patient_state.at(m_env->vector_index-1)
);
/*
// why cant't I compare using patient value
double p = patient_state.at(m_env->vector_index-1).pressure;
double value = (int)(p*100 + .5);
double v = (double)value / 100;
bool x = (p > 95.07);
cout <<x<<endl;
*/
//if ( x) doesn't work if x is not true for first loop
if ( m_env->time_index % 96 == 0 ) {
new_rate = array_rate[rand() % 3];
m_env->logger->LogRate(
engine->GetSimulationTime(TimeUnit::s),
"Controller",
"RATE_CHANGE",
"Controller sends Command to saline Pump",
new_rate
);
cout<< "Command SENT to saline PUMP: "<< engine->
GetSimulationTime(TimeUnit::s)<<"s\n";
//Send information to pump (rate, time index)
//SetRate(new_rate, m_env->time_index);
//cout << "Invoking Change Pump rate command" << endl;
//cout << "new rate " << new_rate << endl;
//cout << "Controller time index " << m_env->time_index << endl;
m_pumps["saline"]->ChangePumpRate(new_rate, m_env->time_index);
/*
cout<< "Command SENT to bpdrug PUMP: "<< engine->
GetSimulationTime(TimeUnit::s)<<"s\n";
m_env->logger->LogRate(
engine->GetSimulationTime(TimeUnit::s),
"Controller",
"RATE_CHANGE",
"Controller sends Command to bpdrug Pump",
new_rate
);
//m_pumps["bpdrug"]->ChangePumpRate(new_rate, m_env->time_index);
//pumpSetRate['saline'](salinerate);
//pumpSetRate['BPdrug'](bprate);
*/
//m_env->pump_index++;
}
} // End check input rate condition
}; // End Controller update()
void Controller::LoadConfig(std::unique_ptr<PhysiologyEngine>& engine, const char* file_path) {
try
{
// Read configration file
cfg.readFile(file_path);
}
catch(const FileIOException &fioex)
{
std::cerr << "I/O error while reading file." << std::endl;
}
catch(const ParseException &pex)
{
std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
<< " - " << pex.getError() << std::endl;
}
// Extract the rate and assign it to m_rate_Hz
controller_rate_Hz = cfg.lookup("controller.rate");
Setting& root = cfg.getRoot();
Setting& enabled = root["controller"]["patientData"]["enabled"];
const char* value;
vector<string> p_data;
for (Setting& vital : enabled) {
value = vital;
p_data.push_back(string(value));
}
// Activate patient variables Physiology Data
m_data->HeartRate = (find(p_data.begin(), p_data.end(), "HeartRate") != p_data.end()) ? true : false;
m_data->BloodVolume = (find(p_data.begin(), p_data.end(), "BloodVolume") != p_data.end()) ? true : false;
m_data->BloodPressure = (find(p_data.begin(), p_data.end(), "BloodPressure") != p_data.end()) ? true : false;
time_step = engine->GetTimeStep(TimeUnit::s);
//MAX_RATE_Hz = 1/time_step;
// integer input rate for controller
input_period = (1/controller_rate_Hz) / time_step;
//is_input_multiple = fmod(MAX_RATE_Hz, controller_rate_Hz) == 0.0;
is_input_multiple = ((int)(MAX_RATE_Hz*1000)) % ((int)(controller_rate_Hz*1000)) == 0;
if(controller_rate_Hz > MAX_RATE_Hz) {
cout <<"\nController rate is greater than MAX: 50.0\n\n";
Stop();
}
else if(!is_input_multiple) {
cout <<"\nController rate is not a multiple of MAX: 50.0\n\n";
Stop();
}
}
void Controller::SendValues(PhysiologyData& data) {
//patient_state.emplace_back(value);
patient_state.push_back(data);
}
void Controller::GetData() {
// The following are activated in the config file if controller
// requires them and set to NaN if not required
cout<<"CONTROLLER DATA\n";
if (m_data->HeartRate){
cout<< "Heart Rate: "<<patient_state.at(m_env->
vector_index-1).heart_rate<<endl;
}
else {
patient_state.at(m_env->
vector_index-1).heart_rate=numeric_limits<double>::quiet_NaN();
}
if (m_data->BloodPressure) {
cout<< "Pressure: "<<patient_state.at(m_env->
vector_index-1).pressure<<endl;
}
else {
patient_state.at(m_env->
vector_index-1).pressure=numeric_limits<double>::quiet_NaN();
}
if (m_data->BloodVolume) {
cout<< "Blood Volume: "<<patient_state.at(m_env->
vector_index-1).blood_volume<<endl;
}
else {
patient_state.at(m_env->
vector_index-1).blood_volume=numeric_limits<double>::quiet_NaN();
}
cout<<"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
}
// initialise static variable
vector<PhysiologyData> Controller::patient_state;
//const int Controller::array_sz = 4;
void Controller::Stop() {
throw "Error";
}