From 790306e0b9ebe4d84bee6dde5410734cb8cc9ce5 Mon Sep 17 00:00:00 2001 From: Kyle Benne Date: Fri, 28 Jun 2024 12:02:17 -0500 Subject: [PATCH] Add support for autosizing This change adds new outputs for zone sizing information. There are a few limitations. * Coincident sizing between zones is not yet supported, but is in the spec, and will be added later. * Outputs related to the time of peak load are not yet populated. * Need formal test methodolgy for this feature. --- CMakeLists.txt | 2 +- energyplus_coroutine/iddtypes.hpp | 5 +- energyplus_coroutine/idfprep.cpp | 10 +- energyplus_coroutine/input/input.cpp | 5 + energyplus_coroutine/input/input.hpp | 2 + energyplus_coroutine/spawn.cpp | 86 +++++++++ energyplus_coroutine/spawn.hpp | 4 + energyplus_coroutine/variables.cpp | 256 +++++++++++++++++++++++++++ energyplus_coroutine/variables.hpp | 13 ++ 9 files changed, 377 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd65ae264..179643734 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_policy(SET CMP0048 NEW) cmake_policy(SET CMP0025 NEW) cmake_minimum_required(VERSION 3.13) -project(Spawn VERSION 0.5.0) +project(Spawn VERSION 0.6.0) include(CTest) set(CMAKE_CXX_STANDARD 17) diff --git a/energyplus_coroutine/iddtypes.hpp b/energyplus_coroutine/iddtypes.hpp index 8643c1a62..0e1e831e5 100644 --- a/energyplus_coroutine/iddtypes.hpp +++ b/energyplus_coroutine/iddtypes.hpp @@ -7,7 +7,7 @@ namespace spawn { constexpr std::array supportedScheduleTypes = { "Schedule:Year", "Schedule:Compact", "Schedule:Constant", "Schedule:File"}; -constexpr std::array supportedIDDTypes = { +constexpr std::array supportedIDDTypes = { "Version", "SimulationControl", "PerformancePrecisionTradeoffs", @@ -26,6 +26,9 @@ constexpr std::array supportedIDDTypes = { "RunPeriod", "RunPeriodControl:SpecialDays", "RunPeriodControl:DaylightSavingTime", + "SizingPeriod:DesignDay", + "SizingPeriod:WeatherFileDays", + "SizingPeriod:WeatherFileConditionType", "WeatherProperty:SkyTemperature", "Site:WeatherStation", "Site:HeightVariation", diff --git a/energyplus_coroutine/idfprep.cpp b/energyplus_coroutine/idfprep.cpp index d9ea7563d..241f3f9c6 100644 --- a/energyplus_coroutine/idfprep.cpp +++ b/energyplus_coroutine/idfprep.cpp @@ -4,19 +4,21 @@ namespace spawn { -json &adjustSimulationControl(json &jsonidf) +json &adjustSimulationControl(json &jsonidf, const Input &input) { 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"; // This is what we need for spawn jsonidf[simulationcontroltype] = {{"Spawn-SimulationControl", {{"do_plant_sizing_calculation", "No"}, {"do_system_sizing_calculation", "No"}, - {"do_zone_sizing_calculation", "No"}, - {"run_simulation_for_sizing_periods", "No"}, + {"do_zone_sizing_calculation", autosize}, + {"run_simulation_for_sizing_periods", autosize}, {"run_simulation_for_weather_file_run_periods", "Yes"}}}}; return jsonidf; @@ -328,7 +330,7 @@ json &removeInfiltration(json &jsonidf, const Input &input) void prepare_idf(json &jsonidf, const Input &input, const StartTime &start_time) { - adjustSimulationControl(jsonidf); + adjustSimulationControl(jsonidf, input); removeUnusedObjects(jsonidf); addRunPeriod(jsonidf, input, start_time); removeInfiltration(jsonidf, input); diff --git a/energyplus_coroutine/input/input.cpp b/energyplus_coroutine/input/input.cpp index ceec523a3..2ef573038 100644 --- a/energyplus_coroutine/input/input.cpp +++ b/energyplus_coroutine/input/input.cpp @@ -98,6 +98,11 @@ void Input::setEPWInputPath(const spawn_fs::path &epwpath) spawnjson["EnergyPlus"]["weather"] = epwpath.string(); } +bool Input::autosize() const +{ + return spawnjson.value("EnergyPlus", json()).value("autosize", false); +} + void Input::save(const spawn_fs::path &savepath) const { std::ofstream o(savepath.string()); diff --git a/energyplus_coroutine/input/input.hpp b/energyplus_coroutine/input/input.hpp index f0334fe42..3a24d4e6e 100644 --- a/energyplus_coroutine/input/input.hpp +++ b/energyplus_coroutine/input/input.hpp @@ -40,6 +40,8 @@ class Input [[nodiscard]] spawn_fs::path epwInputPath() const; void setEPWInputPath(const spawn_fs::path &epwpath); + [[nodiscard]] bool autosize() const; + double relativeSurfaceTolerance() const; void save(const spawn_fs::path &savepath) const; diff --git a/energyplus_coroutine/spawn.cpp b/energyplus_coroutine/spawn.cpp index 27f5e73e6..893db7537 100644 --- a/energyplus_coroutine/spawn.cpp +++ b/energyplus_coroutine/spawn.cpp @@ -94,6 +94,9 @@ void Spawn::start() sim_thread.join(); } + // This will poppulate const parameters such as the zone sizing values + initConstParameters(); + // This will make sure that we have a data exchange setTime(start_time_.Seconds()); } @@ -562,6 +565,84 @@ double Spawn::getSensorValue(Variable &var) return getVariableValue(simState(), h); } +void Spawn::initConstParameters() +{ + isRunningCheck(); + + // TODO: look for a better way to check sizing. + // DoZoneSizing does not indicate that sizing was done, + // so we have to be careful about when to call initConstParameters + // sim_state.dataSize->FinalZoneSizing will not be filled out if zone sizing do not happen + if (!sim_state.dataGlobal->DoZoneSizing) { + return; + } + + for (auto &varmap : variables) { + auto &var = varmap.second; + auto zone_num = zoneNum(var.name); + + switch (var.type) { // NOLINT + case VariableType::QCOOSEN_FLOW: { + const auto value = sim_state.dataSize->FinalZoneSizing[zone_num].DesCoolLoad; + var.setValue(value, spawn::units::UnitSystem::EP); + break; + } + case VariableType::QCOOLAT_FLOW: { + const auto value = sim_state.dataSize->FinalZoneSizing[zone_num].DesLatentCoolLoad; + var.setValue(value, spawn::units::UnitSystem::EP); + break; + } + case VariableType::TOUTCOO: { + const auto value = sim_state.dataSize->FinalZoneSizing[zone_num].OutTempAtCoolPeak; + var.setValue(value, spawn::units::UnitSystem::EP); + break; + } + case VariableType::XOUTCOO: { + const auto value = sim_state.dataSize->FinalZoneSizing[zone_num].OutHumRatAtLatentCoolPeak; + var.setValue(value, spawn::units::UnitSystem::EP); + break; + } + case VariableType::TCOO: { + const auto value = 0; + var.setValue(value, spawn::units::UnitSystem::EP); + break; + } + case VariableType::QHEA_FLOW: { + const auto value = sim_state.dataSize->FinalZoneSizing[zone_num].DesHeatLoad; + var.setValue(value, spawn::units::UnitSystem::EP); + break; + } + case VariableType::TOUTHEA: { + const auto value = sim_state.dataSize->FinalZoneSizing[zone_num].OutTempAtHeatPeak; + var.setValue(value, spawn::units::UnitSystem::EP); + break; + } + case VariableType::XOUTHEA: { + const auto value = sim_state.dataSize->FinalZoneSizing[zone_num].OutHumRatAtLatentHeatPeak; + var.setValue(value, spawn::units::UnitSystem::EP); + break; + } + case VariableType::MOUTCOO_FLOW: { + const auto value = 0; + var.setValue(value, spawn::units::UnitSystem::EP); + break; + } + case VariableType::MOUTHEA_FLOW: { + const auto value = 0; + var.setValue(value, spawn::units::UnitSystem::EP); + break; + } + case VariableType::THEA: { + const auto value = 0; + var.setValue(value, spawn::units::UnitSystem::EP); + break; + } + default: + break; + } + } +} + void Spawn::exchange(const bool force) { isRunningCheck(); @@ -719,6 +800,11 @@ void Spawn::initZoneEquip() void Spawn::externalHVACManager([[maybe_unused]] EnergyPlusState state) { + // Don't run external HVAC during sizing + if (sim_state.dataGlobal->ZoneSizingCalc) { + return; + } + // Although we do not use the ZoneTempPredictorCorrector, // some global variables need to be initialized by InitZoneAirSetPoints // This is protected by a one time flag so that it will only happen once diff --git a/energyplus_coroutine/spawn.hpp b/energyplus_coroutine/spawn.hpp index 8ecb8317f..f7731a68a 100644 --- a/energyplus_coroutine/spawn.hpp +++ b/energyplus_coroutine/spawn.hpp @@ -165,6 +165,10 @@ class Spawn double getInsideSurfaceHeatFlow(const int surfacenum) const; double getOutsideSurfaceHeatFlow(const int surfacenum) const; + // Initialize Variables that have fixed values that do not change during the simulation. + // This should be called at the end of the ::start() sequence. + void initConstParameters(); + // WarmupManager will register its own callbacks during construction // Maybe all of Spawn's implementation can be derived from "Manager" class // Maybe all of EnergyPlus can derive from Manager and the simulation is diff --git a/energyplus_coroutine/variables.cpp b/energyplus_coroutine/variables.cpp index b227dadbb..e6f22fcf0 100644 --- a/energyplus_coroutine/variables.cpp +++ b/energyplus_coroutine/variables.cpp @@ -381,6 +381,262 @@ std::map parseVariables(const spawn::Input &input) result.emplace(i, std::move(var)); } + // Sizing related parameters + ++i; + { + const auto var_name = zone.idfname + "_QCooSen_flow"; + Variable var; + var.type = VariableType::QCOOSEN_FLOW; + var.name = zone.idfname; + var.epunittype = spawn::units::UnitType::W; + var.mounittype = spawn::units::UnitType::W; + + var.scalar_attributes.emplace_back("name", var_name); + var.scalar_attributes.emplace_back("valueReference", std::to_string(i)); + var.scalar_attributes.emplace_back("description", "Design sensible cooling load"); + var.scalar_attributes.emplace_back("causality", "calculatedParameter"); + var.scalar_attributes.emplace_back("variability", "fixed"); + var.scalar_attributes.emplace_back("initial", "calculated"); + + var.real_attributes.emplace_back("quantity", "Power"); + var.real_attributes.emplace_back("relativeQuantity", "false"); + var.real_attributes.emplace_back("unit", spawn::units::toString(var.mounittype)); + + var.setValue(0.0, spawn::units::UnitSystem::MO); + result.emplace(i, std::move(var)); + } + ++i; + { + const auto var_name = zone.idfname + "_QCooLat_flow"; + Variable var; + var.type = VariableType::QCOOLAT_FLOW; + var.name = zone.idfname; + var.epunittype = spawn::units::UnitType::W; + var.mounittype = spawn::units::UnitType::W; + + var.scalar_attributes.emplace_back("name", var_name); + var.scalar_attributes.emplace_back("valueReference", std::to_string(i)); + var.scalar_attributes.emplace_back("description", "Design latent cooling load"); + var.scalar_attributes.emplace_back("causality", "calculatedParameter"); + var.scalar_attributes.emplace_back("variability", "fixed"); + var.scalar_attributes.emplace_back("initial", "calculated"); + + var.real_attributes.emplace_back("quantity", "Power"); + var.real_attributes.emplace_back("relativeQuantity", "false"); + var.real_attributes.emplace_back("unit", spawn::units::toString(var.mounittype)); + + var.setValue(0.0, spawn::units::UnitSystem::MO); + result.emplace(i, std::move(var)); + } + ++i; + { + const auto var_name = zone.idfname + "_TOutCoo"; + Variable var; + var.type = VariableType::TOUTCOO; + var.name = zone.idfname; + var.epunittype = spawn::units::UnitType::C; + var.mounittype = spawn::units::UnitType::K; + + var.scalar_attributes.emplace_back("name", var_name); + var.scalar_attributes.emplace_back("valueReference", std::to_string(i)); + var.scalar_attributes.emplace_back("description", "Outdoor drybulb temperature at the cooling design load"); + var.scalar_attributes.emplace_back("causality", "calculatedParameter"); + var.scalar_attributes.emplace_back("variability", "fixed"); + var.scalar_attributes.emplace_back("initial", "calculated"); + + var.real_attributes.emplace_back("quantity", "ThermodynamicTemperature"); + var.real_attributes.emplace_back("relativeQuantity", "false"); + var.real_attributes.emplace_back("unit", spawn::units::toString(var.mounittype)); + + var.setValue(0.0, spawn::units::UnitSystem::MO); + result.emplace(i, std::move(var)); + } + ++i; + { + const auto var_name = zone.idfname + "_XOutCoo"; + Variable var; + var.type = VariableType::XOUTCOO; + var.name = zone.idfname; + var.epunittype = spawn::units::UnitType::one; + var.mounittype = spawn::units::UnitType::one; + + var.scalar_attributes.emplace_back("name", var_name); + var.scalar_attributes.emplace_back("valueReference", std::to_string(i)); + var.scalar_attributes.emplace_back( + "description", "Outdoor humidity ratio at the cooling design load per total air mass of the zone"); + var.scalar_attributes.emplace_back("causality", "calculatedParameter"); + var.scalar_attributes.emplace_back("variability", "fixed"); + var.scalar_attributes.emplace_back("initial", "calculated"); + + var.real_attributes.emplace_back("relativeQuantity", "false"); + var.real_attributes.emplace_back("unit", spawn::units::toString(var.mounittype)); + + var.setValue(0.0, spawn::units::UnitSystem::MO); + result.emplace(i, std::move(var)); + } + ++i; + { + const auto var_name = zone.idfname + "_tCoo"; + Variable var; + var.type = VariableType::TCOO; + var.name = zone.idfname; + var.epunittype = spawn::units::UnitType::s; + var.mounittype = spawn::units::UnitType::s; + + var.scalar_attributes.emplace_back("name", var_name); + var.scalar_attributes.emplace_back("valueReference", std::to_string(i)); + var.scalar_attributes.emplace_back("description", "Time at which these loads occurred"); + var.scalar_attributes.emplace_back("causality", "calculatedParameter"); + var.scalar_attributes.emplace_back("variability", "fixed"); + var.scalar_attributes.emplace_back("initial", "calculated"); + + var.real_attributes.emplace_back("quantity", "Time"); + var.real_attributes.emplace_back("relativeQuantity", "false"); + var.real_attributes.emplace_back("unit", spawn::units::toString(var.mounittype)); + + var.setValue(0.0, spawn::units::UnitSystem::MO); + result.emplace(i, std::move(var)); + } + ++i; + { + const auto var_name = zone.idfname + "_QHea_flow"; + Variable var; + var.type = VariableType::QHEA_FLOW; + var.name = zone.idfname; + var.epunittype = spawn::units::UnitType::W; + var.mounittype = spawn::units::UnitType::W; + + var.scalar_attributes.emplace_back("name", var_name); + var.scalar_attributes.emplace_back("valueReference", std::to_string(i)); + var.scalar_attributes.emplace_back("description", "Design heating load"); + var.scalar_attributes.emplace_back("causality", "calculatedParameter"); + var.scalar_attributes.emplace_back("variability", "fixed"); + var.scalar_attributes.emplace_back("initial", "calculated"); + + var.real_attributes.emplace_back("quantity", "Power"); + var.real_attributes.emplace_back("relativeQuantity", "false"); + var.real_attributes.emplace_back("unit", spawn::units::toString(var.mounittype)); + + var.setValue(0.0, spawn::units::UnitSystem::MO); + result.emplace(i, std::move(var)); + } + ++i; + { + const auto var_name = zone.idfname + "_TOutHea"; + Variable var; + var.type = VariableType::TOUTHEA; + var.name = zone.idfname; + var.epunittype = spawn::units::UnitType::C; + var.mounittype = spawn::units::UnitType::K; + + var.scalar_attributes.emplace_back("name", var_name); + var.scalar_attributes.emplace_back("valueReference", std::to_string(i)); + var.scalar_attributes.emplace_back("description", "Outdoor drybulb temperature at the heating design load"); + var.scalar_attributes.emplace_back("causality", "calculatedParameter"); + var.scalar_attributes.emplace_back("variability", "fixed"); + var.scalar_attributes.emplace_back("initial", "calculated"); + + var.real_attributes.emplace_back("quantity", "ThermodynamicTemperature"); + var.real_attributes.emplace_back("relativeQuantity", "false"); + var.real_attributes.emplace_back("unit", spawn::units::toString(var.mounittype)); + + var.setValue(0.0, spawn::units::UnitSystem::MO); + result.emplace(i, std::move(var)); + } + ++i; + { + const auto var_name = zone.idfname + "_XOutHea"; + Variable var; + var.type = VariableType::XOUTHEA; + var.name = zone.idfname; + var.epunittype = spawn::units::UnitType::one; + var.mounittype = spawn::units::UnitType::one; + + var.scalar_attributes.emplace_back("name", var_name); + var.scalar_attributes.emplace_back("valueReference", std::to_string(i)); + var.scalar_attributes.emplace_back( + "description", "Outdoor humidity ratio at the heating design load per total air mass of the zone"); + var.scalar_attributes.emplace_back("causality", "calculatedParameter"); + var.scalar_attributes.emplace_back("variability", "fixed"); + var.scalar_attributes.emplace_back("initial", "calculated"); + + var.real_attributes.emplace_back("relativeQuantity", "false"); + var.real_attributes.emplace_back("unit", spawn::units::toString(var.mounittype)); + + var.setValue(0.0, spawn::units::UnitSystem::MO); + result.emplace(i, std::move(var)); + } + ++i; + { + const auto var_name = zone.idfname + "_tHea"; + Variable var; + var.type = VariableType::THEA; + var.name = zone.idfname; + var.epunittype = spawn::units::UnitType::s; + var.mounittype = spawn::units::UnitType::s; + + var.scalar_attributes.emplace_back("name", var_name); + var.scalar_attributes.emplace_back("valueReference", std::to_string(i)); + var.scalar_attributes.emplace_back("description", "Time at which these loads occurred"); + var.scalar_attributes.emplace_back("causality", "calculatedParameter"); + var.scalar_attributes.emplace_back("variability", "fixed"); + var.scalar_attributes.emplace_back("initial", "calculated"); + + var.real_attributes.emplace_back("quantity", "Time"); + var.real_attributes.emplace_back("relativeQuantity", "false"); + var.real_attributes.emplace_back("unit", spawn::units::toString(var.mounittype)); + + var.setValue(0.0, spawn::units::UnitSystem::MO); + result.emplace(i, std::move(var)); + } + ++i; + { + const auto var_name = zone.idfname + "_mOutCoo_flow"; + Variable var; + var.type = VariableType::MOUTCOO_FLOW; + var.name = zone.idfname; + var.epunittype = spawn::units::UnitType::kg_per_s; + var.mounittype = spawn::units::UnitType::kg_per_s; + + var.scalar_attributes.emplace_back("name", var_name); + var.scalar_attributes.emplace_back("valueReference", std::to_string(i)); + var.scalar_attributes.emplace_back("description", + "Minimum outdoor air flow rate during the cooling design load"); + var.scalar_attributes.emplace_back("causality", "calculatedParameter"); + var.scalar_attributes.emplace_back("variability", "fixed"); + var.scalar_attributes.emplace_back("initial", "calculated"); + + var.real_attributes.emplace_back("quantity", "MassFlowRate"); + var.real_attributes.emplace_back("relativeQuantity", "false"); + var.real_attributes.emplace_back("unit", spawn::units::toString(var.mounittype)); + + var.setValue(0.0, spawn::units::UnitSystem::MO); + result.emplace(i, std::move(var)); + } + ++i; + { + const auto var_name = zone.idfname + "_mOutHea_flow"; + Variable var; + var.type = VariableType::MOUTHEA_FLOW; + var.name = zone.idfname; + var.epunittype = spawn::units::UnitType::kg_per_s; + var.mounittype = spawn::units::UnitType::kg_per_s; + + var.scalar_attributes.emplace_back("name", var_name); + var.scalar_attributes.emplace_back("valueReference", std::to_string(i)); + var.scalar_attributes.emplace_back("description", + "Minimum outdoor air flow rate during the heating design load"); + var.scalar_attributes.emplace_back("causality", "calculatedParameter"); + var.scalar_attributes.emplace_back("variability", "fixed"); + var.scalar_attributes.emplace_back("initial", "calculated"); + + var.real_attributes.emplace_back("quantity", "MassFlowRate"); + var.real_attributes.emplace_back("relativeQuantity", "false"); + var.real_attributes.emplace_back("unit", spawn::units::toString(var.mounittype)); + + var.setValue(0.0, spawn::units::UnitSystem::MO); + result.emplace(i, std::move(var)); + } ++i; } } diff --git a/energyplus_coroutine/variables.hpp b/energyplus_coroutine/variables.hpp index 2cf061378..17ecbcca0 100644 --- a/energyplus_coroutine/variables.hpp +++ b/energyplus_coroutine/variables.hpp @@ -33,6 +33,19 @@ enum class VariableType QSURF_FRONT, TSURF_BACK, QSURF_BACK, + + // Sizing related parameters + QCOOSEN_FLOW, + QCOOLAT_FLOW, + TOUTCOO, + XOUTCOO, + TCOO, + QHEA_FLOW, + TOUTHEA, + XOUTHEA, + MOUTCOO_FLOW, + MOUTHEA_FLOW, + THEA }; using VariableAttribute = std::pair;