Program Listing for File RunPlanVector.cpp

Return to documentation for file (src/flamegpu/simulation/RunPlanVector.cpp)

#include "flamegpu/simulation/RunPlanVector.h"

#include <vector>
#include <string>
#include <memory>
#include <unordered_map>
#include <algorithm>


#include "flamegpu/model/ModelDescription.h"

namespace flamegpu {

RunPlanVector::RunPlanVector(const ModelDescription &model, unsigned int initial_length)
    : std::vector<RunPlan>(initial_length, RunPlan(model))
    , randomPropertySeed(std::random_device()())
    , rand(randomPropertySeed)
    , environment(std::make_shared<std::unordered_map<std::string, EnvironmentData::PropData> const>(model.model->environment->properties))
    , allow_0_steps(model.model->exitConditions.size() + model.model->exitConditionCallbacks.size() > 0) {
    this->resize(initial_length, RunPlan(environment, allow_0_steps));
}

RunPlanVector::RunPlanVector(const std::shared_ptr<const std::unordered_map<std::string, EnvironmentData::PropData>> &_environment, const bool _allow_0_steps)
    : std::vector<RunPlan>()
    , randomPropertySeed(std::random_device()())
    , rand(randomPropertySeed)
    , environment(_environment)
    , allow_0_steps(_allow_0_steps) { }
void RunPlanVector::setRandomSimulationSeed(const uint64_t initial_seed, const unsigned int step) {
    uint64_t current_seed = initial_seed;
    for (auto &i : *this) {
        i.setRandomSimulationSeed(current_seed);
        current_seed += step;
    }
}
void RunPlanVector::setSteps(const unsigned int steps) {
    if (steps == 0 && !allow_0_steps) {
        THROW exception::OutOfBoundsException("Model description requires atleast 1 exit condition to have unlimited steps, "
            "in RunPlanVector::setSteps()");
    }
    for (auto &i : *this) {
        i.setSteps(steps);
    }
}
void RunPlanVector::setOutputSubdirectory(const std::string &subdir) {
    for (auto &i : *this) {
        i.setOutputSubdirectory(subdir);
    }
}
void RunPlanVector::setRandomPropertySeed(const uint64_t seed) {
    randomPropertySeed = seed;
    rand.seed(randomPropertySeed);
}

uint64_t RunPlanVector::getRandomPropertySeed() {
    return randomPropertySeed;
}

RunPlanVector RunPlanVector::operator+(const RunPlan& rhs) const {
    // This function is defined internally inside both RunPlan and RunPlanVector as it's the only way to both pass CI and have SWIG build
    // Validation
    if (*rhs.environment != *this->environment) {
        THROW exception::InvalidArgument("RunPlan is for a different ModelDescription, "
            "in ::operator+(RunPlanVector, RunPlan)");
    }
    // Operation
    RunPlanVector rtn(*this);
    rtn+=rhs;
    return rtn;
}
RunPlanVector RunPlanVector::operator+(const RunPlanVector& rhs) const {
    // Validation
    if (*rhs.environment != *this->environment) {
        THROW exception::InvalidArgument("RunPlanVectors are for different ModelDescriptions, "
            "in ::operator+(RunPlanVector, RunPlanVector)");
    }
    // Operation
    RunPlanVector rtn(*this);
    rtn+=rhs;
    return rtn;
}
RunPlanVector& RunPlanVector::operator+=(const RunPlan& rhs) {
    // Validation
    if (*rhs.environment != *this->environment) {
        THROW exception::InvalidArgument("RunPlan is for a different ModelDescription, "
            "in ::operator+=(RunPlanVector, RunPlan)");
    }
    // Update shared_ptr to env
    RunPlan rhs_copy = rhs;
    rhs_copy.environment = environment;
    // Operation
    this->push_back(rhs_copy);
    return *this;
}
RunPlanVector& RunPlanVector::operator+=(const RunPlanVector& rhs) {
    // Validation
    if (this == &rhs) {
        return *this*=2;
    }
    if (*rhs.environment != *this->environment) {
        THROW exception::InvalidArgument("RunPlan is for a different ModelDescription, "
            "in ::operator+=(RunPlanVector, RunPlan)");
    }
    // Operation
    this->reserve(size() + rhs.size());
    // Iterate, because insert would require RunPlan::operator==
    for (const auto &i : rhs) {
        // Update shared_ptr to env
        RunPlan i_copy = i;
        i_copy.environment = environment;
        this->push_back(i);
    }
    return *this;
}
RunPlanVector& RunPlanVector::operator*=(const unsigned int rhs) {
    RunPlanVector copy(*this);
    this->clear();
    this->reserve(copy.size() * rhs);
    for (unsigned int i = 0; i < rhs; ++i) {
        // Iterate, because insert would require RunPlan::operator==
        for (const auto &j : copy) {
            this->push_back(j);
        }
    }
    return *this;
}
RunPlanVector RunPlanVector::operator*(const unsigned int rhs) const {
    RunPlanVector rtn(this->environment, this->allow_0_steps);
    rtn.reserve(size() * rhs);
    for (unsigned int i = 0; i < rhs; ++i) {
        // Iterate, because insert would require RunPlan::operator==
        for (const auto &j : *this) {
            rtn.push_back(j);
        }
    }
    return rtn;
}

bool RunPlanVector::operator==(const RunPlanVector& rhs) const {
    if (this == &rhs)
        return true;
    if (this->randomPropertySeed == rhs.randomPropertySeed &&
        this->rand == rhs.rand &&
        this->environment == rhs.environment &&  // Could check the pointed to map matches instead
        this->allow_0_steps == rhs.allow_0_steps &&
        this->size() == rhs.size()) {
        for (size_t i = 0; i < this->size(); ++i) {
            if (!(this->at(i) == rhs.at(i))) {
                return false;
            }
        }
        return true;
    }
    return false;
}
bool RunPlanVector::operator!=(const RunPlanVector& rhs) const {
    return !((*this) == rhs);
}

}  // namespace flamegpu