13 #include <argos3/core/utility/logging/argos_log.h>
14 #include <argos3/core/utility/profiler/profiler.h>
15 #include <argos3/core/utility/string_utilities.h>
16 #include <argos3/core/utility/plugins/dynamic_loading.h>
17 #include <argos3/core/utility/math/rng.h>
18 #include <argos3/core/simulator/space/space_no_threads.h>
19 #include <argos3/core/simulator/space/space_multi_thread_balance_quantity.h>
20 #include <argos3/core/simulator/space/space_multi_thread_balance_length.h>
21 #include <argos3/core/simulator/visualization/default_visualization.h>
22 #include <argos3/core/simulator/physics_engine/physics_engine.h>
23 #include <argos3/core/simulator/loop_functions.h>
24 #include <argos3/core/simulator/entity/composable_entity.h>
25 #include <argos3/core/simulator/entity/embodied_entity.h>
32 CSimulator::CSimulator() :
33 m_pcVisualization(nullptr),
35 m_pcLoopFunctions(nullptr),
36 m_unMaxSimulationClock(0),
37 m_bWasRandomSeedSet(false),
39 m_pcProfiler(nullptr),
40 m_bHumanReadableProfile(true),
41 m_bRealTimeClock(false),
42 m_bTerminated(false) {}
47 CSimulator::~CSimulator() {
52 if(m_pcVisualization !=
nullptr)
delete m_pcVisualization;
54 for(
auto it = m_mapMedia.begin();
55 it != m_mapMedia.end(); ++it) {
61 for(
auto it = m_mapPhysicsEngines.begin();
62 it != m_mapPhysicsEngines.end(); ++it) {
65 m_mapPhysicsEngines.clear();
66 m_vecPhysicsEngines.clear();
68 if(m_pcSpace !=
nullptr) {
72 CDynamicLoading::UnloadAllLibraries();
79 static std::unique_ptr<CSimulator> pcSimulatorInstance(
new CSimulator());
80 return *(pcSimulatorInstance.get());
86 CPhysicsEngine& CSimulator::GetPhysicsEngine(
const std::string& str_id)
const {
87 auto it = m_mapPhysicsEngines.find(str_id);
88 ARGOS_ASSERT(it != m_mapPhysicsEngines.end(),
"Physics engine \"" << str_id <<
"\" not found.")
96 auto it = m_mapControllerConfig.find(str_id);
97 if(it == m_mapControllerConfig.end()) {
100 return *(it->second);
106 void CSimulator::Load(ticpp::Document& t_tree) {
108 m_tConfiguration = t_tree;
109 m_tConfigurationRoot = *m_tConfiguration.FirstChildElement();
119 void CSimulator::LoadExperiment() {
121 m_tConfiguration.LoadFile(m_strExperimentConfigFileName);
122 m_tConfigurationRoot = *m_tConfiguration.FirstChildElement();
132 void CSimulator::Init() {
134 InitFramework(
GetNode(m_tConfigurationRoot,
"framework"));
136 InitControllers(
GetNode(m_tConfigurationRoot,
"controllers"));
138 if(
NodeExists(m_tConfigurationRoot,
"loop_functions")) {
140 InitLoopFunctions(
GetNode(m_tConfigurationRoot,
"loop_functions"));
147 InitPhysics(
GetNode(m_tConfigurationRoot,
"physics_engines"));
149 InitMedia(
GetNode(m_tConfigurationRoot,
"media"));
151 InitSpace(
GetNode(m_tConfigurationRoot,
"arena"));
153 if(
NodeExists(m_tConfigurationRoot,
"loop_functions")) {
154 m_pcLoopFunctions->Init(
GetNode(m_tConfigurationRoot,
"loop_functions"));
162 if(
NodeExists(m_tConfigurationRoot,
"visualization") &&
163 ((itVisualization = itVisualization.begin(&
GetNode(m_tConfigurationRoot,
"visualization"))) != itVisualization.end())) {
164 InitVisualization(
GetNode(m_tConfigurationRoot,
"visualization"));
167 LOG <<
"[INFO] No visualization selected." << std::endl;
172 m_pcProfiler->Start();
179 void CSimulator::Reset() {
181 m_bTerminated =
false;
183 if(m_bWasRandomSeedSet) {
184 CRandom::SetSeedOf(
"argos", m_unRandomSeed);
188 struct timeval sTimeValue;
189 ::gettimeofday(&sTimeValue,
nullptr);
190 auto unSeed =
static_cast<UInt32>(sTimeValue.tv_usec);
191 CRandom::SetSeedOf(
"argos", unSeed);
192 m_unRandomSeed = unSeed;
193 LOG <<
"[INFO] Using random seed = " << m_unRandomSeed << std::endl;
195 CRandom::GetCategory(
"argos").ResetRNGs();
199 for(
auto it = m_mapMedia.begin();
200 it != m_mapMedia.end(); ++it) {
204 for(
auto it = m_mapPhysicsEngines.begin();
205 it != m_mapPhysicsEngines.end(); ++it) {
209 m_pcLoopFunctions->Reset();
217 void CSimulator::Destroy() {
219 if (m_pcLoopFunctions !=
nullptr) {
220 m_pcLoopFunctions->Destroy();
221 delete m_pcLoopFunctions;
222 m_pcLoopFunctions =
nullptr;
225 if(m_pcVisualization !=
nullptr) {
226 m_pcVisualization->Destroy();
229 if(m_pcSpace !=
nullptr) {
230 m_pcSpace->Destroy();
233 for(
auto it = m_mapMedia.begin();
234 it != m_mapMedia.end(); ++it) {
235 it->second->Destroy();
241 for(
auto it = m_mapPhysicsEngines.begin();
242 it != m_mapPhysicsEngines.end(); ++it) {
243 it->second->Destroy();
246 m_mapPhysicsEngines.clear();
247 m_vecPhysicsEngines.clear();
249 if(CRandom::ExistsCategory(
"argos")) {
250 CRandom::RemoveCategory(
"argos");
263 m_pcProfiler->Stop();
264 m_pcProfiler->Flush(m_bHumanReadableProfile);
273 void CSimulator::Execute() {
274 m_pcVisualization->Execute();
280 void CSimulator::UpdateSpace() {
288 bool CSimulator::IsExperimentFinished()
const {
294 if (m_unMaxSimulationClock > 0 &&
295 m_pcSpace->GetSimulationClock() >= m_unMaxSimulationClock) {
299 return m_pcLoopFunctions->IsExperimentFinished();
310 tSystem =
GetNode(t_tree,
"system");
312 if(m_unThreads == 0) {
313 LOG <<
"[INFO] Not using threads" << std::endl;
317 LOG <<
"[INFO] Using " << m_unThreads <<
" parallel threads" << std::endl;
318 std::string strThreadingMethod =
"balance_quantity";
320 if(strThreadingMethod ==
"balance_quantity") {
321 LOG <<
"[INFO] Chosen method \"balance_quantity\": threads will be assigned the same"
323 <<
"[INFO] number of tasks, independently of the task length."
325 m_pcSpace =
new CSpaceMultiThreadBalanceQuantity();
327 else if(strThreadingMethod ==
"balance_length") {
328 LOG <<
"[INFO] Chosen method \"balance_length\": threads will be assigned different"
330 <<
"[INFO] numbers of tasks, depending on the task length."
332 m_pcSpace =
new CSpaceMultiThreadBalanceLength();
335 THROW_ARGOSEXCEPTION(
"Error parsing the <system> tag. Unknown threading method \"" << strThreadingMethod <<
"\". Available methods: \"balance_quantity\" and \"balance_length\".");
340 LOG <<
"[INFO] Not using threads" << std::endl;
341 m_pcSpace =
new CSpaceNoThreads();
345 tExperiment =
GetNode(t_tree,
"experiment");
348 if(!m_bWasRandomSeedSet)
354 if(m_unRandomSeed != 0) {
355 CRandom::CreateCategory(
"argos", m_unRandomSeed);
356 LOG <<
"[INFO] Using random seed = " << m_unRandomSeed << std::endl;
357 m_bWasRandomSeedSet =
true;
361 m_bWasRandomSeedSet =
false;
362 struct timeval sTimeValue;
363 ::gettimeofday(&sTimeValue,
nullptr);
364 auto unSeed =
static_cast<UInt32>(sTimeValue.tv_usec);
365 m_unRandomSeed = unSeed;
366 CRandom::CreateCategory(
"argos", unSeed);
367 LOG <<
"[INFO] Using random seed = " << unSeed << std::endl;
369 m_pcRNG = CRandom::CreateRNG(
"argos");
375 CPhysicsEngine::SetSimulationClockTick(1.0 /
static_cast<Real>(unTicksPerSec));
378 GetNodeAttributeOrDefault<Real>(tExperiment,
382 m_unMaxSimulationClock =
static_cast<UInt32>(fExpLength * unTicksPerSec);
383 LOG <<
"[INFO] Total experiment length in clock ticks = "
384 << (m_unMaxSimulationClock ?
ToString(m_unMaxSimulationClock) :
"unlimited")
388 if(m_bRealTimeClock) {
389 LOG <<
"[INFO] Using the real-time clock." << std::endl;
396 std::string strFormat;
398 if(strFormat ==
"human_readable") {
399 m_bHumanReadableProfile =
true;
401 else if(strFormat ==
"table") {
402 m_bHumanReadableProfile =
false;
405 THROW_ARGOSEXCEPTION(
"Unrecognized profile format \"" << strFormat <<
"\". Accepted values are \"human_readable\" and \"table\".");
409 m_pcProfiler =
new CProfiler(strFile, bTrunc);
412 catch(CARGoSException& ex) {
422 std::string strLibrary, strLabel;
425 if(! strLibrary.empty()) {
426 CDynamicLoading::LoadLibrary(strLibrary);
428 m_pcLoopFunctions = CFactory<CLoopFunctions>::New(strLabel);
430 catch(CARGoSException& ex) {
443 if(! t_tree.NoChildren()) {
445 std::string strLibrary;
448 for(it = it.begin(&t_tree);
449 it != it.end(); ++it) {
454 catch(CARGoSException& ex) {
455 std::string strValue;
456 it->GetValue(&strValue);
460 if(m_mapControllerConfig.find(strId) != m_mapControllerConfig.end()) {
468 CDynamicLoading::LoadLibrary(strLibrary);
471 m_mapControllerConfig.insert(std::pair<std::string, TConfigurationNode*>(strId, &(*it)));
474 catch(CARGoSException& ex) {
485 m_pcSpace->Init(t_tree);
487 catch(CARGoSException& ex) {
499 for(itEngines = itEngines.begin(&t_tree);
500 itEngines != itEngines.end();
503 CPhysicsEngine* pcEngine = CFactory<CPhysicsEngine>::New(itEngines->Value());
506 pcEngine->Init(*itEngines);
508 if(m_mapPhysicsEngines.find(pcEngine->GetId()) == m_mapPhysicsEngines.end()) {
510 m_mapPhysicsEngines[pcEngine->GetId()] = pcEngine;
511 m_vecPhysicsEngines.push_back(pcEngine);
515 THROW_ARGOSEXCEPTION(
"A physics engine with id \"" << pcEngine->GetId() <<
"\" exists already. The ids must be unique!");
518 catch(CARGoSException& ex) {
526 catch(CARGoSException& ex) {
534 void CSimulator::InitPhysics2() {
537 CPhysicsEngine::TMap::iterator it;
538 for(it = m_mapPhysicsEngines.begin(); it != m_mapPhysicsEngines.end(); ++it) {
539 CPhysicsEngine& cPhysicsEngine = *(it->second);
542 cPhysicsEngine.PostSpaceInit();
544 catch(CARGoSException& ex) {
546 std::ostringstream ossMsg;
547 ossMsg <<
"Error executing post-space initialization of physics engine \"" << cPhysicsEngine.GetId() <<
"\"";
548 cPhysicsEngine.Destroy();
553 catch(CARGoSException& ex) {
565 for(itMedia = itMedia.begin(&t_tree);
566 itMedia != itMedia.end();
569 CMedium* pcMedium = CFactory<CMedium>::New(itMedia->Value());
572 pcMedium->Init(*itMedia);
574 if(m_mapMedia.find(pcMedium->GetId()) == m_mapMedia.end()) {
576 m_mapMedia[pcMedium->GetId()] = pcMedium;
577 m_vecMedia.push_back(pcMedium);
581 THROW_ARGOSEXCEPTION(
"A medium with id \"" << pcMedium->GetId() <<
"\" exists already. The ids must be unique!");
584 catch(CARGoSException& ex) {
592 catch(CARGoSException& ex) {
600 void CSimulator::InitMedia2() {
603 CMedium::TMap::iterator it;
604 for(it = m_mapMedia.begin(); it != m_mapMedia.end(); ++it) {
605 CMedium& cMedium = *(it->second);
608 cMedium.PostSpaceInit();
610 catch(CARGoSException& ex) {
612 std::ostringstream ossMsg;
613 ossMsg <<
"Error executing post-space initialization of medium \"" << cMedium.GetId() <<
"\"";
619 catch(CARGoSException& ex) {
631 itVisualization = itVisualization.begin(&t_tree);
633 m_pcVisualization = CFactory<CVisualization>::New(itVisualization->Value());
635 m_pcVisualization->Init(*itVisualization);
637 catch(CARGoSException& ex) {
#define ARGOS_ASSERT(condition, message)
When code is compiled in debug, this macro throws an ARGoS exception with the passed message if the s...
#define THROW_ARGOSEXCEPTION_NESTED(message, nested)
This macro throws an ARGoS exception with the passed message and nesting the passed exception.
#define THROW_ARGOSEXCEPTION(message)
This macro throws an ARGoS exception with the passed message.
unsigned int UInt32
32-bit unsigned integer.
float Real
Collects all ARGoS code.
The namespace containing all the ARGoS related code.
ticpp::Iterator< ticpp::Element > TConfigurationNodeIterator
The iterator for the ARGoS configuration XML node.
CARGoSLog LOGERR(std::cerr, SLogColor(ARGOS_LOG_ATTRIBUTE_BRIGHT, ARGOS_LOG_COLOR_RED))
TConfigurationNode & GetNode(TConfigurationNode &t_node, const std::string &str_tag)
Given a tree root node, returns the first of its child nodes with the wanted name.
bool NodeAttributeExists(TConfigurationNode &t_node, const std::string &str_attribute)
Returns true if the specified attribute of a node exists.
void GetNodeAttributeOrDefault(TConfigurationNode &t_node, const std::string &str_attribute, T &t_buffer, const T &t_default)
Returns the value of a node's attribute, or the passed default value.
ticpp::Element TConfigurationNode
The ARGoS configuration XML node.
CARGoSLog LOG(std::cout, SLogColor(ARGOS_LOG_ATTRIBUTE_BRIGHT, ARGOS_LOG_COLOR_GREEN))
bool NodeExists(TConfigurationNode &t_node, const std::string &str_tag)
Given a tree root node, returns true if one of its child nodes has the wanted name.
std::string ToString(const T &t_value)
Converts the given parameter to a std::string.
void GetNodeAttribute(TConfigurationNode &t_node, const std::string &str_attribute, T &t_buffer)
Returns the value of a node's attribute.
A set of hook functions to customize an experimental run.