Program Listing for File SubModelDescription.cpp

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

#include "flamegpu/model/SubModelDescription.h"

#include <utility>
#include <string>
#include <memory>

#include "flamegpu/model/ModelData.h"
#include "flamegpu/model/AgentData.h"
#include "flamegpu/model/SubModelData.h"
#include "flamegpu/model/SubAgentData.h"
#include "flamegpu/model/SubAgentDescription.h"
#include "flamegpu/model/SubEnvironmentData.h"
#include "flamegpu/model/SubEnvironmentDescription.h"

namespace flamegpu {

CSubModelDescription::CSubModelDescription(std::shared_ptr<SubModelData> data)
    : submodel(std::move(data)) { }
CSubModelDescription::CSubModelDescription(std::shared_ptr<const SubModelData> data)
    : submodel(std::move(std::const_pointer_cast<SubModelData>(data))) { }

bool CSubModelDescription::operator==(const CSubModelDescription& rhs) const {
    return *this->submodel == *rhs.submodel;  // Compare content is functionally the same
}
bool CSubModelDescription::operator!=(const CSubModelDescription& rhs) const {
    return !(*this == rhs);
}

unsigned int CSubModelDescription::getMaxSteps() const {
    return submodel->max_steps;
}
const std::string CSubModelDescription::getName() const {
    return submodel->name;
}

SubModelDescription::SubModelDescription(std::shared_ptr<SubModelData> data)
    : CSubModelDescription(std::move(data)) { }

SubAgentDescription SubModelDescription::bindAgent(const std::string &sub_agent_name, const std::string &master_agent_name, bool auto_map_vars, bool auto_map_states) {
    // Sub agent exists
    const auto subagent = submodel->submodel->agents.find(sub_agent_name);
    if (subagent == submodel->submodel->agents.end()) {
        THROW exception::InvalidSubAgentName("SubModel '%s' does not contain Agent '%s', "
            "in SubModelDescription::bindAgent()\n", submodel->submodel->name.c_str(), sub_agent_name.c_str());
    }
    auto mdl = submodel->model.lock();
    if (!mdl) {
        THROW exception::ExpiredWeakPtr();
    }
    // Master agent exists
    const auto masteragent = mdl->agents.find(master_agent_name);
    if (masteragent == mdl->agents.end()) {
        THROW exception::InvalidAgentName("Master Model '%s' does not contain Agent '%s', "
            "in SubModelDescription::bindAgent()\n", mdl->name.c_str(), master_agent_name.c_str());
    }
    // Sub agent has not been bound yet
    {
        const auto subagent_bind = submodel->subagents.find(sub_agent_name);
        if (subagent_bind != submodel->subagents.end()) {
            auto master_agent_ptr = subagent_bind->second->masterAgent.lock();
            THROW exception::InvalidSubAgentName("SubModel '%s's Agent '%s' has already been bound to Master agent '%s', "
                "in SubModelDescription::bindAgent()\n", submodel->submodel->name.c_str(), sub_agent_name.c_str(), master_agent_ptr ? master_agent_ptr->name.c_str() : "?");
        }
    }
    // Master agent has not been bound yet
    for (auto &a : submodel->subagents) {
        const auto master_agent_ptr = a.second->masterAgent.lock();
        if (master_agent_ptr && master_agent_ptr->name == master_agent_name) {
            THROW exception::InvalidAgentName("Master Agent '%s' has already been bound to Sub agent '%s', "
                "in SubModelDescription::bindAgent()\n", master_agent_name.c_str(), a.first.c_str());
        }
    }
    // Create SubAgent
    auto rtn = std::shared_ptr<SubAgentData>(new SubAgentData(mdl, submodel->shared_from_this(), subagent->second, masteragent->second));
    submodel->subagents.emplace(sub_agent_name, rtn);
    // If auto_map, map any matching vars
    // Otherwise map all internal variables that begin _ (e.g. _id)
    for (auto& sub_var : subagent->second->variables) {
        if (auto_map_vars || (!sub_var.first.empty() && sub_var.first[0] == '_')) {
            auto master_var = masteragent->second->variables.find(sub_var.first);
            // If there exists variable with same name in both agents
            if (master_var != masteragent->second->variables.end()) {
                // Check type and length (is it an array var)
                if (sub_var.second.type == master_var->second.type
                    && sub_var.second.elements == master_var->second.elements) {
                    // Variables match, create mapping
                    rtn->variables.emplace(sub_var.first, master_var->first);  // Doesn't actually matter, both strings are equal
                }
            }
        }
    }
    // If auto_map, map any matching states
    if (auto_map_states) {
        for (auto &sub_var : subagent->second->states) {
            auto master_var = masteragent->second->states.find(sub_var);
            // If there exists states with same name in both agents
            if (master_var != masteragent->second->states.end()) {
                // States match, create mapping
                rtn->states.emplace(sub_var, *master_var);  // Doesn't actually matter, both strings are equal
            }
        }
    }
    // return SubAgentDescription
    return SubAgentDescription(rtn);
}

SubAgentDescription SubModelDescription::SubAgent(const std::string &sub_agent_name) {
    const auto rtn = submodel->subagents.find(sub_agent_name);
    if (rtn != submodel->subagents.end())
        return SubAgentDescription(rtn->second);
    THROW exception::InvalidSubAgentName("SubAgent ('%s') either does not exist, or has not been bound yet, "
        "in SubModelDescription::SubAgent().",
        sub_agent_name.c_str());
}
CSubAgentDescription SubModelDescription::getSubAgent(const std::string &sub_agent_name) const {
    const auto rtn = submodel->subagents.find(sub_agent_name);
    if (rtn != submodel->subagents.end())
        return SubAgentDescription(rtn->second);
    THROW exception::InvalidSubAgentName("SubAgent ('%s')  either does not exist, or has not been bound yet, "
        "in SubModelDescription::getSubAgent().",
        sub_agent_name.c_str());
}


SubEnvironmentDescription SubModelDescription::SubEnvironment(bool auto_map) {
    if (!submodel->subenvironment) {
        auto mdl = submodel->model.lock();
        if (!mdl) {
            THROW exception::ExpiredWeakPtr();
        }
        submodel->subenvironment = std::shared_ptr<SubEnvironmentData>(new SubEnvironmentData(mdl, submodel->shared_from_this(), submodel->submodel->environment));
    }
    SubEnvironmentDescription rtn(submodel->subenvironment);
    if (auto_map) {
        rtn.autoMapProperties();
        rtn.autoMapMacroProperties();
    }
    return rtn;
}
CSubEnvironmentDescription SubModelDescription::getSubEnvironment() const {
    if (!submodel->subenvironment) {
        auto mdl = submodel->model.lock();
        if (!mdl) {
            THROW exception::ExpiredWeakPtr();
        }
        submodel->subenvironment = std::shared_ptr<SubEnvironmentData>(new SubEnvironmentData(mdl, submodel->shared_from_this(), submodel->submodel->environment));
    }
    return CSubEnvironmentDescription(submodel->subenvironment);
}

void SubModelDescription::setMaxSteps(const unsigned int max_steps) {
    submodel->max_steps = max_steps;
}

}  // namespace flamegpu