In Demo_00, all code was placed in a single file, Demo_00.cpp. For the remainder of this tutorial, a different structure will be used. The structure used represents the common practice among C++ programmers and helps keep a certain order when the code becomes more complicated. The structure also allows the separation of structure from content.
For the remainder of the tutorial, header files will be found in a directory called 'include'; source files (.cpp) will be in a directory called 'src'; the results of compilation will be placed in a directory called 'object'; the results of linking will be placed in a directory called 'bin'; properties files will be kept in a directory called 'props'.
The model code will be divided into three separate components. A 'Demo_01_Main.cpp' file will act as the entry point for the simulation (the int main(argc, argv) function). A second component will be the 'Model' code, now in two separate files (Demo_01_Model.h and Demo_01_Model.cpp). The third component will be the 'Agent' code, in Demo_01_Agent.h and Demo_01_Agent.cpp.
The importance of the makefile should begin to be clearer: each of the .cpp files will have to be compiled separately, and then all of them linked together. All of this will be done automatically with a basic 'make' instruction similar to the one for Demo_00.
The new code comprises five files: Demo_01_Agent.h, Demo_01_Agent.cpp, Demo_01_Model.h, Demo_01_Model.cpp and Demo_01_Main.cpp. (The 'main' function has no structure and is not referred to by any other file, so there is no need to have a 'main.h' file).
We will build the agent class in the next steps of this demo, so for now the code in the agent files is:
/* Demo_01_Agent.h */
#ifndef DEMO_01_AGENT
#define DEMO_01_AGENT
#endif
And:
/* Demo_01_Agent.cpp */
The model is now found in these files:
/* Demo_01_Model.h */
#ifndef DEMO_01_MODEL
#define DEMO_01_MODEL
#include <boost/mpi.hpp>
#include "repast_hpc/Schedule.h"
#include "repast_hpc/Properties.h"
class RepastHPCDemoModel{
int stopAt;
repast::Properties* props;
public:
RepastHPCDemoModel(std::string propsFile, int argc, char** argv, boost::mpi::communicator* comm);
~RepastHPCDemoModel();
void init();
void doSomething();
void initSchedule(repast::ScheduleRunner& runner);
void recordResults();
};
#endif
And
/* Demo_01_Model.cpp */
#include <stdio.h>
#include <vector>
#include <boost/mpi.hpp>
#include "repast_hpc/RepastProcess.h"
#include "Utilities.h.h"
#include "repast_hpc/Properties.h"
#include "Demo_01_Model.h"
RepastHPCDemoModel::RepastHPCDemoModel(std::string propsFile, int argc, char** argv, boost::mpi::communicator* comm){
props = new repast::Properties(propsFile, argc, argv, comm);
stopAt = repast::strToInt(props->getProperty("stop.at"));
if(repast::RepastProcess::instance()->rank() == 0) props->writeToSVFile("./output/record.csv");
}
RepastHPCDemoModel::~RepastHPCDemoModel(){
delete props;
}
void RepastHPCDemoModel::init(){}
void RepastHPCDemoModel::doSomething(){
std::cout << "Rank " << repast::RepastProcess::instance()->rank() << " is doing something." << std::endl;
}
void RepastHPCDemoModel::initSchedule(repast::ScheduleRunner& runner){
runner.scheduleEvent(1, 1, repast::Schedule::FunctorPtr(new repast::MethodFunctor<RepastHPCDemoModel> (this, &RepastHPCDemoModel::doSomething)));
runner.scheduleEndEvent(repast::Schedule::FunctorPtr(new repast::MethodFunctor<RepastHPCDemoModel> (this, &RepastHPCDemoModel::recordResults)));
runner.scheduleStop(stopAt);
}
void RepastHPCDemoModel::recordResults(){
if(repast::RepastProcess::instance()->rank() == 0){
props->putProperty("Result","Passed");
std::vector<std::string> keyOrder;
keyOrder.push_back("RunNumber");
keyOrder.push_back("stop.at");
keyOrder.push_back("Result");
props->writeToSVFile("./output/results.csv", keyOrder);
}
}
And the main function is defined as:
/* Demo_01_Main.cpp */
#include <boost/mpi.hpp>
#include "repast_hpc/RepastProcess.h"
#include "Demo_01_Model.h"
int main(int argc, char** argv){
std::string configFile = argv[1]; // The name of the configuration file is Arg 1
std::string propsFile = argv[2]; // The name of the properties file is Arg 2
boost::mpi::environment env(argc, argv);
boost::mpi::communicator world;
repast::RepastProcess::init(configFile);
RepastHPCDemoModel* model = new RepastHPCDemoModel(propsFile, argc, argv, &world);
repast::ScheduleRunner& runner = repast::RepastProcess::instance()->getScheduleRunner();
model->init();
model->initSchedule(runner);
runner.run();
delete model;
repast::RepastProcess::instance()->done();
}
The 'main' function does not need to be altered during the rest of this demo: it already contains all that it needs to run a RepastHPC model.
Note also that invoking this model requires adding the full paths to the executable and properties files, as:
mpirun -n 4 ./bin/Demo_01.exe ./props/config.props ./props/model.props RunNumber=1 stop.at=5