Program Listing for File RunPlan.h
↰ Return to documentation for file (include/flamegpu/simulation/RunPlan.h
)
#ifndef INCLUDE_FLAMEGPU_SIMULATION_RUNPLAN_H_
#define INCLUDE_FLAMEGPU_SIMULATION_RUNPLAN_H_
#include <unordered_map>
#include <string>
#include <typeinfo>
#include <vector>
#include <memory>
#include "flamegpu/model/EnvironmentDescription.h"
#include "flamegpu/detail/Any.h"
#include "flamegpu/detail/type_decode.h"
#include "flamegpu/simulation/CUDAEnsemble.h"
namespace flamegpu {
namespace detail {
class AbstractSimRunner;
}
class ModelDescription;
class RunPlanVector;
class CUDASimulation;
namespace io {
class JSONLogger;
class XMLLogger;
} // namespace io
class RunPlan {
friend class RunPlanVector;
friend class detail::AbstractSimRunner;
friend class CUDASimulation;
friend class io::JSONLogger;
friend class io::XMLLogger;
public:
explicit RunPlan(const ModelDescription &environment);
RunPlan& operator=(const RunPlan& other);
void setRandomSimulationSeed(uint64_t random_seed);
void setSteps(unsigned int steps);
void setOutputSubdirectory(const std::string &subdir);
template<typename T>
void setProperty(const std::string &name, T value);
template<typename T, flamegpu::size_type N>
void setProperty(const std::string &name, const std::array<T, N> &value);
template<typename T, flamegpu::size_type N = 0>
void setProperty(const std::string &name, flamegpu::size_type index, T value);
#ifdef SWIG
template<typename T>
void setPropertyArray(const std::string &name, const std::vector<T> &value);
#endif
uint64_t getRandomSimulationSeed() const;
unsigned int getSteps() const;
std::string getOutputSubdirectory() const;
template<typename T>
T getProperty(const std::string &name) const;
template<typename T, flamegpu::size_type N>
std::array<T, N> getProperty(const std::string &name) const;
template<typename T, flamegpu::size_type N = 0>
T getProperty(const std::string &name, flamegpu::size_type index) const;
#ifdef SWIG
template<typename T>
std::vector<T> getPropertyArray(const std::string &name);
#endif
RunPlanVector operator+(const RunPlan& rhs) const;
RunPlanVector operator+(const RunPlanVector& rhs) const;
RunPlanVector operator*(unsigned int rhs) const;
bool operator==(const RunPlan& rhs) const;
bool operator!=(const RunPlan& rhs) const;
private:
explicit RunPlan(const std::shared_ptr<const std::unordered_map<std::string, EnvironmentData::PropData>> &environment, bool allow_0);
uint64_t random_seed;
unsigned int steps;
std::string output_subdirectory;
std::unordered_map<std::string, detail::Any> property_overrides;
// This needs to be shared_ptr, reference goes out of scope, otherwise have a copy of the map per RunPlan
std::shared_ptr<const std::unordered_map<std::string, EnvironmentData::PropData>> environment;
bool allow_0_steps;
};
template<typename T>
void RunPlan::setProperty(const std::string &name, T value) {
// Validation
const auto it = environment->find(name);
if (it == environment->end()) {
THROW exception::InvalidEnvProperty("Environment description does not contain property '%s', "
"in RunPlan::setProperty()\n",
name.c_str());
}
if (it->second.data.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidEnvPropertyType("Environment property '%s' type mismatch '%s' != '%s', "
"in RunPlan::setProperty()\n",
name.c_str(), it->second.data.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
}
if (it->second.data.elements != detail::type_decode<T>::len_t) {
THROW exception::InvalidEnvPropertyType("Environment property '%s' is an array with %u elements, array method should be used, "
"in RunPlan::setProperty()\n",
name.c_str(), it->second.data.elements);
}
// Store property
property_overrides.erase(name);
property_overrides.emplace(name, detail::Any(&value, sizeof(T), typeid(typename detail::type_decode<T>::type_t), detail::type_decode<T>::len_t));
}
template<typename T, flamegpu::size_type N>
void RunPlan::setProperty(const std::string &name, const std::array<T, N> &value) {
// Validation
const auto it = environment->find(name);
if (it == environment->end()) {
THROW exception::InvalidEnvProperty("Environment description does not contain property '%s', "
"in RunPlan::setProperty()\n",
name.c_str());
}
if (it->second.data.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidEnvPropertyType("Environment property '%s' type mismatch '%s' != '%s', "
"in RunPlan::setProperty()\n",
name.c_str(), it->second.data.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
}
if (it->second.data.elements != N * detail::type_decode<T>::len_t) {
THROW exception::InvalidEnvPropertyType("Environment property array '%s' length mismatch %u != %u "
"in RunPlan::setProperty()\n",
name.c_str(), it->second.data.elements, N * detail::type_decode<T>::len_t);
}
// Store property
property_overrides.erase(name);
property_overrides.emplace(name, detail::Any(value.data(), sizeof(T) * N, typeid(typename detail::type_decode<T>::type_t), detail::type_decode<T>::len_t * N));
}
template<typename T, flamegpu::size_type N>
void RunPlan::setProperty(const std::string &name, const flamegpu::size_type index, T value) {
// Validation
const auto it = environment->find(name);
if (it == environment->end()) {
THROW exception::InvalidEnvProperty("Environment description does not contain property '%s', "
"in RunPlan::setProperty()\n",
name.c_str());
}
if (it->second.data.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidEnvPropertyType("Environment property '%s' type mismatch '%s' != '%s', "
"in RunPlan::setProperty()\n",
name.c_str(), it->second.data.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
}
if (N && N != it->second.data.elements) {
THROW exception::OutOfBoundsException("Environment property '%s' length mismatch '%u' != '%u', "
"in RunPlan::setProperty()\n",
name.c_str(), N, it->second.data.elements);
}
const unsigned int t_index = detail::type_decode<T>::len_t * index + detail::type_decode<T>::len_t;
if (it->second.data.elements < t_index || t_index < index) {
THROW exception::OutOfBoundsException("Environment property array index out of bounds "
"in RunPlan::setProperty()\n");
}
// Check whether array already exists in property overrides
auto it2 = property_overrides.find(name);
if (it2 == property_overrides.end()) {
// Clone default property first
it2 = property_overrides.emplace(name, it->second.data).first;
}
// Store property
memcpy(static_cast<T*>(it2->second.ptr) + index, &value, sizeof(T));
}
#ifdef SWIG
template<typename T>
void RunPlan::setPropertyArray(const std::string &name, const std::vector<T> &value) {
// Validation
const auto it = environment->find(name);
if (it == environment->end()) {
THROW exception::InvalidEnvProperty("Environment description does not contain property '%s', "
"in RunPlan::setPropertyArray()\n",
name.c_str());
}
if (it->second.data.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidEnvPropertyType("Environment property '%s' type mismatch '%s' != '%s', "
"in RunPlan::setPropertyArray()\n",
name.c_str(), it->second.data.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
}
if (detail::type_decode<T>::len_t * value.size() != it->second.data.elements) {
THROW exception::InvalidEnvPropertyType("Environment property array length does not match the value provided, %u != %llu,"
"in RunPlan::setPropertyArray()\n",
name.c_str(), detail::type_decode<T>::len_t * value.size(), it->second.data.elements);
}
// Store property
property_overrides.erase(name);
property_overrides.emplace(name, detail::Any(value.data(), sizeof(T) * value.size(), typeid(typename detail::type_decode<T>::type_t), detail::type_decode<T>::len_t * value.size()));
}
#endif
template<typename T>
T RunPlan::getProperty(const std::string &name) const {
// Validation
const auto it = environment->find(name);
if (it == environment->end()) {
THROW exception::InvalidEnvProperty("Environment description does not contain property '%s', "
"in RunPlan::getProperty()\n",
name.c_str());
}
if (it->second.data.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidEnvPropertyType("Environment property '%s' type mismatch '%s' != '%s', "
"in RunPlan::getProperty()\n",
name.c_str(), it->second.data.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
}
if (it->second.data.elements != detail::type_decode<T>::len_t) {
THROW exception::InvalidEnvPropertyType("Environment property '%s' is an array with %u elements, array method should be used, "
"in RunPlan::getProperty()\n",
name.c_str(), it->second.data.elements);
}
// Check whether property already exists in property overrides
const auto it2 = property_overrides.find(name);
if (it2 != property_overrides.end()) {
// The property has been overridden, return the value from the override.
return *static_cast<T *>(it2->second.ptr);
} else {
// The property has not been overridden, so return the value from the environment
return *static_cast<T *>(it->second.data.ptr);
}
}
template<typename T, flamegpu::size_type N>
std::array<T, N> RunPlan::getProperty(const std::string &name) const {
// Validation
const auto it = environment->find(name);
if (it == environment->end()) {
THROW exception::InvalidEnvProperty("Environment description does not contain property '%s', "
"in RunPlan::getProperty()\n",
name.c_str());
}
if (it->second.data.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidEnvPropertyType("Environment property '%s' type mismatch '%s' != '%s', "
"in RunPlan::getProperty()\n",
name.c_str(), it->second.data.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
}
if (it->second.data.elements != N * detail::type_decode<T>::len_t) {
THROW exception::InvalidEnvPropertyType("Environment property array '%s' length mismatch %u != %u "
"in RunPlan::getProperty()\n",
name.c_str(), it->second.data.elements, N);
}
// Check whether array already exists in property overrides
const auto it2 = property_overrides.find(name);
std::array<T, N> rtn;
if (it2 != property_overrides.end()) {
// The property has been overridden, return the override
memcpy(rtn.data(), it2->second.ptr, it2->second.length);
} else {
// The property has not been overridden, return the environment property
memcpy(rtn.data(), it->second.data.ptr, it->second.data.length);
}
return rtn;
}
template<typename T, flamegpu::size_type N>
T RunPlan::getProperty(const std::string &name, const flamegpu::size_type index) const {
// Validation
const auto it = environment->find(name);
if (it == environment->end()) {
THROW exception::InvalidEnvProperty("Environment description does not contain property '%s', "
"in RunPlan::getProperty()\n",
name.c_str());
}
if (it->second.data.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidEnvPropertyType("Environment property '%s' type mismatch '%s' != '%s', "
"in RunPlan::getProperty()\n",
name.c_str(), it->second.data.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
}
if (N && N != it->second.data.elements) {
THROW exception::OutOfBoundsException("Environment property '%s' length mismatch '%u' != '%u', "
"in RunPlan::getProperty()\n",
name.c_str(), N, it->second.data.elements);
}
const unsigned int t_index = detail::type_decode<T>::len_t * index + detail::type_decode<T>::len_t;
if (it->second.data.elements < t_index || t_index < index) {
THROW exception::OutOfBoundsException("Environment property array index out of bounds "
"in RunPlan::getProperty()\n");
}
// Check whether property already exists in property overrides
const auto it2 = property_overrides.find(name);
if (it2 != property_overrides.end()) {
// The property has been overridden, return the override
return static_cast<T *>(it2->second.ptr)[index];
} else {
// The property has not been overridden, return the environment property
return static_cast<T *>(it->second.data.ptr)[index];
}
}
#ifdef SWIG
template<typename T>
std::vector<T> RunPlan::getPropertyArray(const std::string &name) {
// Validation
const auto it = environment->find(name);
if (it == environment->end()) {
THROW exception::InvalidEnvProperty("Environment description does not contain property '%s', "
"in RunPlan::getProperty()\n",
name.c_str());
}
if (it->second.data.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
THROW exception::InvalidEnvPropertyType("Environment property '%s' type mismatch '%s' != '%s', "
"in RunPlan::getProperty()\n",
name.c_str(), it->second.data.type.name(), std::type_index(typeid(typename detail::type_decode<T>::type_t)).name());
}
if (it->second.data.elements % detail::type_decode<T>::len_t != 0) {
THROW exception::InvalidEnvPropertyType("Environmental property array '%s' length (%u) is not a multiple of vector length (%u), "
"in RunPlan::getPropertyArray().",
name.c_str(), detail::type_decode<T>::len_t, it->second.data.elements, detail::type_decode<T>::len_t);
}
// Check whether array already exists in property overrides
const auto it2 = property_overrides.find(name);
std::vector<T> rtn(it->second.data.elements / detail::type_decode<T>::len_t);
if (it2 != property_overrides.end()) {
// The property has been overridden, return the override
memcpy(rtn.data(), it2->second.ptr, it2->second.length);
} else {
// The property has not been overridden, return the environment property
memcpy(rtn.data(), it->second.data.ptr, it->second.data.length);
}
return rtn;
}
#endif
} // namespace flamegpu
#endif // INCLUDE_FLAMEGPU_SIMULATION_RUNPLAN_H_