Program Listing for File ModelDescription.cpp
↰ Return to documentation for file (src/flamegpu/model/ModelDescription.cpp
)
#include "flamegpu/model/ModelDescription.h"
#include <string>
#include <memory>
#include "flamegpu/model/DependencyGraph.h"
#include "flamegpu/model/AgentDescription.h"
#include "flamegpu/model/LayerDescription.h"
#include "flamegpu/exception/FLAMEGPUException.h"
#include "flamegpu/model/EnvironmentDescription.h"
#include "flamegpu/runtime/messaging/MessageBruteForce.h"
#include "flamegpu/model/SubModelData.h"
#include "flamegpu/model/SubModelDescription.h"
#include "flamegpu/model/SubEnvironmentDescription.h"
namespace flamegpu {
ModelDescription::ModelDescription(const std::string &model_name)
: model(new ModelData(model_name)) {
model->environment = std::shared_ptr<EnvironmentData>(new EnvironmentData(model));
}
bool ModelDescription::operator==(const ModelDescription& rhs) const {
return *this->model == *rhs.model; // Compare content is functionally the same
}
bool ModelDescription::operator!=(const ModelDescription& rhs) const {
return !(*this == rhs);
}
AgentDescription ModelDescription::newAgent(const std::string &agent_name) {
if (!hasAgent(agent_name)) {
auto rtn = std::shared_ptr<AgentData>(new AgentData(model, agent_name));
model->agents.emplace(agent_name, rtn);
return AgentDescription(rtn);
}
THROW exception::InvalidAgentName("Agent with name '%s' already exists, "
"in ModelDescription::newAgent().",
agent_name.c_str());
}
AgentDescription ModelDescription::Agent(const std::string &agent_name) {
auto rtn = model->agents.find(agent_name);
if (rtn != model->agents.end())
return AgentDescription(rtn->second);
THROW exception::InvalidAgentName("Agent ('%s') was not found, "
"in ModelDescription::Agent().",
agent_name.c_str());
}
MessageBruteForce::Description ModelDescription::newMessage(const std::string &message_name) {
return newMessage<MessageBruteForce>(message_name);
}
MessageBruteForce::Description ModelDescription::Message(const std::string &message_name) {
return Message<MessageBruteForce>(message_name);
}
EnvironmentDescription ModelDescription::Environment() {
return EnvironmentDescription(model->environment);
}
SubModelDescription ModelDescription::newSubModel(const std::string &submodel_name, const ModelDescription &submodel_description) {
// Submodel is not self
if (submodel_description.model == this->model) {
THROW exception::InvalidSubModel("A model cannot be a submodel of itself, that would create infinite recursion, "
"in ModelDescription::newSubModel().");
}
// Submodel is not already a submodel of this model
for (auto &m : this->model->submodels) {
if (m.second->submodel == submodel_description.model) {
THROW exception::InvalidSubModel("Model '%s' is already a submodel of '%s', "
"in ModelDescription::newSubModel().",
submodel_name.c_str(), this->model->name.c_str());
}
}
// Submodel is not already in the submodel hierarchy above us
if (submodel_description.model->hasSubModelRecursive(this->model)) {
THROW exception::InvalidSubModel("Models cannot exist in their own submodel hierarchy, that would create infinite recursion,"
"in ModelDescription::newSubModel().");
}
// Submodel name is not in use
if (!hasSubModel(submodel_name)) {
auto rtn = std::shared_ptr<SubModelData>(new SubModelData(model, submodel_name, submodel_description.model));
model->submodels.emplace(submodel_name, rtn);
// This will actually generate the environment mapping (cant do it in constructor, due to shared_from_this)
// Not the end of the world if it isn't init (we should be able to catch it down the line), but safer this way
SubModelDescription rtn2(rtn);
rtn2.SubEnvironment(false);
return rtn2;
}
THROW exception::InvalidSubModelName("SubModel with name '%s' already exists, "
"in ModelDescription::newSubModel().",
submodel_name.c_str());
}
SubModelDescription ModelDescription::SubModel(const std::string &submodel_name) {
auto rtn = model->submodels.find(submodel_name);
if (rtn != model->submodels.end())
return SubModelDescription(rtn->second);
THROW exception::InvalidSubModelName("SubModel ('%s') was not found, "
"in ModelDescription::SubModel().",
submodel_name.c_str());
}
LayerDescription ModelDescription::newLayer(const std::string &name) {
// Ensure name is unique
if (!name.empty()) {
for (auto it = model->layers.begin(); it != model->layers.end(); ++it) {
if ((*it)->name == name) {
THROW exception::InvalidFuncLayerIndx("Layer ('%s') already exists, "
"in ModelDescription::newLayer().",
name.c_str());
}
}
}
auto rtn = std::shared_ptr<LayerData>(new LayerData(model, name, static_cast<unsigned int>(model->layers.size())));
model->layers.push_back(rtn);
return LayerDescription(rtn);
}
LayerDescription ModelDescription::Layer(const flamegpu::size_type &layer_index) {
if (model->layers.size() > layer_index) {
auto it = model->layers.begin();
for (auto i = 0u; i < layer_index; ++i)
++it;
return LayerDescription(*it);
}
THROW exception::OutOfBoundsException("Layer %d is out of bounds, "
"in ModelDescription::Layer().",
layer_index);
}
LayerDescription ModelDescription::Layer(const std::string &name) {
if (!name.empty()) { // Can't search for no name, multiple layers might be nameless
for (auto &layer : model->layers) {
if (layer->name == name)
return LayerDescription(layer);
}
}
THROW exception::InvalidFuncLayerIndx("Layer '%s' was not found, "
"in ModelDescription::Layer().",
name.c_str());
}
void ModelDescription::addInitFunction(FLAMEGPU_INIT_FUNCTION_POINTER func_p) {
if (std::find(model->initFunctions.begin(), model->initFunctions.end(), func_p) != model->initFunctions.end()) {
THROW exception::InvalidHostFunc("Attempted to add same init function twice,"
"in ModelDescription::addInitFunction()");
}
model->initFunctions.push_back(func_p);
}
void ModelDescription::addStepFunction(FLAMEGPU_STEP_FUNCTION_POINTER func_p) {
if (std::find(model->stepFunctions.begin(), model->stepFunctions.end(), func_p) != model->stepFunctions.end()) {
THROW exception::InvalidHostFunc("Attempted to add same step function twice,"
"in ModelDescription::addStepFunction()");
}
model->stepFunctions.push_back(func_p);
}
void ModelDescription::addExitFunction(FLAMEGPU_EXIT_FUNCTION_POINTER func_p) {
if (std::find(model->exitFunctions.begin(), model->exitFunctions.end(), func_p) != model->exitFunctions.end()) {
THROW exception::InvalidHostFunc("Attempted to add same exit function twice,"
"in ModelDescription::addExitFunction()");
}
model->exitFunctions.push_back(func_p);
}
void ModelDescription::addExitCondition(FLAMEGPU_EXIT_CONDITION_POINTER func_p) {
if (std::find(model->exitConditions.begin(), model->exitConditions.end(), func_p) != model->exitConditions.end()) {
THROW exception::InvalidHostFunc("Attempted to add same exit condition twice,"
"in ModelDescription::addExitCondition()");
}
model->exitConditions.push_back(func_p);
}
void ModelDescription::addExecutionRoot(DependencyNode& root) {
model->dependencyGraph->addRoot(root);
}
void ModelDescription::generateLayers() {
model->dependencyGraph->generateLayers();
}
std::string ModelDescription::getName() const {
return model->name;
}
CAgentDescription ModelDescription::getAgent(const std::string& agent_name) const {
const auto rtn = model->agents.find(agent_name);
if (rtn != model->agents.end())
return CAgentDescription(rtn->second);
THROW exception::InvalidAgentName("Agent ('%s') was not found, "
"in ModelDescription::getAgent().",
agent_name.c_str());
}
MessageBruteForce::CDescription ModelDescription::getMessage(const std::string &message_name) const {
return getMessage<MessageBruteForce>(message_name);
}
CSubModelDescription ModelDescription::getSubModel(const std::string &submodel_name) const {
const auto rtn = model->submodels.find(submodel_name);
if (rtn != model->submodels.end())
return CSubModelDescription(rtn->second);
THROW exception::InvalidSubModelName("SubModel ('%s') was not found, "
"in ModelDescription::getSubModel().",
submodel_name.c_str());
}
CEnvironmentDescription ModelDescription::getEnvironment() const {
return CEnvironmentDescription(model->environment);
}
CLayerDescription ModelDescription::getLayer(const std::string &name) const {
if (!name.empty()) { // Can't search for no name, multiple layers might be nameless
for (auto it = model->layers.begin(); it != model->layers.end(); ++it) {
if ((*it)->name == name)
return CLayerDescription(*it);
}
}
THROW exception::InvalidFuncLayerIndx("Layer ('%s') was not found, "
"in ModelDescription::getAgent().",
name.c_str());
}
CLayerDescription ModelDescription::getLayer(const flamegpu::size_type &layer_index) const {
if (model->layers.size() > layer_index) {
auto it = model->layers.begin();
for (auto i = 0u; i < layer_index; ++i)
++it;
return CLayerDescription(*it);
}
THROW exception::OutOfBoundsException("Layer %d is out of bounds, "
"in ModelDescription::Layer().",
layer_index);
}
bool ModelDescription::hasAgent(const std::string &agent_name) const {
return model->agents.find(agent_name) != model->agents.end();
}
bool ModelDescription::hasMessage(const std::string &message_name) const {
return model->messages.find(message_name) != model->messages.end();
}
bool ModelDescription::hasSubModel(const std::string &submodel_name) const {
return model->submodels.find(submodel_name) != model->submodels.end();
}
bool ModelDescription::hasLayer(const std::string &name) const {
if (!name.empty()) { // Can't search for no name, multiple layers might be nameless
for (auto it = model->layers.begin(); it != model->layers.end(); ++it) {
if ((*it)->name == name)
return true;
}
}
return false;
}
bool ModelDescription::hasLayer(const flamegpu::size_type &layer_index) const {
return layer_index < model->layers.size();
}
void ModelDescription::generateDependencyGraphDOTDiagram(std::string outputFileName) const {
model->dependencyGraph->generateDOTDiagram(outputFileName);
}
std::string ModelDescription::getConstructedLayersString() const {
return model->dependencyGraph->getConstructedLayersString();
}
flamegpu::size_type ModelDescription::getAgentsCount() const {
// This down-cast is safe
return static_cast<flamegpu::size_type>(model->agents.size());
}
flamegpu::size_type ModelDescription::getMessagesCount() const {
// This down-cast is safe
return static_cast<flamegpu::size_type>(model->messages.size());
}
flamegpu::size_type ModelDescription::getLayersCount() const {
// This down-cast is safe
return static_cast<flamegpu::size_type>(model->layers.size());
}
} // namespace flamegpu