Skip to content

Commit

Permalink
WIP: Refactor variables
Browse files Browse the repository at this point in the history
  • Loading branch information
kbenne committed Aug 7, 2024
1 parent 4629b5a commit e976b34
Show file tree
Hide file tree
Showing 12 changed files with 322 additions and 267 deletions.
4 changes: 2 additions & 2 deletions energyplus_coroutine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ add_library(

input/emsactuator.hpp
input/emsactuator.cpp
input/input.hpp
input/input.cpp
input/user_config.hpp
input/user_config.cpp
input/outputvariable.hpp
input/outputvariable.cpp
input/runperiod.hpp
Expand Down
38 changes: 20 additions & 18 deletions energyplus_coroutine/create_fmu.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "create_fmu.hpp"
#include "idf_to_json.hpp"
#include "idfprep.hpp"
#include "input/input.hpp"
#include "input/user_config.hpp"
#include "modelDescription.xml.hpp"
#include "util/conversion.hpp"
#include "util/fmi_paths.hpp"
Expand All @@ -13,26 +13,28 @@ using json = nlohmann::json;

namespace spawn {

void createModelDescription(const spawn::Input &input, const spawn_fs::path &savepath, const std::string &id);
void createModelDescription(const spawn::UserConfig &user_config,
const spawn_fs::path &savepath,
const std::string &id);
void copyIDFResourceFiles(const json &jsonidf, const spawn_fs::path &from, const spawn_fs::path &to);

void energyplus::CreateFMU::operator()() const
{
spawn::Input input(input_path.string());
spawn::UserConfig user_config(input_path.string());

// We are going to copy the required files into an FMU staging directory,
// also copy the json input file into root of the fmu staging directory,
// and rewrite the json input file paths so that they reflect the new paths
// contained within the fmu layout.

// The default fmu output path
auto fmuPath = spawn_fs::current_path() / (input.fmuBaseName() + ".fmu");
auto fmuPath = spawn_fs::current_path() / (user_config.fmuBaseName() + ".fmu");

// These are options to override the default output path
if (!output_path.empty()) {
fmuPath = output_path;
} else if (!output_dir.empty()) {
fmuPath = output_dir / (input.fmuBaseName() + ".fmu");
fmuPath = output_dir / (user_config.fmuBaseName() + ".fmu");
}

if (fmuPath.extension() != ".fmu") {
Expand Down Expand Up @@ -64,8 +66,8 @@ void energyplus::CreateFMU::operator()() const
const auto modelDescriptionPath = fmuStagingPath / "modelDescription.xml";
const auto fmuResourcesPath = fmuStagingPath / "resources";
const auto fmuspawnPath = fmuResourcesPath / "model.spawn";
const auto fmuidfPath = fmuResourcesPath / (input.idfInputPath().stem().string() + ".spawn.idf");
const auto fmuepwPath = fmuResourcesPath / input.epwInputPath().filename();
const auto fmuidfPath = fmuResourcesPath / (user_config.idfInputPath().stem().string() + ".spawn.idf");
const auto fmuepwPath = fmuResourcesPath / user_config.epwInputPath().filename();
const auto fmuiddPath = fmuResourcesPath / idd_path.filename();
const auto fmuEPFMIPath = fmuStagingPath / fmi_lib_path(id);

Expand All @@ -77,31 +79,31 @@ void energyplus::CreateFMU::operator()() const
spawn_fs::create_directories(fmuResourcesPath);
spawn_fs::create_directories(fmuEPFMIPath.parent_path());

auto idfjson = idf_to_json(input.idfInputPath());
auto start_time = StartTime(day_from_string(input.runPeriod.day_of_week_for_start_day), 0.0);
prepare_idf(idfjson, input, start_time);
copyIDFResourceFiles(idfjson, input.idfInputPath().parent_path(), fmuResourcesPath);
auto idfjson = idf_to_json(user_config.idfInputPath());
auto start_time = StartTime(day_from_string(user_config.runPeriod.day_of_week_for_start_day), 0.0);
prepare_idf(idfjson, user_config, start_time);
copyIDFResourceFiles(idfjson, user_config.idfInputPath().parent_path(), fmuResourcesPath);
json_to_idf(idfjson, fmuidfPath);

spawn_fs::copy_file(epfmu_path, fmuEPFMIPath, spawn_fs::copy_options::overwrite_existing);
spawn_fs::copy_file(idd_path, fmuiddPath, spawn_fs::copy_options::overwrite_existing);
spawn_fs::copy_file(input.epwInputPath(), fmuepwPath, spawn_fs::copy_options::overwrite_existing);
spawn_fs::copy_file(user_config.epwInputPath(), fmuepwPath, spawn_fs::copy_options::overwrite_existing);

createModelDescription(input, modelDescriptionPath, id);
createModelDescription(user_config, modelDescriptionPath, id);

const auto relativeEPWPath = spawn_fs::relative(fmuepwPath, fmuResourcesPath);
input.setEPWInputPath(relativeEPWPath);
user_config.setEPWInputPath(relativeEPWPath);
const auto relativeIdfPath = spawn_fs::relative(fmuidfPath, fmuResourcesPath);
input.setIdfInputPath(relativeIdfPath);
input.save(fmuspawnPath);
user_config.setIdfInputPath(relativeIdfPath);
user_config.save(fmuspawnPath);

if (!no_zip) {
zip_directory(fmuStagingPath.string(), fmuPath.string(), no_compress);
spawn_fs::remove_all(fmuStagingPath);
}
}

void createModelDescription([[maybe_unused]] const spawn::Input &input,
void createModelDescription([[maybe_unused]] const spawn::UserConfig &user_config,
const spawn_fs::path &savepath,
const std::string &id)
{
Expand All @@ -117,7 +119,7 @@ void createModelDescription([[maybe_unused]] const spawn::Input &input,

[[maybe_unused]] auto xmlvariables = fmiModelDescription.child("ModelVariables");
// TODO: init variables
variable::Variables variables;
variable::Variables variables(user_config);
// const auto variables = parseVariables(input);

// for (const auto &varpair : variables) {
Expand Down
57 changes: 29 additions & 28 deletions energyplus_coroutine/idfprep.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
#include "idfprep.hpp"
#include "input/input.hpp"
#include "input/user_config.hpp"
#include "util/strings.hpp"

namespace spawn {

json &adjustSimulationControl(json &jsonidf, const Input &input)
json &adjustSimulationControl(json &jsonidf, const UserConfig &user_config)
{
constexpr auto simulationcontroltype = "SimulationControl";

// Remove the existing control first
jsonidf.erase(simulationcontroltype);

// TODO: fix this slop. Please add a consistent method of handling bool types
const auto autosize = input.autosize() ? "Yes" : "No";
const auto autosize = user_config.autosize() ? "Yes" : "No";
// This is what we need for spawn
jsonidf[simulationcontroltype] = {{"Spawn-SimulationControl",
{{"do_plant_sizing_calculation", "No"},
Expand All @@ -24,7 +24,7 @@ json &adjustSimulationControl(json &jsonidf, const Input &input)
return jsonidf;
}

json &addRunPeriod(json &jsonidf, [[maybe_unused]] const Input &input, const StartTime &start_time)
json &addRunPeriod(json &jsonidf, [[maybe_unused]] const UserConfig &user_config, const StartTime &start_time)
{
constexpr auto runperiodtype = "RunPeriod";
// Remove the existing run periods first
Expand All @@ -34,18 +34,19 @@ json &addRunPeriod(json &jsonidf, [[maybe_unused]] const Input &input, const Sta
// 200 years should be plenty
jsonidf[runperiodtype] = {
{"Spawn-RunPeriod",
{{"apply_weekend_holiday_rule", input.runPeriod.apply_weekend_holiday_rule},
{{"apply_weekend_holiday_rule", user_config.runPeriod.apply_weekend_holiday_rule},
{"begin_day_of_month", int(start_time.EnergyPlusEpoch().day())},
{"begin_month", int(start_time.EnergyPlusEpoch().month())},
{"begin_year", int(start_time.EnergyPlusEpoch().year())},
{"day_of_week_for_start_day", input.runPeriod.day_of_week_for_start_day},
{"day_of_week_for_start_day", user_config.runPeriod.day_of_week_for_start_day},
{"end_day_of_month", 31},
{"end_month", 12},
{"end_year", 2217},
{"use_weather_file_daylight_saving_period", input.runPeriod.use_weather_file_daylight_saving_period},
{"use_weather_file_holidays_and_special_days", input.runPeriod.use_weather_file_holidays_and_special_days},
{"use_weather_file_rain_indicators", input.runPeriod.use_weather_file_rain_indicators},
{"use_weather_file_snow_indicators", input.runPeriod.use_weather_file_snow_indicators}}}};
{"use_weather_file_daylight_saving_period", user_config.runPeriod.use_weather_file_daylight_saving_period},
{"use_weather_file_holidays_and_special_days",
user_config.runPeriod.use_weather_file_holidays_and_special_days},
{"use_weather_file_rain_indicators", user_config.runPeriod.use_weather_file_rain_indicators},
{"use_weather_file_snow_indicators", user_config.runPeriod.use_weather_file_snow_indicators}}}};

return jsonidf;
}
Expand All @@ -59,7 +60,7 @@ json &addRunPeriod(json &jsonidf, [[maybe_unused]] const Input &input, const Sta
// this approach seems reasonable
// With this approach QGaiRad_flow will interface with the OtherEquipment actuator,
// Spawn user does not need to interface directly with the actuator
json &addOtherEquipment(json &jsonidf, const Input &input)
json &addOtherEquipment(json &jsonidf, const UserConfig &user_config)
{
constexpr auto scheduletype = "Schedule:Constant";
constexpr auto schedulename = "Spawn-RadiantGains-Schedule";
Expand All @@ -71,7 +72,7 @@ json &addOtherEquipment(json &jsonidf, const Input &input)
jsonidf[scheduletype][schedulename] = {{"schedule_type_limits_name", schedule_typelimits_name},
{"hourly_value", "1.0"}};

for (const auto &zone : input.zones) {
for (const auto &zone : user_config.zones) {
if (!zone.isconnected) {
continue;
}
Expand Down Expand Up @@ -125,7 +126,7 @@ json &removeUnusedObjects(json &jsonidf)
return jsonidf;
}

json &addPeopleOutputVariables(json &jsonidf, const Input &input)
json &addPeopleOutputVariables(json &jsonidf, const UserConfig &user_config)
{
// Some zones don't have people input, which will result in an EnergyPlus error,
// Insert a default people object that defines zero people
Expand All @@ -143,7 +144,7 @@ json &addPeopleOutputVariables(json &jsonidf, const Input &input)
jsonidf[scheduletype][activitySchedulename] = {{"schedule_type_limits_name", schedule_typelimits_name},
{"hourly_value", "100.0"}};

for (const auto &zone : input.zones) {
for (const auto &zone : user_config.zones) {
if (!zone.isconnected) {
continue;
}
Expand All @@ -169,14 +170,14 @@ json &addPeopleOutputVariables(json &jsonidf, const Input &input)
}

// Add output variables requested in the spawn input file, but not in the idf
json &addRequestedOutputVariables(json &jsonidf, const Input &input)
json &addRequestedOutputVariables(json &jsonidf, const UserConfig &user_config)
{
// A pair that holds an output variable name and key,
using Varpair = std::pair<std::string, std::string>;

// Make a list of the requested outputs
std::vector<Varpair> requestedpairs;
for (const auto &var : input.outputVariables) {
for (const auto &var : user_config.outputVariables) {
requestedpairs.emplace_back(var.idfname, var.idfkey);
}

Expand Down Expand Up @@ -262,7 +263,7 @@ json &expandInfiltrationZoneLists(json &jsonidf)
// since some zones have infiltration output variables and actuators while others don't.
// To address this confusion we will insert default infiltration objects for connected zones,
// which have zero flow specified.
json &addDefaultZeroInfiltration(json &jsonidf, const Input &input)
json &addDefaultZeroInfiltration(json &jsonidf, const UserConfig &user_config)
{
constexpr auto infiltrationType = "ZoneInfiltration:DesignFlowRate";
constexpr auto scheduletype = "Schedule:Constant";
Expand All @@ -275,7 +276,7 @@ json &addDefaultZeroInfiltration(json &jsonidf, const Input &input)
jsonidf[scheduletype][schedulename] = {{"schedule_type_limits_name", schedule_typelimits_name},
{"hourly_value", "1.0"}};

const auto zones = input.zones;
const auto zones = user_config.zones;
for (const auto &zone : zones) {
// Only add default infiltration for "connected" zones
if (zone.isconnected) {
Expand All @@ -296,7 +297,7 @@ json &addDefaultZeroInfiltration(json &jsonidf, const Input &input)
}

// Remove infiltration idf input objects for zones that are connected to Modelica
json &removeInfiltration(json &jsonidf, const Input &input)
json &removeInfiltration(json &jsonidf, const UserConfig &user_config)
{
// First expand any infiltration that uses zone lists
expandInfiltrationZoneLists(jsonidf);
Expand All @@ -307,7 +308,7 @@ json &removeInfiltration(json &jsonidf, const Input &input)
{"ZoneInfiltration:EffectiveLeakageArea", "zone_name"},
{"ZoneInfiltration:FlowCoefficient", "zone_name"}}};

const auto zones = input.zones;
const auto zones = user_config.zones;

for (const auto &type : infiltrationTypes) {
auto &infiltrationObjects = jsonidf[type.first];
Expand All @@ -323,20 +324,20 @@ json &removeInfiltration(json &jsonidf, const Input &input)
}
}

addDefaultZeroInfiltration(jsonidf, input);
addDefaultZeroInfiltration(jsonidf, user_config);

return jsonidf;
}

void prepare_idf(json &jsonidf, const Input &input, const StartTime &start_time)
void prepare_idf(json &jsonidf, const UserConfig &user_config, const StartTime &start_time)
{
adjustSimulationControl(jsonidf, input);
adjustSimulationControl(jsonidf, user_config);
removeUnusedObjects(jsonidf);
addRunPeriod(jsonidf, input, start_time);
removeInfiltration(jsonidf, input);
addOtherEquipment(jsonidf, input);
addRequestedOutputVariables(jsonidf, input);
addPeopleOutputVariables(jsonidf, input);
addRunPeriod(jsonidf, user_config, start_time);
removeInfiltration(jsonidf, user_config);
addOtherEquipment(jsonidf, user_config);
addRequestedOutputVariables(jsonidf, user_config);
addPeopleOutputVariables(jsonidf, user_config);
}

void validate_idf(json &jsonidf)
Expand Down
4 changes: 2 additions & 2 deletions energyplus_coroutine/idfprep.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
using json = nlohmann::json;

namespace spawn {
class Input;
class UserConfig;

// Reduce the jsonidf down to the EnergyPlus features that Spawn depends on,
// and insert idf content that is required.
void prepare_idf(json &jsonidf, const Input &input, const StartTime &start_time);
void prepare_idf(json &jsonidf, const UserConfig &user_config, const StartTime &start_time);

// Validate the jsonidf to ensure that the user input is not requesting something
// that Spawn does not support, such as zone multipliers.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include "input.hpp"
#include "../idf_to_json.hpp"
#include "user_config.hpp"

using json = nlohmann::json;

namespace spawn {

Input::Input(const std::string &spawninput)
UserConfig::UserConfig(const std::string &spawninput)
{
std::ifstream fileinput(spawninput);
if (!fileinput.fail()) {
Expand Down Expand Up @@ -42,22 +42,22 @@ Input::Input(const std::string &spawninput)
runPeriod = RunPeriod::create_run_period(spawnjson);
}

std::string Input::fmuname() const
std::string UserConfig::fmuname() const
{
return spawnjson.value("fmu", json()).value("name", "spawn.fmu");
}

std::string Input::fmuBaseName() const
std::string UserConfig::fmuBaseName() const
{
return spawn_fs::path(fmuname()).stem().string();
}

void Input::setFMUName(std::string name)
void UserConfig::setFMUName(std::string name)
{
spawnjson["fmu"]["name"] = std::move(name);
}

spawn_fs::path Input::toPath(const std::string &pathstring) const
spawn_fs::path UserConfig::toPath(const std::string &pathstring) const
{
spawn_fs::path p(pathstring);
if (!p.is_absolute()) {
Expand All @@ -67,7 +67,7 @@ spawn_fs::path Input::toPath(const std::string &pathstring) const
return p;
}

double Input::relativeSurfaceTolerance() const
double UserConfig::relativeSurfaceTolerance() const
{
const auto tol = spawnjson.value("EnergyPlus", json())["relativeSurfaceTolerance"];
if (!tol.is_null()) {
Expand All @@ -78,38 +78,38 @@ double Input::relativeSurfaceTolerance() const
return 1.0e-6;
}

spawn_fs::path Input::idfInputPath() const
spawn_fs::path UserConfig::idfInputPath() const
{
return toPath(spawnjson.value("EnergyPlus", json()).value("idf", "in.idf"));
}

void Input::setIdfInputPath(const spawn_fs::path &idfpath)
void UserConfig::setIdfInputPath(const spawn_fs::path &idfpath)
{
spawnjson["EnergyPlus"]["idf"] = idfpath.string();
}

spawn_fs::path Input::epwInputPath() const
spawn_fs::path UserConfig::epwInputPath() const
{
return toPath(spawnjson.value("EnergyPlus", json()).value("weather", "in.epw"));
}

void Input::setEPWInputPath(const spawn_fs::path &epwpath)
void UserConfig::setEPWInputPath(const spawn_fs::path &epwpath)
{
spawnjson["EnergyPlus"]["weather"] = epwpath.string();
}

bool Input::autosize() const
bool UserConfig::autosize() const
{
return spawnjson.value("EnergyPlus", json()).value("autosize", false);
}

void Input::save(const spawn_fs::path &savepath) const
void UserConfig::save(const spawn_fs::path &savepath) const
{
std::ofstream o(savepath.string());
o << std::setw(4) << spawnjson << std::endl;
}

spawn_fs::path Input::basepath() const
spawn_fs::path UserConfig::basepath() const
{
return m_basepath;
}
Expand Down
Loading

0 comments on commit e976b34

Please sign in to comment.