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) {}
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) {
79 static std::unique_ptr<CSimulator> pcSimulatorInstance(
new CSimulator());
80 return *(pcSimulatorInstance.get());
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);
108 m_tConfiguration = t_tree;
109 m_tConfigurationRoot = *m_tConfiguration.FirstChildElement();
121 m_tConfiguration.LoadFile(m_strExperimentConfigFileName);
122 m_tConfigurationRoot = *m_tConfiguration.FirstChildElement();
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();
181 m_bTerminated =
false;
183 if(m_bWasRandomSeedSet) {
188 struct timeval sTimeValue;
189 ::gettimeofday(&sTimeValue,
nullptr);
190 auto unSeed =
static_cast<UInt32>(sTimeValue.tv_usec);
192 m_unRandomSeed = unSeed;
193 LOG <<
"[INFO] Using random seed = " << m_unRandomSeed << std::endl;
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();
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();
263 m_pcProfiler->Stop();
264 m_pcProfiler->Flush(m_bHumanReadableProfile);
274 m_pcVisualization->Execute();
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";
319 GetNodeAttributeOrDefault(tSystem,
"method", strThreadingMethod, strThreadingMethod);
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) {
420 void CSimulator::InitLoopFunctions(TConfigurationNode& t_tree) {
422 std::string strLibrary, strLabel;
425 if(! strLibrary.empty()) {
426 CDynamicLoading::LoadLibrary(strLibrary);
428 m_pcLoopFunctions = CFactory<CLoopFunctions>::New(strLabel);
430 catch(CARGoSException& ex) {
438 void CSimulator::InitControllers(TConfigurationNode& t_tree) {
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) {
483 void CSimulator::InitSpace(TConfigurationNode& t_tree) {
485 m_pcSpace->Init(t_tree);
487 catch(CARGoSException& ex) {
495 void CSimulator::InitPhysics(TConfigurationNode& t_tree) {
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) {
561 void CSimulator::InitMedia(TConfigurationNode& t_tree) {
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) {
627 void CSimulator::InitVisualization(TConfigurationNode& t_tree) {
631 itVisualization = itVisualization.begin(&t_tree);
633 m_pcVisualization = CFactory<CVisualization>::New(itVisualization->Value());
635 m_pcVisualization->Init(*itVisualization);
637 catch(CARGoSException& ex) {
unsigned int UInt32
32-bit unsigned integer.
float Real
Collects all ARGoS code.
#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.
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))
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.
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.
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.
For argos::CTCPSocket::EEvent to be used in std::unordered_set<> and std::unordered_map<>,...
A set of hook functions to customize an experimental run.
void Destroy()
Undoes whatever was done by Init().
~CSimulator()
Class destructor.
void Load(ticpp::Document &t_tree)
Loads an already-parsed XML configuration tree.
void Init()
Initializes the experiment.
static CSimulator & GetInstance()
Returns the instance to the CSimulator class.
bool IsExperimentFinished() const
Returns true if the experiment has finished.
CPhysicsEngine & GetPhysicsEngine(const std::string &str_id) const
Returns a reference to a physics engine.
void Execute()
Executes the simulation loop.
bool IsProfiling() const
Returns true if ARGoS is being profiled.
void LoadExperiment()
Loads the XML configuration file.
void UpdateSpace()
Performs an update step of the space.
TConfigurationNode & GetConfigForController(const std::string &str_id)
Returns the XML portion relative to the controller with the given ID.
void Reset()
Resets the experiment.
static void RemoveCategory(const std::string &str_category)
Removes the wanted category.
static void SetSeedOf(const std::string &str_category, UInt32 un_seed)
Sets the new seed of the wanted category.
static CCategory & GetCategory(const std::string &str_category)
Returns a reference to the wanted category.
static bool ExistsCategory(const std::string &str_category)
Returns true if the given category exists in the pool.
static void UnloadAllLibraries()
Unloads all the dynamic libraries.
static void Destroy()
Frees up all used memory.