Program Listing for File ModelData.cpp

Return to documentation for file (src/flamegpu/model/ModelData.cpp)

#include <iostream>
#include <algorithm>
#include <string>
#include <memory>

#include "flamegpu/model/ModelData.h"

#include "flamegpu/model/AgentData.h"
#include "flamegpu/model/AgentDescription.h"
#include "flamegpu/model/AgentFunctionDescription.h"
#include "flamegpu/model/AgentFunctionData.cuh"
#include "flamegpu/model/LayerData.h"
#include "flamegpu/model/EnvironmentData.h"
#include "flamegpu/model/SubModelData.h"
#include "flamegpu/model/SubAgentData.h"
#include "flamegpu/model/SubEnvironmentData.h"
#include "flamegpu/model/DependencyGraph.h"
#include "flamegpu/runtime/HostFunctionCallback.h"

namespace flamegpu {

const char *ModelData::DEFAULT_STATE = "default";

ModelData::ModelData(const std::string &model_name)
    : name(model_name)
    , dependencyGraph(new DependencyGraph(this)) {
    // Environment is init by ModelDescription's constructor (as it requires a shared pointer to this
}

std::shared_ptr<ModelData> ModelData::clone() const {
    // Awkwardly cant use shared from this inside constructor, so use raw pts instead
    auto rtn = std::shared_ptr<ModelData>(new ModelData(*this));

    // Manually copy construct maps of shared ptr
    for (const auto &m : this->messages) {
        rtn->messages.emplace(m.first, std::shared_ptr<MessageBruteForce::Data>(m.second->clone(rtn)));  // Need to convert this to shared_ptr, how to force shared copy construct?
    }
    // Copy all agents first
    for (const auto &a : this->agents) {
        auto b = std::shared_ptr<AgentData>(new AgentData(rtn, *a.second));
        rtn->agents.emplace(a.first, b);
    }
    // Copy agent functions per agent, after all agents have been implemented.
    for (const auto &a : this->agents) {
        auto b = rtn->agents.find(a.first)->second;
        // Manually copy construct maps of shared ptr
        for (const auto &f : a.second->functions) {
            b->functions.emplace(f.first, std::shared_ptr<AgentFunctionData>(new AgentFunctionData(rtn, b, *f.second)));
        }
    }
    // Copy submodels
    for (const auto &a : this->submodels) {
        auto b = std::shared_ptr<SubModelData>(new SubModelData(rtn, *a.second));
        // Manually copy construct maps of shared ptr
        for (const auto &f : a.second->subagents) {
            b->subagents.emplace(f.first, std::shared_ptr<SubAgentData>(new SubAgentData(rtn, b, *f.second)));
        }
        // Manually copy construct environment
        b->subenvironment = std::unique_ptr<SubEnvironmentData>(new SubEnvironmentData(rtn, b, *a.second->subenvironment));
        rtn->submodels.emplace(a.first, b);
    }

    for (const auto &m : this->layers) {
        rtn->layers.push_back(std::shared_ptr<LayerData>(new LayerData(rtn, *m)));
    }
    rtn->environment = std::shared_ptr<EnvironmentData>(new EnvironmentData(rtn, *this->environment));
    return rtn;
}

ModelData::ModelData(const ModelData &other)
    : std::enable_shared_from_this<ModelData>(other)
    , initFunctions(other.initFunctions)
    , initFunctionCallbacks(other.initFunctionCallbacks)
    , stepFunctions(other.stepFunctions)
    , stepFunctionCallbacks(other.stepFunctionCallbacks)
    , exitFunctions(other.exitFunctions)
    , exitFunctionCallbacks(other.exitFunctionCallbacks)
    , exitConditions(other.exitConditions)
    , exitConditionCallbacks(other.exitConditionCallbacks)
    , name(other.name)
    , dependencyGraph(new DependencyGraph(*other.dependencyGraph)) {
    // Must be called from clone() so that items are all init
}

bool ModelData::operator==(const ModelData& rhs) const {
    if (this == &rhs)  // They point to same object
        return true;
    if (name == rhs.name
        && agents.size() == rhs.agents.size()
        && messages.size() == rhs.messages.size()
        && submodels.size() == rhs.submodels.size()
        && layers.size() == rhs.layers.size()
        && initFunctions.size() == rhs.initFunctions.size()
        && stepFunctions.size() == rhs.stepFunctions.size()
        && exitFunctions.size() == rhs.exitFunctions.size()
        && initFunctionCallbacks.size() == rhs.initFunctionCallbacks.size()
        && stepFunctionCallbacks.size() == rhs.stepFunctionCallbacks.size()
        && exitFunctionCallbacks.size() == rhs.exitFunctionCallbacks.size()
        && exitConditionCallbacks.size() == rhs.exitConditionCallbacks.size()
        && exitConditions.size() == rhs.exitConditions.size()
        && *environment == *rhs.environment
        && *dependencyGraph == *rhs.dependencyGraph) {
            {  // Compare agents (map)
                for (auto &v : agents) {
                    auto _v = rhs.agents.find(v.first);
                    if (_v == rhs.agents.end())
                        return false;
                    if (*v.second != *_v->second)
                        return false;
                }
            }
            {  // Compare messages (map)
                for (auto &v : messages) {
                    auto _v = rhs.messages.find(v.first);
                    if (_v == rhs.messages.end())
                        return false;
                    if (*v.second != *_v->second)
                        return false;
                }
            }
            {  // Compare submodels (map)
                for (auto &v : submodels) {
                    auto _v = rhs.submodels.find(v.first);
                    if (_v == rhs.submodels.end())
                        return false;
                    if (*v.second != *_v->second)
                        return false;
                }
            }
            {  // Compare layers (ordered list)
                auto it1 = layers.begin();
                auto it2 = rhs.layers.begin();
                while (it1 != layers.end() && it2 != rhs.layers.end()) {
                    if (*(*it1) != *(*it2))
                        return false;
                    ++it1;
                    ++it2;
                }
            }
            {  // Init fns (set)
                if (initFunctions != rhs.initFunctions)
                    return false;
                if (initFunctionCallbacks != rhs.initFunctionCallbacks)
                    return false;
            }
            {  // Step fns (set)
                if (stepFunctions != rhs.stepFunctions)
                    return false;
                if (stepFunctionCallbacks != rhs.stepFunctionCallbacks)
                    return false;
            }
            {  // Exit fns (set)
                if (exitFunctions != rhs.exitFunctions)
                    return false;
                if (exitFunctionCallbacks != rhs.exitFunctionCallbacks)
                    return false;
            }
            {  // Exit cdns (set)
                if (exitConditions != rhs.exitConditions)
                    return false;
                if (exitConditionCallbacks != rhs.exitConditionCallbacks)
                    return false;
            }
            return true;
    }
    return false;
}

bool ModelData::operator!=(const ModelData& rhs) const {
    return !operator==(rhs);
}
bool ModelData::hasSubModelRecursive(const std::shared_ptr<const ModelData> &submodel_data) const {
    for (auto &m : submodels) {
        if (m.second->submodel.get() == submodel_data.get())
            return true;
        if (m.second->submodel->hasSubModelRecursive(submodel_data))
            return true;
    }
    return false;
}

flamegpu::size_type ModelData::getMaxLayerWidth() const {
    unsigned int maxWidth = 0u;
    for (auto &layer : layers) {
        maxWidth = (std::max)(maxWidth, static_cast<flamegpu::size_type>(layer->agent_functions.size()));
    }
    return maxWidth;
}

}  // namespace flamegpu