Skip to content

Commit

Permalink
Read env macro property from state file
Browse files Browse the repository at this point in the history
May wish to add support for setting up macro properties default value in model description?
  • Loading branch information
Robadob committed Jul 11, 2023
1 parent 2cc3212 commit cabc60c
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 14 deletions.
9 changes: 7 additions & 2 deletions include/flamegpu/io/JSONStateReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

#include "flamegpu/io/StateReader.h"
#include "flamegpu/model/ModelDescription.h"
Expand All @@ -24,15 +25,19 @@ class JSONStateReader : public StateReader {
* Agent data will be read into 'model_state'
* @param model_name Name from the model description hierarchy of the model to be loaded
* @param env_desc Environment description for validating property data on load
* @param env_init Dictionary of loaded values map:<{name, index}, value>
* @param env_init Dictionary of loaded values map:<name, value>
* @param macro_env_desc Macro environment description for validating property data on load
* @param macro_env_init Dictionary of loaded values map:<name, value>
* @param model_state Map of AgentVector to load the agent data into per agent, key should be agent name
* @param input_file Filename of the input file (This will be used to determine which reader to return)
* @param sim_instance Instance of the Simulation object (This is used for setting/getting config)
*/
JSONStateReader(
const std::string &model_name,
const std::unordered_map<std::string, EnvironmentData::PropData> &env_desc,
std::unordered_map<std::string, detail::Any>&env_init,
std::unordered_map<std::string, detail::Any> &env_init,
const std::unordered_map<std::string, EnvironmentData::MacroPropData> &macro_env_desc,
std::unordered_map<std::string, std::vector<char>> &macro_env_init,
util::StringPairUnorderedMap<std::shared_ptr<AgentVector>> &model_state,
const std::string &input_file,
Simulation *sim_instance);
Expand Down
13 changes: 11 additions & 2 deletions include/flamegpu/io/StateReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

#include "flamegpu/util/StringPair.h"
#include "flamegpu/model/EnvironmentData.h"
Expand All @@ -29,7 +30,9 @@ class StateReader {
* Agent data will be read into 'model_state'
* @param _model_name Name from the model description hierarchy of the model to be loaded
* @param _env_desc Environment description for validating property data on load
* @param _env_init Dictionary of loaded values map:<{name, index}, value>
* @param _env_init Dictionary of loaded values map:<name, value>
* @param _macro_env_desc Macro environment description for validating property data on load
* @param _macro_env_init Dictionary of loaded values map:<name, value>
* @param _model_state Map of AgentVector to load the agent data into per agent, key should be agent name
* @param input Filename of the input file (This will be used to determine which reader to return)
* @param _sim_instance Instance of the simulation (for configuration data IO)
Expand All @@ -38,6 +41,8 @@ class StateReader {
const std::string& _model_name,
const std::unordered_map<std::string, EnvironmentData::PropData>& _env_desc,
std::unordered_map<std::string, detail::Any>& _env_init,
const std::unordered_map<std::string, EnvironmentData::MacroPropData>& _macro_env_desc,
std::unordered_map<std::string, std::vector<char>>& _macro_env_init,
util::StringPairUnorderedMap<std::shared_ptr<AgentVector>>& _model_state,
const std::string& input,
Simulation* _sim_instance)
Expand All @@ -46,6 +51,8 @@ class StateReader {
, model_name(_model_name)
, env_desc(_env_desc)
, env_init(_env_init)
, macro_env_desc(_macro_env_desc)
, macro_env_init(_macro_env_init)
, sim_instance(_sim_instance) {}
/**
* Virtual destructor for correct inheritance behaviour
Expand All @@ -63,11 +70,13 @@ class StateReader {
virtual int parse() = 0;

protected:
util::StringPairUnorderedMap<std::shared_ptr<AgentVector>>& model_state;
util::StringPairUnorderedMap<std::shared_ptr<AgentVector>> &model_state;
std::string inputFile;
const std::string model_name;
const std::unordered_map<std::string, EnvironmentData::PropData> &env_desc;
std::unordered_map<std::string, detail::Any>& env_init;
const std::unordered_map<std::string, EnvironmentData::MacroPropData> &macro_env_desc;
std::unordered_map<std::string, std::vector<char>>& macro_env_init;
Simulation *sim_instance;
};
} // namespace io
Expand Down
11 changes: 8 additions & 3 deletions include/flamegpu/io/StateReaderFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <utility>
#include <algorithm>
#include <filesystem>
#include <vector>

#include "flamegpu/io/StateReader.h"
#include "flamegpu/io/XMLStateReader.h"
Expand All @@ -29,7 +30,9 @@ class StateReaderFactory {
* Agent data will be read into 'model_state'
* @param model_name Name from the model description hierarchy of the model to be loaded
* @param env_desc Environment description for validating property data on load
* @param env_init Dictionary of loaded values map:<{name, index}, value>
* @param env_init Dictionary of loaded values map:<name, value>
* @param macro_env_desc Macro environment description for validating property data on load
* @param macro_env_init Dictionary of loaded values map:<name, value>
* @param model_state Map of AgentVector to load the agent data into per agent, key should be agent name
* @param input Filename of the input file (This will be used to determine which reader to return)
* @param sim_instance Instance of the Simulation object (This is used for setting/getting config)
Expand All @@ -39,15 +42,17 @@ class StateReaderFactory {
const std::string& model_name,
const std::unordered_map<std::string, EnvironmentData::PropData>& env_desc,
std::unordered_map<std::string, detail::Any>& env_init,
const std::unordered_map<std::string, EnvironmentData::MacroPropData>& macro_env_desc,
std::unordered_map<std::string, std::vector<char>>& macro_env_init,
util::StringPairUnorderedMap<std::shared_ptr<AgentVector>>& model_state,
const std::string& input,
Simulation* sim_instance) {
const std::string extension = std::filesystem::path(input).extension().string();

if (extension == ".xml") {
return new XMLStateReader(model_name, env_desc, env_init, model_state, input, sim_instance);
return new XMLStateReader(model_name, env_desc, env_init, macro_env_desc, macro_env_init, model_state, input, sim_instance);
} else if (extension == ".json") {
return new JSONStateReader(model_name, env_desc, env_init, model_state, input, sim_instance);
return new JSONStateReader(model_name, env_desc, env_init, macro_env_desc, macro_env_init, model_state, input, sim_instance);
}
THROW exception::UnsupportedFileType("File '%s' is not a type which can be read "
"by StateReaderFactory::createReader().",
Expand Down
5 changes: 5 additions & 0 deletions include/flamegpu/io/XMLStateReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

#include "flamegpu/io/StateReader.h"
#include "flamegpu/model/ModelDescription.h"
Expand All @@ -24,6 +25,8 @@ class XMLStateReader : public StateReader {
* @param model_name Name from the model description hierarchy of the model to be loaded
* @param env_desc Environment description for validating property data on load
* @param env_init Dictionary of loaded values map:<{name, index}, value>
* @param macro_env_desc Macro environment description for validating property data on load
* @param macro_env_init Dictionary of loaded values map:<name, value>
* @param model_state Map of AgentVector to load the agent data into per agent, key should be agent name
* @param input_file Filename of the input file (This will be used to determine which reader to return)
* @param sim_instance Instance of the Simulation object (This is used for setting/getting config)
Expand All @@ -32,6 +35,8 @@ class XMLStateReader : public StateReader {
const std::string &model_name,
const std::unordered_map<std::string, EnvironmentData::PropData> &env_desc,
std::unordered_map<std::string, detail::Any> &env_init,
const std::unordered_map<std::string, EnvironmentData::MacroPropData> &macro_env_desc,
std::unordered_map<std::string, std::vector<char>> &macro_env_init,
util::StringPairUnorderedMap<std::shared_ptr<AgentVector>> &model_state,
const std::string &input_file,
Simulation *sim_instance);
Expand Down
4 changes: 4 additions & 0 deletions include/flamegpu/simulation/CUDASimulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,10 @@ class CUDASimulation : public Simulation {
* Common method for adding this Model's data to env manager
*/
void initEnvironmentMgr();
/**
* Common method for initialising macro environment properties from macro_env_init
*/
void initMacroEnvironment();
/**
* Flag indicating that the model has been initialsed
*/
Expand Down
5 changes: 5 additions & 0 deletions include/flamegpu/simulation/Simulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <ctime>
#include <utility>
#include <unordered_map>
#include <vector>

#include "flamegpu/defines.h"
#include "flamegpu/simulation/detail/AgentInterface.h"
Expand Down Expand Up @@ -184,6 +185,10 @@ class Simulation {
* Initial environment items if they have been loaded from file, prior to device selection
*/
std::unordered_map<std::string, detail::Any> env_init;
/**
* Initial macro environment items if they have been loaded from file, prior to device selection
*/
std::unordered_map<std::string, std::vector<char>> macro_env_init;
/**
* the width of the widest layer in the concrete version of the model (calculated once)
*/
Expand Down
73 changes: 70 additions & 3 deletions src/flamegpu/io/JSONStateReader.cu
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <string>
#include <unordered_map>
#include <cerrno>
#include <numeric>

#include "flamegpu/exception/FLAMEGPUException.h"
#include "flamegpu/simulation/AgentVector.h"
Expand All @@ -22,10 +23,12 @@ JSONStateReader::JSONStateReader(
const std::string &model_name,
const std::unordered_map<std::string, EnvironmentData::PropData> &env_desc,
std::unordered_map<std::string, detail::Any> &env_init,
const std::unordered_map<std::string, EnvironmentData::MacroPropData>& macro_env_desc,
std::unordered_map<std::string, std::vector<char>>& macro_env_init,
util::StringPairUnorderedMap<std::shared_ptr<AgentVector>> &model_state,
const std::string &input,
Simulation *sim_instance)
: StateReader(model_name, env_desc, env_init, model_state, input, sim_instance) {}
: StateReader(model_name, env_desc, env_init, macro_env_desc, macro_env_init, model_state, input, sim_instance) {}
/**
* This is the main sax style parser for the json state
* It stores it's current position within the hierarchy with mode, lastKey and current_variable_array_index
Expand All @@ -37,6 +40,8 @@ class JSONStateReader_impl : public rapidjson::BaseReaderHandler<rapidjson::UTF8
std::string filename;
const std::unordered_map<std::string, EnvironmentData::PropData> env_desc;
std::unordered_map<std::string, detail::Any> &env_init;
const std::unordered_map<std::string, EnvironmentData::MacroPropData> macro_env_desc;
std::unordered_map<std::string, std::vector<char>> &macro_env_init;
/**
* Used for setting agent values
*/
Expand All @@ -58,10 +63,14 @@ class JSONStateReader_impl : public rapidjson::BaseReaderHandler<rapidjson::UTF8
JSONStateReader_impl(const std::string &_filename,
const std::unordered_map<std::string, EnvironmentData::PropData> &_env_desc,
std::unordered_map<std::string, detail::Any> &_env_init,
const std::unordered_map<std::string, EnvironmentData::MacroPropData> & _macro_env_desc,
std::unordered_map<std::string, std::vector<char>> & _macro_env_init,
util::StringPairUnorderedMap<std::shared_ptr<AgentVector>> &_model_state)
: filename(_filename)
, env_desc(_env_desc)
, env_init(_env_init)
, macro_env_desc(_macro_env_desc)
, macro_env_init(_macro_env_init)
, model_state(_model_state) { }
template<typename T>
bool processValue(const T val) {
Expand Down Expand Up @@ -113,6 +122,50 @@ class JSONStateReader_impl : public rapidjson::BaseReaderHandler<rapidjson::UTF8
THROW exception::RapidJSONError("Model contains environment property '%s' of unsupported type '%s', "
"in JSONStateReader::parse()\n", lastKey.c_str(), val_type.name());
}
} else if (mode.top() == MacroEnvironment) {
const auto it = macro_env_desc.find(lastKey);
if (it == macro_env_desc.end()) {
THROW exception::RapidJSONError("Input file contains unrecognised macro environment property '%s',"
"in JSONStateReader::parse()\n", lastKey.c_str());
}
const unsigned int macro_prop_elements = std::accumulate(it->second.elements.begin(), it->second.elements.end(), 1, std::multiplies<unsigned int>());
if (current_variable_array_index == 0) {
// New property, create buffer with default value and add to map
if (!macro_env_init.emplace(lastKey, std::vector<char>(macro_prop_elements * it->second.type_size)).second) {
THROW exception::RapidJSONError("Input file contains environment property '%s' multiple times, "
"in JSONStateReader::parse()\n", lastKey.c_str());
}
} else if (current_variable_array_index >= macro_prop_elements) {
THROW exception::RapidJSONError("Input file contains environment property '%s' with %u elements expected %u,"
"in JSONStateReader::parse()\n", lastKey.c_str(), current_variable_array_index, macro_prop_elements);
}
// Retrieve the linked any and replace the value
auto mei = macro_env_init.at(lastKey);
const std::type_index val_type = it->second.type;
if (val_type == std::type_index(typeid(float))) {
static_cast<float*>(static_cast<void*>(mei.data()))[current_variable_array_index++] = static_cast<float>(val);
} else if (val_type == std::type_index(typeid(double))) {
static_cast<double*>(static_cast<void*>(mei.data()))[current_variable_array_index++] = static_cast<double>(val);
} else if (val_type == std::type_index(typeid(int64_t))) {
static_cast<int64_t*>(static_cast<void*>(mei.data()))[current_variable_array_index++] = static_cast<int64_t>(val);
} else if (val_type == std::type_index(typeid(uint64_t))) {
static_cast<uint64_t*>(static_cast<void*>(mei.data()))[current_variable_array_index++] = static_cast<uint64_t>(val);
} else if (val_type == std::type_index(typeid(int32_t))) {
static_cast<int32_t*>(static_cast<void*>(mei.data()))[current_variable_array_index++] = static_cast<int32_t>(val);
} else if (val_type == std::type_index(typeid(uint32_t))) {
static_cast<uint32_t*>(static_cast<void*>(mei.data()))[current_variable_array_index++] = static_cast<uint32_t>(val);
} else if (val_type == std::type_index(typeid(int16_t))) {
static_cast<int16_t*>(static_cast<void*>(mei.data()))[current_variable_array_index++] = static_cast<int16_t>(val);
} else if (val_type == std::type_index(typeid(uint16_t))) {
static_cast<uint16_t*>(static_cast<void*>(mei.data()))[current_variable_array_index++] = static_cast<uint16_t>(val);
} else if (val_type == std::type_index(typeid(int8_t))) {
static_cast<int8_t*>(static_cast<void*>(mei.data()))[current_variable_array_index++] = static_cast<int8_t>(val);
} else if (val_type == std::type_index(typeid(uint8_t))) {
static_cast<uint8_t*>(static_cast<void*>(mei.data()))[current_variable_array_index++] = static_cast<uint8_t>(val);
} else {
THROW exception::RapidJSONError("Model contains macro environment property '%s' of unsupported type '%s', "
"in JSONStateReader::parse()\n", lastKey.c_str(), val_type.name());
}
} else if (mode.top() == AgentInstance) {
const std::shared_ptr<AgentVector> &pop = model_state.at({current_agent, current_state});
AgentVector::Agent instance = pop->back();
Expand Down Expand Up @@ -192,6 +245,8 @@ class JSONStateReader_impl : public rapidjson::BaseReaderHandler<rapidjson::UTF8
mode.push(Stats);
} else if (lastKey == "environment") {
mode.push(Environment);
} else if (lastKey == "macro_environment") {
mode.push(MacroEnvironment);
} else if (lastKey == "agents") {
mode.push(Agents);
} else {
Expand Down Expand Up @@ -236,6 +291,8 @@ class JSONStateReader_impl : public rapidjson::BaseReaderHandler<rapidjson::UTF8
mode.push(VariableArray);
} else if (mode.top() == Environment) {
mode.push(VariableArray);
} else if (mode.top() == MacroEnvironment) {
mode.push(VariableArray);
} else if (mode.top() == Agent) {
current_state = lastKey;
mode.push(State);
Expand All @@ -254,6 +311,14 @@ class JSONStateReader_impl : public rapidjson::BaseReaderHandler<rapidjson::UTF8
THROW exception::RapidJSONError("Input file contains environment property '%s' with %u elements expected %u,"
"in JSONStateReader::parse()\n", lastKey.c_str(), current_variable_array_index, prop.data.elements);
}
} else if (mode.top() == MacroEnvironment) {
// Confirm macro env array had correct number of elements
const auto macro_prop = macro_env_desc.at(lastKey);
const unsigned int macro_prop_elements = std::accumulate(macro_prop.elements.begin(), macro_prop.elements.end(), 1, std::multiplies<unsigned int>());
if (current_variable_array_index != macro_prop_elements) {
THROW exception::RapidJSONError("Input file contains environment macro property '%s' with %u elements expected %u,"
"in JSONStateReader::parse()\n", lastKey.c_str(), current_variable_array_index, macro_prop_elements);
}
}
current_variable_array_index = 0;
} else {
Expand All @@ -268,7 +333,7 @@ class JSONStateReader_impl : public rapidjson::BaseReaderHandler<rapidjson::UTF8
* It also reads the config blocks, so that device can be init before we do environment
*/
class JSONStateReader_agentsize_counter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, JSONStateReader_impl> {
enum Mode{ Nop, Root, Config, Stats, SimCfg, CUDACfg, Environment, Agents, Agent, State, AgentInstance, VariableArray };
enum Mode{ Nop, Root, Config, Stats, SimCfg, CUDACfg, Environment, MacroEnvironment, Agents, Agent, State, AgentInstance, VariableArray };
std::stack<Mode> mode;
std::string lastKey;
unsigned int currentIndex = 0;
Expand Down Expand Up @@ -374,6 +439,8 @@ class JSONStateReader_agentsize_counter : public rapidjson::BaseReaderHandler<ra
mode.push(Stats);
} else if (lastKey == "environment") {
mode.push(Environment);
} else if (lastKey == "macro_environment") {
mode.push(MacroEnvironment);
} else if (lastKey == "agents") {
mode.push(Agents);
} else {
Expand Down Expand Up @@ -437,7 +504,7 @@ int JSONStateReader::parse() {
THROW exception::RapidJSONError("Unable to open file '%s' for reading.\n", inputFile.c_str());
}
JSONStateReader_agentsize_counter agentcounter(inputFile, sim_instance);
JSONStateReader_impl handler(inputFile, env_desc, env_init, model_state);
JSONStateReader_impl handler(inputFile, env_desc, env_init, macro_env_desc, macro_env_init, model_state);
std::string filestring = std::string((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
rapidjson::StringStream filess(filestring.c_str());
rapidjson::Reader reader;
Expand Down
Loading

0 comments on commit cabc60c

Please sign in to comment.