diff --git a/.claude/agents/auto-dry-refactor.md b/.claude/agents/auto-dry-refactor.md new file mode 100644 index 00000000000..6f4a758bb28 --- /dev/null +++ b/.claude/agents/auto-dry-refactor.md @@ -0,0 +1,131 @@ +--- +name: auto-dry-refactor +description: Find the largest un-refactored function in src/EnergyPlus, then do up to 4 rounds of DRY refactoring with compile/test/commit cycles. +tools: Read, Edit, Write, Bash, Glob, Grep +model: opus +--- + +# Auto DRY Refactoring Agent + +You find the largest function that hasn't been refactored yet, then do up to 4 rounds of: refactor → build → test → commit. + +## RULES + +- **Do NOT install anything.** lizard, cmake, ctest, git are already installed. +- **Never change behavior.** Purely structural refactoring. +- **Skip rather than break.** 3 retries max per stage, then revert and skip. +- **Always verify.** Never commit without successful compile + tests. +- **Do NOT use `touch` to force recompilation.** +- **Prefer static free functions over lambdas** for extracted helpers (they reduce NLOC and show in stack traces). Lambdas only for ≤10 lines or complex captures. +- **Use what exists.** Grep for existing utilities before writing new helpers. + +## Phase 1: Prepare + +## Step 1: Pick a Function + +Read `tools/dry-refactor-done.txt` (if it exists) — these are already processed. + +Find all functions over 500 NLOC, sorted largest-first. The `-w` flag suppresses per-file noise and only prints warnings. lizard exits with code 1 when warnings exist — this is normal. + +```bash +lizard src/EnergyPlus/ -L 500 -w -t8 --sort nloc 2>&1 || true +``` +Each output line looks like: `:: warning: has NLOC, ...` + +Go through results largest-first. Skip any in the done list. For each candidate, read the function body and look for DRY opportunities (≥2 blocks of ≥10 duplicated lines). Pick the first one with opportunities. + +If no candidates have DRY opportunities, report "No suitable candidates" and stop. + +## Step 2: Refactor Loop (repeat up to 4 times) + +1. Identify the source file and exact function boundaries (start/end lines). +2. Map the source file to its test file: `src/EnergyPlus/Foo.cc` → `tst/EnergyPlus/unit/Foo.unit.cc` +3. Derive a ctest filter substring from the filename for use with `-R "EnergyPlusFixture.*"`. For example, `RefrigeratedCase.cc` → `Refr`. +4. Analyze the function for DRY violations: + - Repeated code blocks (exact or near-exact duplicates) + - Copy-paste patterns with minor variations (e.g., same logic applied to different variables) + - Common setup/teardown sequences that could be extracted into helpers + - Repeated conditional structures with the same shape + - Similar loops that differ only in target variables or array indices +5. Produce a numbered plan of up to **4** discrete refactoring stages, prioritized by largest expected NLOC reduction first. Each stage must be: + - Independently compilable and testable + - A single logical DRY improvement (one refactoring concept per commit) + - Purely structural — never change behavior + - A **meaningful** code reduction (not just removing comments, whitespace, or blank lines) +6. **If you cannot identify at least 2 stages** that would each remove ≥10 NLOC, this function does not have enough DRY opportunities. Report this and stop. + +## Phase 2: Iterative Refactoring Loop + +For each stage in your plan, follow this cycle: + +### Step 1: Apply Changes +Make the refactoring changes (extract helper, deduplicate block, consolidate repeated patterns, etc.). + +### Step 2: Compile + +The build directory is `build-normal` and uses Ninja. Do NOT search for or create other build directories. + +```bash +ninja -C build-normal energyplus_tests 2>&1 | tail -30 +``` +- If compilation fails, read the errors, fix them, and retry. +- Maximum 3 compile attempts per stage. If still failing after 3, skip this stage. + +### Step 3: Test +```bash +ctest --test-dir build-normal -j8 -R "EnergyPlusFixture.*" 2>&1 | tail -30 +``` +- If tests fail, read the output, diagnose the issue, fix, and retry. +- Maximum 3 test attempts per stage. If still failing after 3, revert changes for this stage and skip it. +- Tests must pass for a commit to be made +- Build must succeed for a commit to be made + +### Step 4: Reformat Files Edited + +```bash +clang-format-19 -i +``` + +### Step 5: Verify LOC Improvement +Before committing, verify the stage made a meaningful reduction: +```bash +lizard 2>&1 | grep "" +``` +Compare the NLOC to the value before this stage. Also check `git diff --stat` to confirm net lines removed. +- The stage must show a **net reduction in NLOC** of the target function (not just cosmetic changes). +- If the NLOC did not decrease, or the change only removed comments/whitespace/blank lines, **revert the changes** (`git checkout -- `) and skip this stage. + +### Step 6: Commit +First stage the files: +```bash +git add +``` +Then commit (as a separate command): +```bash +git commit -m "" +``` + +### Step 7: Continue +Move to the next stage (maximum 4 stages total). + +## Key Rules + +- **Prefer static free functions over lambdas.** When extracting a helper, define it as a `static` free function before the target function rather than a lambda inside it. Lambdas are acceptable only for very small helpers (~10 lines or fewer) or when they truly need to capture complex local state that would be unwieldy as parameters. Free functions show up in stack traces, can be tested independently, and — critically — reduce the NLOC of the target function (lizard counts lambda bodies as part of the enclosing function). +- **Use what exists.** Before writing a new helper function, search the codebase for existing utilities, methods, or patterns that already do what you need. Grep for similar logic, check related headers, and reuse existing infrastructure. Only write new code when nothing suitable already exists. +- **Never change behavior.** This is purely structural refactoring. The program must produce identical results before and after each change. +- **One concept per commit.** Each commit should represent a single logical DRY improvement that is easy to review. +- **Skip rather than break.** If stuck after 3 retries on any stage (compile or test), skip that stage and move on. Do not leave the build broken. +- **Always verify.** Never commit without a successful compile and test run. +- **Do NOT install anything.** All required tools (lizard, cmake, ctest, git) are already installed. Never run pip, apt, npm, or any package manager. +- **Do NOT use `touch` to force recompilation.** The build system tracks file modifications correctly. +- **Do NOT set `CCACHE_DISABLE=1` or any other env vars that disable caching.** Always run plain `ninja -C build-normal energyplus_tests` for incremental builds. +- **Do NOT use `sleep` commands.** Never wait/poll — just run the build or test command directly and wait for it to complete. +- **Do NOT run commands in the background.** Run builds and tests as foreground commands so you get the output directly. + +## Final Summary + +After completing all stages (or skipping ones that failed), report: +- Number of stages completed vs. skipped +- What each completed stage did (one line each) +- Approximate NLOC reduction (re-run lizard on the function to measure) +- Any stages that were skipped and why diff --git a/.claude/agents/dry-refactor.md b/.claude/agents/dry-refactor.md new file mode 100644 index 00000000000..da3281a9bea --- /dev/null +++ b/.claude/agents/dry-refactor.md @@ -0,0 +1,104 @@ +--- +name: dry-refactor +description: Analyze a specified function for DRY improvements, then iteratively refactor with compile/test/commit cycles. Expects a filename and/or function name. +tools: Read, Edit, Write, Bash, Glob, Grep +model: opus +--- + +# DRY Refactoring Agent + +You are a refactoring agent for the EnergyPlus codebase. Your job is to analyze a specified function for DRY (Don't Repeat Yourself) violations, and iteratively refactor it with compile/test/commit cycles. + +## Input + +You will be given a **source file** and/or **function name** to refactor. If only a filename is given, refactor the largest function in that file. If only a function name is given, search for it in `src/EnergyPlus/`. + +Use the system-installed `lizard` command to measure the function's NLOC: +``` +lizard 2>&1 | grep "" +``` + +`lizard` is already installed on this system. Do NOT attempt to install it via pip or any other method. If the command fails, stop and report the error. + +## Phase 1: Analysis + +1. Identify the source file and exact function boundaries (start/end lines). +2. Map the source file to its test file: `src/EnergyPlus/Foo.cc` → `tst/EnergyPlus/unit/Foo.unit.cc` +3. Derive a ctest filter substring from the filename for use with `-R "EnergyPlusFixture.*"`. For example, `RefrigeratedCase.cc` → `Refr`. +4. Analyze the function for DRY violations: + - Repeated code blocks (exact or near-exact duplicates) + - Copy-paste patterns with minor variations (e.g., same logic applied to different variables) + - Common setup/teardown sequences that could be extracted into helpers + - Repeated conditional structures with the same shape + - Similar loops that differ only in target variables or array indices +5. Produce a numbered plan of up to **4** discrete refactoring stages, prioritized by largest expected NLOC reduction first. Each stage must be: + - Independently compilable and testable + - A single logical DRY improvement (one refactoring concept per commit) + - Purely structural — never change behavior + - A **meaningful** code reduction (not just removing comments, whitespace, or blank lines) +6. **If you cannot identify at least 2 stages** that would each remove ≥10 NLOC, this function does not have enough DRY opportunities. Report this and stop. + +## Phase 2: Iterative Refactoring Loop + +For each stage in your plan, follow this cycle: + +### Step 1: Apply Changes +Make the refactoring changes (extract helper, deduplicate block, consolidate repeated patterns, etc.). + +### Step 2: Compile + +The build directory is `build-normal` and uses Ninja. Do NOT search for or create other build directories. + +```bash +ninja -C build-normal energyplus_tests -j8 2>&1 | tail -30 +``` +- If compilation fails, read the errors, fix them, and retry. +- Maximum 3 compile attempts per stage. If still failing after 3, skip this stage. + +### Step 3: Test +```bash +cd build-normal && ctest -j8 -R "EnergyPlusFixture.*" 2>&1 | tail -30 +``` +- If tests fail, read the output, diagnose the issue, fix, and retry. +- Maximum 3 test attempts per stage. If still failing after 3, revert changes for this stage and skip it. + +### Step 4: Verify LOC Improvement +Before committing, verify the stage made a meaningful reduction: +```bash +lizard 2>&1 | grep "" +``` +Compare the NLOC to the value before this stage. Also check `git diff --stat` to confirm net lines removed. +- The stage must show a **net reduction in NLOC** of the target function (not just cosmetic changes). +- If the NLOC did not decrease, or the change only removed comments/whitespace/blank lines, **revert the changes** (`git checkout -- `) and skip this stage. + +### Step 5: Commit +First stage the files: +```bash +git add +``` +Then commit (as a separate command): +```bash +git commit -m "" +``` + +### Step 6: Continue +Move to the next stage (maximum 4 stages total). + +## Key Rules + +- **Prefer static free functions over lambdas.** When extracting a helper, define it as a `static` free function before the target function rather than a lambda inside it. Lambdas are acceptable only for very small helpers (~10 lines or fewer) or when they truly need to capture complex local state that would be unwieldy as parameters. Free functions show up in stack traces, can be tested independently, and — critically — reduce the NLOC of the target function (lizard counts lambda bodies as part of the enclosing function). +- **Use what exists.** Before writing a new helper function, search the codebase for existing utilities, methods, or patterns that already do what you need. Grep for similar logic, check related headers, and reuse existing infrastructure. Only write new code when nothing suitable already exists. +- **Never change behavior.** This is purely structural refactoring. The program must produce identical results before and after each change. +- **One concept per commit.** Each commit should represent a single logical DRY improvement that is easy to review. +- **Skip rather than break.** If stuck after 3 retries on any stage (compile or test), skip that stage and move on. Do not leave the build broken. +- **Always verify.** Never commit without a successful compile and test run. +- **Do NOT install anything.** All required tools (lizard, cmake, ctest, git) are already installed. Never run pip, apt, npm, or any package manager. +- **Do NOT use `touch` to force recompilation.** The build system tracks file modifications correctly. + +## Final Summary + +After completing all stages (or skipping ones that failed), report: +- Number of stages completed vs. skipped +- What each completed stage did (one line each) +- Approximate NLOC reduction (re-run lizard on the function to measure) +- Any stages that were skipped and why diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index cb7e26e0db3..f268d6d8120 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -120,6 +120,9 @@ elseif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" O # depending on the level of overflow check selected, the stringop-overflow can also emit false positives # https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wstringop-overflow target_compile_options(project_warnings INTERFACE -Wno-stringop-overflow) + # GCC 15 emits false positives for alloc-size-larger-than in ObjexxFCL's AlignedAllocator + # when aggressive inlining causes the compiler to lose track of size constraints + target_compile_options(project_warnings INTERFACE -Wno-alloc-size-larger-than) # for RelWithDebInfo builds, lets turn OFF NDEBUG, which will re-enable assert statements target_compile_options(project_options INTERFACE $<$:-UNDEBUG>) elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") diff --git a/src/EnergyPlus/AirflowNetwork/src/Solver.cpp b/src/EnergyPlus/AirflowNetwork/src/Solver.cpp index fb0f600ff44..b90421dd519 100644 --- a/src/EnergyPlus/AirflowNetwork/src/Solver.cpp +++ b/src/EnergyPlus/AirflowNetwork/src/Solver.cpp @@ -49,7 +49,9 @@ // C++ Headers #include +#include #include +#include #include #include @@ -150,6 +152,58 @@ namespace AirflowNetwork { { } + // Populate a range of AirflowNetworkCompData entries with the common boilerplate fields. + // Returns the updated offset (j + count) for chaining. + static int populateCompDataRange(Array1D &compData, + std::unordered_map &compnumMap, + int j, + int count, + iComponentTypeNum compType, + std::function const &getName, + iEPlusComponentType ePlusType = iEPlusComponentType::Invalid) + { + for (int i = 1 + j; i <= count + j; ++i) { + int n = i - j; + compData(i).Name = getName(n); + compnumMap[compData(i).Name] = i; + compData(i).CompTypeNum = compType; + compData(i).TypeNum = n; + compData(i).EPlusName = ""; + compData(i).EPlusCompName = ""; + compData(i).EPlusType = ""; + compData(i).CompNum = i; + if (ePlusType != iEPlusComponentType::Invalid) { + compData(i).EPlusTypeNum = ePlusType; + } + } + return j + count; + } + + // Compute the minimum and maximum z-coordinates across all vertices of a surface. + static void getVertexHeightRange(DataSurfaces::SurfaceData const &surf, Real64 &minHeight, Real64 &maxHeight) + { + minHeight = surf.Vertex(1).z; + maxHeight = surf.Vertex(1).z; + for (int j = 2; j <= surf.Sides; ++j) { + minHeight = min(minHeight, surf.Vertex(j).z); + maxHeight = max(maxHeight, surf.Vertex(j).z); + } + } + + // Check that an opening surface is a window, door, glassdoor, or air boundary. + static void checkOpeningSurfaceClass( + EnergyPlusData &state, DataSurfaces::SurfaceData const &surf, std::string_view routineName, std::string const &linkageName, bool &errorsFound) + { + if (!(surf.OriginalClass == DataSurfaces::SurfaceClass::Window || surf.OriginalClass == DataSurfaces::SurfaceClass::GlassDoor || + surf.OriginalClass == DataSurfaces::SurfaceClass::Door || surf.IsAirBoundarySurf)) { + ShowSevereError(state, + EnergyPlus::format(routineName) + + "AirflowNetworkComponent: The opening must be assigned to a window, door, glassdoor or air boundary at " + + linkageName); + errorsFound = true; + } + } + int constexpr NumOfVentCtrTypes(6); // Number of zone level venting control types void Solver::manage_balance(ObjexxFCL::Optional_bool_const FirstHVACIteration, // True when solution technique on first iteration @@ -320,6 +374,67 @@ namespace AirflowNetwork { update(FirstHVACIteration); } + // Helper: look up reference crack conditions from the map, or use defaults. + // Returns true on success, false if the named conditions object was not found. + static bool lookupReferenceConditions(EnergyPlusData &state, + std::string_view RoutineName, + std::string const &CurrentModuleObject, + std::string const &thisObjectName, + nlohmann::json const &fields, + bool conditionsAreDefaulted, + ReferenceConditions const &defaultReferenceConditions, + std::unordered_map &referenceConditions, + Real64 &refT, + Real64 &refP, + Real64 &refW) + { + refT = defaultReferenceConditions.temperature; + refP = defaultReferenceConditions.pressure; + refW = defaultReferenceConditions.humidity_ratio; + if (!conditionsAreDefaulted) { + if (fields.find("reference_crack_conditions") != fields.end()) { + auto refCrackCondName = fields.at("reference_crack_conditions").get(); + auto result = referenceConditions.find(Util::makeUPPER(refCrackCondName)); + if (result == referenceConditions.end()) { + ShowSevereError(state, + EnergyPlus::format("{}: {}: {}. Cannot find reference crack conditions object \"{}\".", + RoutineName, + CurrentModuleObject, + thisObjectName, + refCrackCondName)); + return false; + } else { + refT = result->second.temperature; + refP = result->second.pressure; + refW = result->second.humidity_ratio; + state.dataInputProcessing->inputProcessor->markObjectAsUsed("AirflowNetwork:MultiZone:ReferenceCrackConditions", + result->second.name); + } + } + } + return true; + } + + // Helper: add an element to the lookup table, checking for duplicate names. + // Returns true on success, false if a duplicate was found. + static bool addElementToLookup(EnergyPlusData &state, + std::string_view RoutineName, + std::string const &CurrentModuleObject, + std::string const &elementName, + AirflowElement *element, + std::unordered_map &elements) + { + if (elements.find(elementName) == elements.end()) { + elements[elementName] = element; + return true; + } else { + ShowSevereError( + state, + EnergyPlus::format("{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, elementName)); + return false; + } + } + bool Solver::get_element_input() { // SUBROUTINE INFORMATION: @@ -415,32 +530,20 @@ namespace AirflowNetwork { if (fields.find("air_mass_flow_exponent") != fields.end()) { // not required field, has default value expnt = fields.at("air_mass_flow_exponent").get(); } - Real64 refT = defaultReferenceConditions.temperature; - Real64 refP = defaultReferenceConditions.pressure; - Real64 refW = defaultReferenceConditions.humidity_ratio; - if (!conditionsAreDefaulted) { - if (fields.find("reference_crack_conditions") != fields.end()) { // not required field, *should* have default value - auto refCrackCondName = fields.at("reference_crack_conditions").get(); - auto result = referenceConditions.find(Util::makeUPPER(refCrackCondName)); - - if (result == referenceConditions.end()) { - ShowSevereError(m_state, - EnergyPlus::format("{}: {}: {}. Cannot find reference crack conditions object \"{}\".", - RoutineName, - CurrentModuleObject, - thisObjectName, - refCrackCondName)); - success = false; - } else { - refT = result->second.temperature; - refP = result->second.pressure; - refW = result->second.humidity_ratio; - m_state.dataInputProcessing->inputProcessor->markObjectAsUsed("AirflowNetwork:MultiZone:ReferenceCrackConditions", - result->second.name); - } - } + Real64 refT, refP, refW; + if (!lookupReferenceConditions(m_state, + RoutineName, + CurrentModuleObject, + thisObjectName, + fields, + conditionsAreDefaulted, + defaultReferenceConditions, + referenceConditions, + refT, + refP, + refW)) { + success = false; } - // globalSolverObject.cracks[thisObjectName] = SurfaceCrack(coeff, expnt, refT, refP, refW); MultizoneSurfaceCrackData(i).name = thisObjectName; // Name of surface crack component MultizoneSurfaceCrackData(i).coefficient = coeff; // Air Mass Flow Coefficient MultizoneSurfaceCrackData(i).exponent = expnt; // Air Mass Flow exponent @@ -501,29 +604,19 @@ namespace AirflowNetwork { success = false; } - Real64 refT = defaultReferenceConditions.temperature; - Real64 refP = defaultReferenceConditions.pressure; - Real64 refW = defaultReferenceConditions.humidity_ratio; - if (!conditionsAreDefaulted) { - if (fields.find("reference_crack_conditions") != fields.end()) { // not required field, *should* have default value - auto refCrackCondName = fields.at("reference_crack_conditions").get(); - auto result = referenceConditions.find(Util::makeUPPER(refCrackCondName)); - if (result == referenceConditions.end()) { - ShowSevereError(m_state, - EnergyPlus::format("{}: {}: {}. Cannot find reference crack conditions object \"{}\".", - RoutineName, - CurrentModuleObject, - thisObjectName, - fields.at("reference_crack_conditions").get())); - success = false; - } else { - refT = result->second.temperature; - refP = result->second.pressure; - refW = result->second.humidity_ratio; - m_state.dataInputProcessing->inputProcessor->markObjectAsUsed("AirflowNetwork:MultiZone:ReferenceCrackConditions", - result->second.name); - } - } + Real64 refT, refP, refW; + if (!lookupReferenceConditions(m_state, + RoutineName, + CurrentModuleObject, + thisObjectName, + fields, + conditionsAreDefaulted, + defaultReferenceConditions, + referenceConditions, + refT, + refP, + refW)) { + success = false; } MultizoneCompExhaustFanData(i).name = thisObjectName; // Name of zone exhaust fan component @@ -539,14 +632,7 @@ namespace AirflowNetwork { MultizoneCompExhaustFanData(i).StandardW = refW; // Add the element to the lookup table, check for name overlaps - if (elements.find(thisObjectName) == elements.end()) { - elements[thisObjectName] = &MultizoneCompExhaustFanData(i); // Yet another workaround - } else { - ShowSevereError( - m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, thisObjectName)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, thisObjectName, &MultizoneCompExhaustFanData(i), elements)) { success = false; } @@ -585,29 +671,19 @@ namespace AirflowNetwork { success = false; } - Real64 refT = defaultReferenceConditions.temperature; - Real64 refP = defaultReferenceConditions.pressure; - Real64 refW = defaultReferenceConditions.humidity_ratio; - if (!conditionsAreDefaulted) { - if (fields.find("reference_crack_conditions") != fields.end()) { // not required field, *should* have default value - auto refCrackCondName = fields.at("reference_crack_conditions").get(); - auto result = referenceConditions.find(Util::makeUPPER(refCrackCondName)); - if (result == referenceConditions.end()) { - ShowSevereError(m_state, - EnergyPlus::format("{}: {}: {}. Cannot find reference crack conditions object \"{}\".", - RoutineName, - CurrentModuleObject, - thisObjectName, - refCrackCondName)); - success = false; - } else { - refT = result->second.temperature; - refP = result->second.pressure; - refW = result->second.humidity_ratio; - m_state.dataInputProcessing->inputProcessor->markObjectAsUsed("AirflowNetwork:MultiZone:ReferenceCrackConditions", - result->second.name); - } - } + Real64 refT, refP, refW; + if (!lookupReferenceConditions(m_state, + RoutineName, + CurrentModuleObject, + thisObjectName, + fields, + conditionsAreDefaulted, + defaultReferenceConditions, + referenceConditions, + refT, + refP, + refW)) { + success = false; } DisSysCompOutdoorAirData(i).name = thisObjectName; // Name of zone exhaust fan component @@ -621,14 +697,7 @@ namespace AirflowNetwork { DisSysCompOutdoorAirData(i).StandardW = refW; // Add the element to the lookup table, check for name overlaps - if (elements.find(thisObjectName) == elements.end()) { - elements[thisObjectName] = &DisSysCompOutdoorAirData(i); // Yet another workaround - } else { - ShowSevereError( - m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, thisObjectName)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, thisObjectName, &DisSysCompOutdoorAirData(i), elements)) { success = false; } @@ -664,29 +733,19 @@ namespace AirflowNetwork { success = false; } - Real64 refT = defaultReferenceConditions.temperature; - Real64 refP = defaultReferenceConditions.pressure; - Real64 refW = defaultReferenceConditions.humidity_ratio; - if (!conditionsAreDefaulted) { - if (fields.find("reference_crack_conditions") != fields.end()) { // not required field, *should* have default value - auto refCrackCondName = fields.at("reference_crack_conditions").get(); - auto result = referenceConditions.find(Util::makeUPPER(refCrackCondName)); - if (result == referenceConditions.end()) { - ShowSevereError(m_state, - EnergyPlus::format("{}: {}: {}. Cannot find reference crack conditions object \"{}\".", - RoutineName, - CurrentModuleObject, - thisObjectName, - refCrackCondName)); - success = false; - } else { - refT = result->second.temperature; - refP = result->second.pressure; - refW = result->second.humidity_ratio; - m_state.dataInputProcessing->inputProcessor->markObjectAsUsed("AirflowNetwork:MultiZone:ReferenceCrackConditions", - result->second.name); - } - } + Real64 refT, refP, refW; + if (!lookupReferenceConditions(m_state, + RoutineName, + CurrentModuleObject, + thisObjectName, + fields, + conditionsAreDefaulted, + defaultReferenceConditions, + referenceConditions, + refT, + refP, + refW)) { + success = false; } DisSysCompReliefAirData(i).name = thisObjectName; // Name of zone exhaust fan component @@ -698,14 +757,7 @@ namespace AirflowNetwork { DisSysCompReliefAirData(i).StandardW = refW; // Add the element to the lookup table, check for name overlaps - if (elements.find(thisObjectName) == elements.end()) { - elements[thisObjectName] = &DisSysCompReliefAirData(i); // Yet another workaround - } else { - ShowSevereError( - m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, thisObjectName)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, thisObjectName, &DisSysCompReliefAirData(i), elements)) { success = false; } @@ -982,14 +1034,7 @@ namespace AirflowNetwork { } // Add the element to the lookup table, check for name overlaps - if (elements.find(thisObjectName) == elements.end()) { - elements[thisObjectName] = &MultizoneCompDetOpeningData(i); // Yet another workaround - } else { - ShowSevereError( - m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, thisObjectName)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, thisObjectName, &MultizoneCompDetOpeningData(i), elements)) { success = false; } @@ -1026,14 +1071,7 @@ namespace AirflowNetwork { MultizoneCompSimpleOpeningData(i).DischCoeff = dischargeCoeff; // Discharge coefficient at full opening // Add the element to the lookup table, check for name overlaps - if (elements.find(thisObjectName) == elements.end()) { - elements[thisObjectName] = &MultizoneCompSimpleOpeningData(i); // Yet another workaround - } else { - ShowSevereError( - m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, thisObjectName)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, thisObjectName, &MultizoneCompSimpleOpeningData(i), elements)) { success = false; } @@ -1073,14 +1111,7 @@ namespace AirflowNetwork { MultizoneCompHorOpeningData(i).DischCoeff = dischargeCoeff; // Discharge coefficient at full opening // Add the element to the lookup table, check for name overlaps - if (elements.find(thisObjectName) == elements.end()) { - elements[thisObjectName] = &MultizoneCompHorOpeningData(i); // Yet another workaround - } else { - ShowSevereError( - m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, thisObjectName)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, thisObjectName, &MultizoneCompHorOpeningData(i), elements)) { success = false; } @@ -1126,13 +1157,7 @@ namespace AirflowNetwork { MultizoneSurfaceELAData(i).TestDisCoef = 0.0; // Testing Discharge coefficient // Add the element to the lookup table, check for name overlaps - if (elements.find(thisObjectName) == elements.end()) { - elements[thisObjectName] = &MultizoneSurfaceELAData(i); // Yet another workaround - } else { - ShowSevereError( - m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, thisObjectName)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, thisObjectName, &MultizoneSurfaceELAData(i), elements)) { success = false; } @@ -1218,14 +1243,7 @@ namespace AirflowNetwork { DisSysCompLeakData(i).FlowExpo = expnt; // Air Mass Flow exponent // Add the element to the lookup table, check for name overlaps - if (elements.find(thisObjectName) == elements.end()) { - elements[thisObjectName] = &DisSysCompLeakData(i); // Yet another workaround - } else { - ShowSevereError( - m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, thisObjectName)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, thisObjectName, &DisSysCompLeakData(i), elements)) { success = false; } @@ -1261,14 +1279,7 @@ namespace AirflowNetwork { DisSysCompELRData(i).FlowExpo = expnt; // Air Mass Flow exponent // Add the element to the lookup table, check for name overlaps - if (elements.find(thisObjectName) == elements.end()) { - elements[thisObjectName] = &DisSysCompELRData(i); // Yet another workaround - } else { - ShowSevereError( - m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, thisObjectName)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, thisObjectName, &DisSysCompELRData(i), elements)) { success = false; } @@ -1338,14 +1349,7 @@ namespace AirflowNetwork { DisSysCompDuctData(i).g = DisSysCompDuctData(i).A1; // 1/sqrt(Darcy friction factor) // Add the element to the lookup table, check for name overlaps - if (elements.find(thisObjectName) == elements.end()) { - elements[thisObjectName] = &DisSysCompDuctData(i); // Yet another workaround - } else { - ShowSevereError( - m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, thisObjectName)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, thisObjectName, &DisSysCompDuctData(i), elements)) { success = false; } @@ -1472,13 +1476,7 @@ namespace AirflowNetwork { DisSysCompCVFData(i).OutletNode = outletNode; // Add the element to the lookup table, check for name overlaps - if (elements.find(fan_name) == elements.end()) { - elements[fan_name] = &DisSysCompCVFData(i); // Yet another workaround - } else { - ShowSevereError(m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, fan_name)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, fan_name, &DisSysCompCVFData(i), elements)) { success = false; } @@ -1510,15 +1508,7 @@ namespace AirflowNetwork { DisSysCompCoilData(i).hydraulicDiameter = D; // Air path hydraulic diameter // Add the element to the lookup table, check for name overlaps - if (elements.find(DisSysCompCoilData(i).name) == elements.end()) { - elements[DisSysCompCoilData(i).name] = &DisSysCompCoilData(i); // Yet another workaround - } else { - ShowSevereError(m_state, - EnergyPlus::format("{}: {}: Duplicated airflow element names are found = \"{}\".", - RoutineName, - CurrentModuleObject, - DisSysCompCoilData(i).name)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, DisSysCompCoilData(i).name, &DisSysCompCoilData(i), elements)) { success = false; } @@ -1551,15 +1541,7 @@ namespace AirflowNetwork { DisSysCompHXData(i).CoilParentExists = HVACHXAssistedCoolingCoil::VerifyHeatExchangerParent(m_state, hx_type, hx_name); // Add the element to the lookup table, check for name overlaps - if (elements.find(DisSysCompHXData(i).name) == elements.end()) { - elements[DisSysCompHXData(i).name] = &DisSysCompHXData(i); // Yet another workaround - } else { - ShowSevereError(m_state, - EnergyPlus::format("{}: {}: Duplicated airflow element names are found = \"{}\".", - RoutineName, - CurrentModuleObject, - DisSysCompHXData(i).name)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, DisSysCompHXData(i).name, &DisSysCompHXData(i), elements)) { success = false; } ++i; @@ -1590,15 +1572,8 @@ namespace AirflowNetwork { DisSysCompTermUnitData(i).hydraulicDiameter = D; // Air path hydraulic diameter // Add the element to the lookup table, check for name overlaps - if (elements.find(DisSysCompTermUnitData(i).name) == elements.end()) { - elements[DisSysCompTermUnitData(i).name] = &DisSysCompTermUnitData(i); // Yet another workaround - } else { - ShowSevereError(m_state, - EnergyPlus::format("{}: {}: Duplicated airflow element names are found = \"{}\".", - RoutineName, - CurrentModuleObject, - DisSysCompTermUnitData(i).name)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup( + m_state, RoutineName, CurrentModuleObject, DisSysCompTermUnitData(i).name, &DisSysCompTermUnitData(i), elements)) { success = false; } @@ -1626,14 +1601,7 @@ namespace AirflowNetwork { DisSysCompCPDData(i).DP = dp; // Pressure difference across the component // Add the element to the lookup table, check for name overlaps - if (elements.find(thisObjectName) == elements.end()) { - elements[thisObjectName] = &DisSysCompCPDData(i); // Yet another workaround - } else { - ShowSevereError( - m_state, - EnergyPlus::format( - "{}: {}: Duplicated airflow element names are found = \"{}\".", RoutineName, CurrentModuleObject, thisObjectName)); - // ShowContinueError(state, "A unique component name is required in both objects " + CompName(1) + " and " + CompName(2)); + if (!addElementToLookup(m_state, RoutineName, CurrentModuleObject, thisObjectName, &DisSysCompCPDData(i), elements)) { success = false; } @@ -1707,64 +1675,25 @@ namespace AirflowNetwork { static constexpr std::string_view Format_120("AirflowNetwork Model:Control,{}\n"); // Set the maximum numbers of input fields - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:SimulationControl", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(m_state, "AirflowNetwork:MultiZone:Zone", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:MultiZone:Surface", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:MultiZone:Component:DetailedOpening", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:MultiZone:ExternalNode", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:MultiZone:WindPressureCoefficientArray", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:MultiZone:WindPressureCoefficientValues", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:Distribution:Node", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:Distribution:DuctViewFactors", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:Distribution:Linkage", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:OccupantVentilationControl", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(m_state, "AirflowNetwork:IntraZone:Node", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:IntraZone:Linkage", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:ZoneControl:PressureController", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - m_state, "AirflowNetwork:Distribution:DuctSizing", TotalArgs, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); + for (auto const *objName : {"AirflowNetwork:SimulationControl", + "AirflowNetwork:MultiZone:Zone", + "AirflowNetwork:MultiZone:Surface", + "AirflowNetwork:MultiZone:Component:DetailedOpening", + "AirflowNetwork:MultiZone:ExternalNode", + "AirflowNetwork:MultiZone:WindPressureCoefficientArray", + "AirflowNetwork:MultiZone:WindPressureCoefficientValues", + "AirflowNetwork:Distribution:Node", + "AirflowNetwork:Distribution:DuctViewFactors", + "AirflowNetwork:Distribution:Linkage", + "AirflowNetwork:OccupantVentilationControl", + "AirflowNetwork:IntraZone:Node", + "AirflowNetwork:IntraZone:Linkage", + "AirflowNetwork:ZoneControl:PressureController", + "AirflowNetwork:Distribution:DuctSizing"}) { + m_state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(m_state, objName, TotalArgs, NumAlphas, NumNumbers); + MaxNums = max(MaxNums, NumNumbers); + MaxAlphas = max(MaxAlphas, NumAlphas); + } Alphas.allocate(MaxAlphas); cAlphaFields.allocate(MaxAlphas); @@ -1777,6 +1706,22 @@ namespace AirflowNetwork { auto &Zone(m_state.dataHeatBal->Zone); + // Lambda to reduce boilerplate for repeated getObjectItem calls + auto getItem = [&](int idx) { + m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, + CurrentModuleObject, + idx, + Alphas, + NumAlphas, + Numbers, + NumNumbers, + IOStatus, + lNumericBlanks, + lAlphaBlanks, + cAlphaFields, + cNumericFields); + }; + int NumDuctLossConduction = m_state.dataInputProcessing->inputProcessor->getNumObjectsFound(m_state, "Duct:Loss:Conduction"); int NumDuctLossLeakage = m_state.dataInputProcessing->inputProcessor->getNumObjectsFound(m_state, "Duct:Loss:Leakage"); int NumDuctLossMakeupAir = m_state.dataInputProcessing->inputProcessor->getNumObjectsFound(m_state, "Duct:Loss:MakeupAir"); @@ -1791,18 +1736,7 @@ namespace AirflowNetwork { if (AirflowNetworkNumOfOccuVentCtrls > 0) { OccupantVentilationControl.allocate(AirflowNetworkNumOfOccuVentCtrls); for (int i = 1; i <= AirflowNetworkNumOfOccuVentCtrls; ++i) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - i, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(i); OccupantVentilationControl(i).Name = Alphas(1); // Name of object OccupantVentilationControl(i).MinOpeningTime = Numbers(1); if (OccupantVentilationControl(i).MinOpeningTime < 0.0) { @@ -1993,18 +1927,7 @@ namespace AirflowNetwork { } if (!control_defaulted && !simulation_control.DuctLoss) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - NumAirflowNetwork, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(NumAirflowNetwork); simulation_control.name = Alphas(1); simulation_control.WPCCntr = Alphas(3); @@ -2092,54 +2015,35 @@ namespace AirflowNetwork { } if (multizone_always_simulated) { - if (m_state.dataHeatBal->TotInfiltration > 0) { - ShowWarningError(m_state, EnergyPlus::format("{}{} object, ", RoutineName, CurrentModuleObject)); - ShowContinueError( - m_state, "..Specified " + cAlphaFields(2) + " = \"" + SimAirNetworkKey + "\" and ZoneInfiltration:* objects are present."); - ShowContinueError(m_state, "..ZoneInfiltration objects will not be simulated."); - } - if (m_state.dataHeatBal->TotVentilation > 0) { - ShowWarningError(m_state, EnergyPlus::format("{}{} object, ", RoutineName, CurrentModuleObject)); - ShowContinueError( - m_state, "..Specified " + cAlphaFields(2) + " = \"" + SimAirNetworkKey + "\" and ZoneVentilation:* objects are present."); - ShowContinueError(m_state, "..ZoneVentilation objects will not be simulated."); - } - if (m_state.dataHeatBal->TotMixing > 0) { - ShowWarningError(m_state, EnergyPlus::format("{}{} object, ", RoutineName, CurrentModuleObject)); - ShowContinueError(m_state, - "..Specified " + cAlphaFields(2) + " = \"" + SimAirNetworkKey + "\" and ZoneMixing objects are present."); - ShowContinueError(m_state, "..ZoneMixing objects will not be simulated."); - } - if (m_state.dataHeatBal->TotCrossMixing > 0) { - ShowWarningError(m_state, EnergyPlus::format("{}{} object, ", RoutineName, CurrentModuleObject)); - ShowContinueError(m_state, - "..Specified " + cAlphaFields(2) + " = \"" + SimAirNetworkKey + "\" and ZoneCrossMixing objects are present."); - ShowContinueError(m_state, "..ZoneCrossMixing objects will not be simulated."); - } - if (m_state.dataHeatBal->TotZoneAirBalance > 0) { - ShowWarningError(m_state, EnergyPlus::format("{}{} object, ", RoutineName, CurrentModuleObject)); - ShowContinueError(m_state, - "..Specified " + cAlphaFields(2) + " = \"" + SimAirNetworkKey + - "\" and ZoneAirBalance:OutdoorAir objects are present."); - ShowContinueError(m_state, "..ZoneAirBalance:OutdoorAir objects will not be simulated."); - } - if (m_state.dataInputProcessing->inputProcessor->getNumObjectsFound(m_state, "ZoneEarthtube") > 0) { - ShowWarningError(m_state, EnergyPlus::format("{}{} object, ", RoutineName, CurrentModuleObject)); - ShowContinueError(m_state, - "..Specified " + cAlphaFields(2) + " = \"" + SimAirNetworkKey + "\" and ZoneEarthtube objects are present."); - ShowContinueError(m_state, "..ZoneEarthtube objects will not be simulated."); - } - if (m_state.dataInputProcessing->inputProcessor->getNumObjectsFound(m_state, "ZoneThermalChimney") > 0) { - ShowWarningError(m_state, EnergyPlus::format("{}{} object, ", RoutineName, CurrentModuleObject)); - ShowContinueError( - m_state, "..Specified " + cAlphaFields(2) + " = \"" + SimAirNetworkKey + "\" and ZoneThermalChimney objects are present."); - ShowContinueError(m_state, "..ZoneThermalChimney objects will not be simulated."); - } - if (m_state.dataInputProcessing->inputProcessor->getNumObjectsFound(m_state, "ZoneCoolTower:Shower") > 0) { - ShowWarningError(m_state, EnergyPlus::format("{}{} object, ", RoutineName, CurrentModuleObject)); - ShowContinueError( - m_state, "..Specified " + cAlphaFields(2) + " = \"" + SimAirNetworkKey + "\" and ZoneCoolTower:Shower objects are present."); - ShowContinueError(m_state, "..ZoneCoolTower:Shower objects will not be simulated."); + // Warn about zone-level objects that will not be simulated when multizone is active + struct OverriddenObject + { + int count; + char const *presentMsg; + char const *disabledMsg; + }; + std::array overriddenObjects = {{ + {m_state.dataHeatBal->TotInfiltration, "ZoneInfiltration:*", "ZoneInfiltration"}, + {m_state.dataHeatBal->TotVentilation, "ZoneVentilation:*", "ZoneVentilation"}, + {m_state.dataHeatBal->TotMixing, "ZoneMixing", "ZoneMixing"}, + {m_state.dataHeatBal->TotCrossMixing, "ZoneCrossMixing", "ZoneCrossMixing"}, + {m_state.dataHeatBal->TotZoneAirBalance, "ZoneAirBalance:OutdoorAir", "ZoneAirBalance:OutdoorAir"}, + {m_state.dataInputProcessing->inputProcessor->getNumObjectsFound(m_state, "ZoneEarthtube"), "ZoneEarthtube", "ZoneEarthtube"}, + {m_state.dataInputProcessing->inputProcessor->getNumObjectsFound(m_state, "ZoneThermalChimney"), + "ZoneThermalChimney", + "ZoneThermalChimney"}, + {m_state.dataInputProcessing->inputProcessor->getNumObjectsFound(m_state, "ZoneCoolTower:Shower"), + "ZoneCoolTower:Shower", + "ZoneCoolTower:Shower"}, + }}; + for (auto const &obj : overriddenObjects) { + if (obj.count > 0) { + ShowWarningError(m_state, EnergyPlus::format("{}{} object, ", RoutineName, CurrentModuleObject)); + ShowContinueError(m_state, + "..Specified " + cAlphaFields(2) + " = \"" + SimAirNetworkKey + "\" and " + obj.presentMsg + + " objects are present."); + ShowContinueError(m_state, ".." + std::string(obj.disabledMsg) + " objects will not be simulated."); + } } } @@ -2298,18 +2202,7 @@ namespace AirflowNetwork { simulation_control.autosize_ducts = false; } if (simulation_control.autosize_ducts && NumDuctSizing == 1) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - NumDuctSizing, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(NumDuctSizing); simulation_control.ductSizing.name = Alphas(1); if (Util::SameString(Alphas(2), Util::makeUPPER("MaximumVelocity"))) { @@ -2354,18 +2247,7 @@ namespace AirflowNetwork { MultizoneZoneData.allocate(AirflowNetworkNumOfZones); AirflowNetworkZoneFlag.dimension(m_state.dataGlobal->NumOfZones, false); // AirflowNetwork zone flag for (int i = 1; i <= AirflowNetworkNumOfZones; ++i) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - i, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(i); ErrorObjectHeader eoh{RoutineName, CurrentModuleObject, Alphas(1)}; @@ -2581,18 +2463,7 @@ namespace AirflowNetwork { MultizoneExternalNodeData.allocate(AirflowNetworkNumOfExtNode); CurrentModuleObject = "AirflowNetwork:MultiZone:ExternalNode"; for (int i = 1; i <= AirflowNetworkNumOfExtNode - AirflowNetworkNumOfOutAirNode; ++i) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - i, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(i); MultizoneExternalNodeData(i).Name = Alphas(1); // Name of external node MultizoneExternalNodeData(i).height = Numbers(1); // Nodal height if (Util::SameString(simulation_control.HeightOption, "ExternalNode") && lNumericBlanks(1)) { @@ -2634,18 +2505,7 @@ namespace AirflowNetwork { CurrentModuleObject = "OutdoorAir:Node"; for (int i = AirflowNetworkNumOfExtNode - AirflowNetworkNumOfOutAirNode + 1; i <= AirflowNetworkNumOfExtNode; ++i) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - i - (AirflowNetworkNumOfExtNode - AirflowNetworkNumOfOutAirNode), - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(i - (AirflowNetworkNumOfExtNode - AirflowNetworkNumOfOutAirNode)); // HACK: Need to verify name is unique between "OutdoorAir:Node" and "AirflowNetwork:MultiZone:ExternalNode" if (NumAlphas > 5 && !lAlphaBlanks(6)) { // Wind pressure curve @@ -2711,18 +2571,7 @@ namespace AirflowNetwork { if (AirflowNetworkNumOfSurfaces > 0) { MultizoneSurfaceData.allocate(AirflowNetworkNumOfSurfaces); for (int i = 1; i <= AirflowNetworkNumOfSurfaces; ++i) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - i, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(i); MultizoneSurfaceData(i).SurfName = Alphas(1); // Name of Associated EnergyPlus surface MultizoneSurfaceData(i).OpeningName = Alphas(2); // Name of crack or opening component, // either simple or detailed large opening, or crack @@ -2985,18 +2834,7 @@ namespace AirflowNetwork { } } } else { - minHeight = min(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(1).z, - m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(2).z); - maxHeight = max(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(1).z, - m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(2).z); - for (j = 3; j <= m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Sides; ++j) { - minHeight = min(minHeight, - min(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(j - 1).z, - m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(j).z)); - maxHeight = max(maxHeight, - max(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(j - 1).z, - m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(j).z)); - } + getVertexHeightRange(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum), minHeight, maxHeight); if (maxHeight > minHeight) { MultizoneSurfaceData(i).Height = maxHeight - minHeight; MultizoneSurfaceData(i).Width = @@ -3012,18 +2850,7 @@ namespace AirflowNetwork { MultizoneSurfaceData(i).Height = m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Area / MultizoneSurfaceData(i).Width; } else { - minHeight = min(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(1).z, - m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(2).z); - maxHeight = max(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(1).z, - m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(2).z); - for (j = 3; j <= m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Sides; ++j) { - minHeight = min(minHeight, - min(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(j - 1).z, - m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(j).z)); - maxHeight = max(maxHeight, - max(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(j - 1).z, - m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).Vertex(j).z)); - } + getVertexHeightRange(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum), minHeight, maxHeight); if (maxHeight > minHeight) { MultizoneSurfaceData(i).Height = maxHeight - minHeight; MultizoneSurfaceData(i).Width = @@ -3107,14 +2934,14 @@ namespace AirflowNetwork { ErrorsFound = true; } - found = false; - for (j = 1; j <= AirflowNetworkNumOfZones; ++j) { - if (MultizoneZoneData(j).ZoneNum == m_state.dataSurface->Surface(n).Zone) { - found = true; + j = 0; + for (int jz = 1; jz <= AirflowNetworkNumOfZones; ++jz) { + if (MultizoneZoneData(jz).ZoneNum == m_state.dataSurface->Surface(n).Zone) { + j = jz; break; } } - if (found) { + if (j != 0) { MultizoneSurfaceData(i).NodeNums[1] = j; } else { ShowSevereError(m_state, @@ -3131,14 +2958,14 @@ namespace AirflowNetwork { if (Util::SameString(simulation_control.WPCCntr, "SurfaceAverageCalculation")) { n = m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).ExtBoundCond; if (n >= 1) { // exterior boundary condition is a surface - found = false; - for (j = 1; j <= AirflowNetworkNumOfZones; ++j) { - if (MultizoneZoneData(j).ZoneNum == m_state.dataSurface->Surface(n).Zone) { - found = true; + j = 0; + for (int jz = 1; jz <= AirflowNetworkNumOfZones; ++jz) { + if (MultizoneZoneData(jz).ZoneNum == m_state.dataSurface->Surface(n).Zone) { + j = jz; break; } } - if (found) { + if (j != 0) { MultizoneSurfaceData(i).NodeNums[1] = j; } else { ShowSevereError(m_state, EnergyPlus::format(RoutineName) + CurrentModuleObject + " = " + MultizoneSurfaceData(i).SurfName); @@ -3186,21 +3013,16 @@ namespace AirflowNetwork { // Validate adjacent temperature and Enthalpy control for an interior surface only for (int i = 1; i <= AirflowNetworkNumOfSurfaces; ++i) { - if (MultizoneSurfaceData(i).VentSurfCtrNum == VentControlType::AdjTemp) { - if (!(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).ExtBoundCond >= 1)) { - ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + CurrentModuleObject + " object, " + cAlphaFields(1) + " = " + - MultizoneSurfaceData(i).SurfName); - ShowContinueError(m_state, "..AdjacentTemperature venting control must be defined for an interzone surface."); - ErrorsFound = true; - } - } - if (MultizoneSurfaceData(i).VentSurfCtrNum == VentControlType::AdjEnth) { + auto const ventCtrl = MultizoneSurfaceData(i).VentSurfCtrNum; + if (ventCtrl == VentControlType::AdjTemp || ventCtrl == VentControlType::AdjEnth) { if (!(m_state.dataSurface->Surface(MultizoneSurfaceData(i).SurfNum).ExtBoundCond >= 1)) { ShowSevereError(m_state, EnergyPlus::format(RoutineName) + CurrentModuleObject + " object, " + cAlphaFields(1) + " = " + MultizoneSurfaceData(i).SurfName); - ShowContinueError(m_state, "..AdjacentEnthalpy venting control must be defined for an interzone surface."); + ShowContinueError(m_state, + ventCtrl == VentControlType::AdjTemp + ? "..AdjacentTemperature venting control must be defined for an interzone surface." + : "..AdjacentEnthalpy venting control must be defined for an interzone surface."); ErrorsFound = true; } } @@ -3474,31 +3296,18 @@ namespace AirflowNetwork { } } - // Assign external node height - if (Util::SameString(simulation_control.WPCCntr, "SurfaceAverageCalculation") || - Util::SameString(simulation_control.HeightOption, "OpeningHeight")) { - for (int i = 1; i <= AirflowNetworkNumOfExtNode; ++i) { - for (int j = 1; j <= AirflowNetworkNumOfSurfaces; ++j) { - if (m_state.dataSurface->Surface(MultizoneSurfaceData(j).SurfNum).ExtBoundCond == ExternalEnvironment || - (m_state.dataSurface->Surface(MultizoneSurfaceData(j).SurfNum).ExtBoundCond == OtherSideCoefNoCalcExt && - m_state.dataSurface->Surface(MultizoneSurfaceData(j).SurfNum).ExtWind)) { - if (Util::SameString(MultizoneSurfaceData(j).ExternalNodeName, MultizoneExternalNodeData(i).Name)) { - MultizoneExternalNodeData(i).height = m_state.dataSurface->Surface(MultizoneSurfaceData(j).SurfNum).Centroid.z; - break; - } - } - } - } - } - - // Assign external node azimuth, should consider combining this with the above to avoid the repeated search + // Assign external node height and azimuth in a single pass over the surface list + bool const assignHeight = Util::SameString(simulation_control.WPCCntr, "SurfaceAverageCalculation") || + Util::SameString(simulation_control.HeightOption, "OpeningHeight"); for (int i = 1; i <= AirflowNetworkNumOfExtNode; ++i) { for (int j = 1; j <= AirflowNetworkNumOfSurfaces; ++j) { - if (m_state.dataSurface->Surface(MultizoneSurfaceData(j).SurfNum).ExtBoundCond == ExternalEnvironment || - (m_state.dataSurface->Surface(MultizoneSurfaceData(j).SurfNum).ExtBoundCond == OtherSideCoefNoCalcExt && - m_state.dataSurface->Surface(MultizoneSurfaceData(j).SurfNum).ExtWind)) { + auto const &surf = m_state.dataSurface->Surface(MultizoneSurfaceData(j).SurfNum); + if (surf.ExtBoundCond == ExternalEnvironment || (surf.ExtBoundCond == OtherSideCoefNoCalcExt && surf.ExtWind)) { if (Util::SameString(MultizoneSurfaceData(j).ExternalNodeName, MultizoneExternalNodeData(i).Name)) { - MultizoneExternalNodeData(i).azimuth = m_state.dataSurface->Surface(MultizoneSurfaceData(j).SurfNum).Azimuth; + if (assignHeight) { + MultizoneExternalNodeData(i).height = surf.Centroid.z; + } + MultizoneExternalNodeData(i).azimuth = surf.Azimuth; break; } } @@ -3676,18 +3485,7 @@ namespace AirflowNetwork { if (IntraZoneNumOfNodes > 0) { IntraZoneNodeData.allocate(IntraZoneNumOfNodes); for (int i = 1; i <= IntraZoneNumOfNodes; ++i) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - i, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(i); IntraZoneNodeData(i).Name = Alphas(1); // Name of node IntraZoneNodeData(i).RAFNNodeName = Alphas(2); // Name of RoomAir node IntraZoneNodeData(i).Height = Numbers(1); // Nodal height @@ -3755,18 +3553,7 @@ namespace AirflowNetwork { IntraZoneLinkageData.allocate(IntraZoneNumOfLinks); UniqueAirflowNetworkSurfaceName.reserve(IntraZoneNumOfLinks); for (int i = 1; i <= IntraZoneNumOfLinks; ++i) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - i, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(i); IntraZoneLinkageData(i).Name = Alphas(1); // Name of linkage IntraZoneLinkageData(i).NodeNames[0] = Alphas(2); IntraZoneLinkageData(i).NodeHeights[0] = 0.0; @@ -3961,7 +3748,7 @@ namespace AirflowNetwork { if (m_state.dataGlobal->DisplayExtraWarnings) { ShowWarningError(m_state, EnergyPlus::format(RoutineName) + CurrentModuleObject + "='" + IntraZoneLinkageData(link).Name + - " is reomoved from the list due to the surface connection from Intrazone to Interzone."); + " is removed from the list due to the surface connection from Intrazone to Interzone."); } for (int j = link; j <= IntraZoneNumOfLinks - 1; ++j) { IntraZoneLinkageData(j) = IntraZoneLinkageData(j + 1); @@ -3987,18 +3774,7 @@ namespace AirflowNetwork { if (DisSysNumOfNodes > 0) { DisSysNodeData.allocate(DisSysNumOfNodes); for (int i = 1; i <= DisSysNumOfNodes; ++i) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - i, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(i); DisSysNodeData(i).Name = Alphas(1); // Name of node DisSysNodeData(i).EPlusName = Alphas(2); // Name of associated EnergyPlus node DisSysNodeData(i).EPlusType = Alphas(3); // Name of associated EnergyPlus type @@ -4054,18 +3830,7 @@ namespace AirflowNetwork { if (DisSysNumOfDuctViewFactors > 0) { AirflowNetworkLinkageViewFactorData.allocate(DisSysNumOfDuctViewFactors); for (int i = 1; i <= DisSysNumOfDuctViewFactors; ++i) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - i, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(i); auto &this_VF_object(AirflowNetworkLinkageViewFactorData(i)); @@ -4166,18 +3931,7 @@ namespace AirflowNetwork { if (NumOfPressureControllers > 0) { PressureControllerData.allocate(NumOfPressureControllers); for (int i = 1; i <= NumOfPressureControllers; ++i) { - m_state.dataInputProcessing->inputProcessor->getObjectItem(m_state, - CurrentModuleObject, - i, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(i); ErrorObjectHeader eoh{RoutineName, CurrentModuleObject, Alphas(1)}; @@ -4216,31 +3970,19 @@ namespace AirflowNetwork { } } - if (PressureControllerData(i).ControlTypeSet == PressureCtrlExhaust) { - // This is not great - bool is_EXF{false}; - auto afe = elements.find(Alphas(4)); - if (afe != elements.end()) { - is_EXF = afe->second->type() == ComponentType::EXF; - } - if (!is_EXF) { - ShowSevereError(m_state, EnergyPlus::format(RoutineName) + CurrentModuleObject + " object, an invalid name is given:"); - ShowContinueError(m_state, ".. invalid " + cAlphaFields(4) + " = \"" + Alphas(4) + "\"."); - ErrorsFound = true; - } + // Validate that the control object name refers to the correct component type + // (EXF for Exhaust, REL for Relief). This is not great but works for now. + ComponentType requiredCompType = + (PressureControllerData(i).ControlTypeSet == PressureCtrlExhaust) ? ComponentType::EXF : ComponentType::REL; + bool compTypeValid{false}; + auto afe_ctrl = elements.find(Alphas(4)); + if (afe_ctrl != elements.end()) { + compTypeValid = afe_ctrl->second->type() == requiredCompType; } - if (PressureControllerData(i).ControlTypeSet == PressureCtrlRelief) { - // This is not great - bool is_REL{false}; - auto afe = elements.find(Alphas(4)); - if (afe != elements.end()) { - is_REL = afe->second->type() == ComponentType::REL; - } - if (!is_REL) { - ShowSevereError(m_state, EnergyPlus::format(RoutineName) + CurrentModuleObject + " object, an invalid name is given:"); - ShowContinueError(m_state, ".. invalid " + cAlphaFields(4) + " = \"" + Alphas(4) + "\"."); - ErrorsFound = true; - } + if (!compTypeValid) { + ShowSevereError(m_state, EnergyPlus::format(RoutineName) + CurrentModuleObject + " object, an invalid name is given:"); + ShowContinueError(m_state, ".. invalid " + cAlphaFields(4) + " = \"" + Alphas(4) + "\"."); + ErrorsFound = true; } if (lAlphaBlanks(5)) { @@ -4369,11 +4111,7 @@ namespace AirflowNetwork { } if (Util::SameString(DisSysNodeData(i - NumOfNodesMultiZone).EPlusType, "OutdoorAir:NodeList") || Util::SameString(DisSysNodeData(i - NumOfNodesMultiZone).EPlusType, "OutdoorAir:Node")) { - if (j > 1 && OAMixerExist) { - AirflowNetworkNodeData(i).EPlusTypeNum = iEPlusNodeType::EXT; - AirflowNetworkNodeData(i).ExtNodeNum = AirflowNetworkNumOfExtNode + 1; - AirflowNetworkNodeData(i).NodeTypeNum = 1; - } else if (j > 0 && !OAMixerExist) { + if ((j > 1 && OAMixerExist) || (j > 0 && !OAMixerExist)) { AirflowNetworkNodeData(i).EPlusTypeNum = iEPlusNodeType::EXT; AirflowNetworkNodeData(i).ExtNodeNum = AirflowNetworkNumOfExtNode + 1; AirflowNetworkNodeData(i).NodeTypeNum = 1; @@ -4410,273 +4148,92 @@ namespace AirflowNetwork { AirflowNetworkNumOfSFR; AirflowNetworkCompData.allocate(AirflowNetworkNumOfComps); - for (int i = 1; i <= AirflowNetworkNumOfDetOpenings; ++i) { // Detailed opening component - AirflowNetworkCompData(i).Name = MultizoneCompDetOpeningData(i).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::DOP; - AirflowNetworkCompData(i).TypeNum = i; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - int j = AirflowNetworkNumOfDetOpenings; - for (int i = 1 + j; i <= AirflowNetworkNumOfSimOpenings + j; ++i) { // Simple opening component - n = i - j; - AirflowNetworkCompData(i).Name = MultizoneCompSimpleOpeningData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::SOP; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - j += AirflowNetworkNumOfSimOpenings; - for (int i = 1 + j; i <= AirflowNetworkNumOfSurCracks + j; ++i) { // Surface crack component - n = i - j; - AirflowNetworkCompData(i).Name = MultizoneSurfaceCrackData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::SCR; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - j += AirflowNetworkNumOfSurCracks; - for (int i = 1 + j; i <= AirflowNetworkNumOfSurELA + j; ++i) { // Surface crack component - n = i - j; - AirflowNetworkCompData(i).Name = MultizoneSurfaceELAData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::SEL; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - j += AirflowNetworkNumOfSurELA; - for (int i = 1 + j; i <= AirflowNetworkNumOfExhFan + j; ++i) { // Zone exhaust fan component - n = i - j; - AirflowNetworkCompData(i).Name = MultizoneCompExhaustFanData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::EXF; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - j += AirflowNetworkNumOfExhFan; - for (int i = 1 + j; i <= AirflowNetworkNumOfHorOpenings + j; ++i) { // Distribution system crack component - n = i - j; - AirflowNetworkCompData(i).Name = MultizoneCompHorOpeningData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::HOP; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - j += AirflowNetworkNumOfHorOpenings; - for (int i = 1 + j; i <= DisSysNumOfLeaks + j; ++i) { // Distribution system crack component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompLeakData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::PLR; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - j += DisSysNumOfLeaks; - for (int i = 1 + j; i <= DisSysNumOfELRs + j; ++i) { // Distribution system effective leakage ratio component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompELRData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::ELR; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - j += DisSysNumOfELRs; - for (int i = 1 + j; i <= DisSysNumOfDucts + j; ++i) { // Distribution system effective leakage ratio component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompDuctData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::DWC; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - j += DisSysNumOfDucts; - for (int i = 1 + j; i <= DisSysNumOfDampers + j; ++i) { // Distribution system effective leakage ratio component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompDamperData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::DMP; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - j += DisSysNumOfDampers; - for (int i = 1 + j; i <= DisSysNumOfCVFs + j; ++i) { // Distribution system constant volume fan component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompCVFData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::CVF; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - AirflowNetworkCompData(i).EPlusTypeNum = iEPlusComponentType::FAN; - } - - j += DisSysNumOfCVFs; - for (int i = 1 + j; i <= DisSysNumOfDetFans + j; ++i) { // Distribution system fan component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompDetFanData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::FAN; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - AirflowNetworkCompData(i).EPlusTypeNum = iEPlusComponentType::FAN; - } - - j += DisSysNumOfDetFans; - for (int i = 1 + j; i <= DisSysNumOfCPDs + j; ++i) { // Distribution system constant pressure drop component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompCPDData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::CPD; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - j += DisSysNumOfCPDs; - for (int i = 1 + j; i <= DisSysNumOfCoils + j; ++i) { // Distribution system coil component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompCoilData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::COI; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - AirflowNetworkCompData(i).EPlusTypeNum = iEPlusComponentType::COI; - } - - j += DisSysNumOfCoils; - for (int i = 1 + j; i <= DisSysNumOfTermUnits + j; ++i) { // Terminal unit component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompTermUnitData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::TMU; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - AirflowNetworkCompData(i).EPlusTypeNum = iEPlusComponentType::RHT; - } - - j += DisSysNumOfTermUnits; - for (int i = 1 + j; i <= DisSysNumOfHXs + j; ++i) { // Distribution system heat exchanger component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompHXData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::HEX; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - AirflowNetworkCompData(i).EPlusTypeNum = iEPlusComponentType::HEX; - } - - j += DisSysNumOfHXs; - for (int i = 1 + j; i <= NumOfOAFans + j; ++i) { // OA fan component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompOutdoorAirData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::OAF; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - - j += NumOfOAFans; - for (int i = 1 + j; i <= NumOfReliefFans + j; ++i) { // OA fan component - n = i - j; - AirflowNetworkCompData(i).Name = DisSysCompReliefAirData(n).name; - compnum[AirflowNetworkCompData(i).Name] = i; - AirflowNetworkCompData(i).CompTypeNum = iComponentTypeNum::REL; - AirflowNetworkCompData(i).TypeNum = n; - AirflowNetworkCompData(i).EPlusName = ""; - AirflowNetworkCompData(i).EPlusCompName = ""; - AirflowNetworkCompData(i).EPlusType = ""; - AirflowNetworkCompData(i).CompNum = i; - } - + int j = 0; + j = populateCompDataRange(AirflowNetworkCompData, compnum, j, AirflowNetworkNumOfDetOpenings, iComponentTypeNum::DOP, [&](int n) { + return MultizoneCompDetOpeningData(n).name; + }); + j = populateCompDataRange(AirflowNetworkCompData, compnum, j, AirflowNetworkNumOfSimOpenings, iComponentTypeNum::SOP, [&](int n) { + return MultizoneCompSimpleOpeningData(n).name; + }); + j = populateCompDataRange(AirflowNetworkCompData, compnum, j, AirflowNetworkNumOfSurCracks, iComponentTypeNum::SCR, [&](int n) { + return MultizoneSurfaceCrackData(n).name; + }); + j = populateCompDataRange(AirflowNetworkCompData, compnum, j, AirflowNetworkNumOfSurELA, iComponentTypeNum::SEL, [&](int n) { + return MultizoneSurfaceELAData(n).name; + }); + j = populateCompDataRange(AirflowNetworkCompData, compnum, j, AirflowNetworkNumOfExhFan, iComponentTypeNum::EXF, [&](int n) { + return MultizoneCompExhaustFanData(n).name; + }); + j = populateCompDataRange(AirflowNetworkCompData, compnum, j, AirflowNetworkNumOfHorOpenings, iComponentTypeNum::HOP, [&](int n) { + return MultizoneCompHorOpeningData(n).name; + }); + j = populateCompDataRange( + AirflowNetworkCompData, compnum, j, DisSysNumOfLeaks, iComponentTypeNum::PLR, [&](int n) { return DisSysCompLeakData(n).name; }); + j = populateCompDataRange( + AirflowNetworkCompData, compnum, j, DisSysNumOfELRs, iComponentTypeNum::ELR, [&](int n) { return DisSysCompELRData(n).name; }); + j = populateCompDataRange( + AirflowNetworkCompData, compnum, j, DisSysNumOfDucts, iComponentTypeNum::DWC, [&](int n) { return DisSysCompDuctData(n).name; }); + j = populateCompDataRange( + AirflowNetworkCompData, compnum, j, DisSysNumOfDampers, iComponentTypeNum::DMP, [&](int n) { return DisSysCompDamperData(n).name; }); + j = populateCompDataRange( + AirflowNetworkCompData, + compnum, + j, + DisSysNumOfCVFs, + iComponentTypeNum::CVF, + [&](int n) { return DisSysCompCVFData(n).name; }, + iEPlusComponentType::FAN); + j = populateCompDataRange( + AirflowNetworkCompData, + compnum, + j, + DisSysNumOfDetFans, + iComponentTypeNum::FAN, + [&](int n) { return DisSysCompDetFanData(n).name; }, + iEPlusComponentType::FAN); + j = populateCompDataRange( + AirflowNetworkCompData, compnum, j, DisSysNumOfCPDs, iComponentTypeNum::CPD, [&](int n) { return DisSysCompCPDData(n).name; }); + j = populateCompDataRange( + AirflowNetworkCompData, + compnum, + j, + DisSysNumOfCoils, + iComponentTypeNum::COI, + [&](int n) { return DisSysCompCoilData(n).name; }, + iEPlusComponentType::COI); + j = populateCompDataRange( + AirflowNetworkCompData, + compnum, + j, + DisSysNumOfTermUnits, + iComponentTypeNum::TMU, + [&](int n) { return DisSysCompTermUnitData(n).name; }, + iEPlusComponentType::RHT); + j = populateCompDataRange( + AirflowNetworkCompData, + compnum, + j, + DisSysNumOfHXs, + iComponentTypeNum::HEX, + [&](int n) { return DisSysCompHXData(n).name; }, + iEPlusComponentType::HEX); + j = populateCompDataRange( + AirflowNetworkCompData, compnum, j, NumOfOAFans, iComponentTypeNum::OAF, [&](int n) { return DisSysCompOutdoorAirData(n).name; }); + j = populateCompDataRange( + AirflowNetworkCompData, compnum, j, NumOfReliefFans, iComponentTypeNum::REL, [&](int n) { return DisSysCompReliefAirData(n).name; }); // This is also a bit of a hack to keep things working, this needs to be removed ASAP - j += NumOfReliefFans; - int ii = 1 + j; - int type_i = 1; - for (auto const &el : SpecifiedMassFlowData) { - AirflowNetworkCompData(ii).Name = el.name; - compnum[el.name] = ii; - AirflowNetworkCompData(ii).CompTypeNum = iComponentTypeNum::SMF; - AirflowNetworkCompData(ii).TypeNum = type_i; - AirflowNetworkCompData(ii).EPlusName = ""; - AirflowNetworkCompData(ii).EPlusCompName = ""; - AirflowNetworkCompData(ii).EPlusType = ""; - AirflowNetworkCompData(ii).CompNum = ii; - ++ii; - ++type_i; - } - - type_i = 1; - for (auto const &el : SpecifiedVolumeFlowData) { - AirflowNetworkCompData(ii).Name = el.name; - compnum[el.name] = ii; - AirflowNetworkCompData(ii).CompTypeNum = iComponentTypeNum::SVF; - AirflowNetworkCompData(ii).TypeNum = type_i; - AirflowNetworkCompData(ii).EPlusName = ""; - AirflowNetworkCompData(ii).EPlusCompName = ""; - AirflowNetworkCompData(ii).EPlusType = ""; - AirflowNetworkCompData(ii).CompNum = ii; - ++ii; - ++type_i; - } + j = populateCompDataRange( + AirflowNetworkCompData, compnum, j, static_cast(SpecifiedMassFlowData.size()), iComponentTypeNum::SMF, [&](int n) { + auto it = SpecifiedMassFlowData.begin(); + std::advance(it, n - 1); + return it->name; + }); + j = populateCompDataRange( + AirflowNetworkCompData, compnum, j, static_cast(SpecifiedVolumeFlowData.size()), iComponentTypeNum::SVF, [&](int n) { + auto it = SpecifiedVolumeFlowData.begin(); + std::advance(it, n - 1); + return it->name; + }); // Assign linkage data @@ -4748,14 +4305,7 @@ namespace AirflowNetwork { ShowContinueError(m_state, "10 deg of being horizontal. Airflows through large horizontal openings are poorly"); ShowContinueError(m_state, "modeled in the AirflowNetwork model resulting in only one-way airflow."); } - if (!(surf.OriginalClass == SurfaceClass::Window || surf.OriginalClass == SurfaceClass::GlassDoor || - surf.OriginalClass == SurfaceClass::Door || surf.IsAirBoundarySurf)) { - ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + - "AirflowNetworkComponent: The opening must be assigned to a window, door, glassdoor or air boundary at " + - AirflowNetworkLinkageData(count).Name); - ErrorsFound = true; - } + checkOpeningSurfaceClass(m_state, surf, RoutineName, AirflowNetworkLinkageData(count).Name, ErrorsFound); if (surf.OriginalClass == SurfaceClass::Door || surf.OriginalClass == SurfaceClass::GlassDoor) { if (MultizoneCompDetOpeningData(AirflowNetworkCompData(compnum).TypeNum).LVOType == 2) { @@ -4778,15 +4328,7 @@ namespace AirflowNetwork { ShowContinueError(m_state, "AirflowNetwork:Multizone:Component:SimpleOpening = " + AirflowNetworkCompData(compnum).Name); ErrorsFound = true; } - - if (!(surf.OriginalClass == SurfaceClass::Window || surf.OriginalClass == SurfaceClass::GlassDoor || - surf.OriginalClass == SurfaceClass::Door || surf.IsAirBoundarySurf)) { - ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + - "AirflowNetworkComponent: The opening must be assigned to a window, door, glassdoor or air boundary at " + - AirflowNetworkLinkageData(count).Name); - ErrorsFound = true; - } + checkOpeningSurfaceClass(m_state, surf, RoutineName, AirflowNetworkLinkageData(count).Name, ErrorsFound); } break; case ComponentType::HOP: { // if (AirflowNetworkCompData(i).CompTypeNum == iComponentTypeNum::HOP) { @@ -4827,14 +4369,7 @@ namespace AirflowNetwork { "with the object of AirflowNetwork:Multizone:Component:HorizontalOpening = " + AirflowNetworkCompData(compnum).Name); } - if (!(surf.OriginalClass == SurfaceClass::Window || surf.OriginalClass == SurfaceClass::GlassDoor || - surf.OriginalClass == SurfaceClass::Door || surf.IsAirBoundarySurf)) { - ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + - "AirflowNetworkComponent: The opening must be assigned to a window, door, glassdoor or air boundary at " + - AirflowNetworkLinkageData(count).Name); - ErrorsFound = true; - } + checkOpeningSurfaceClass(m_state, surf, RoutineName, AirflowNetworkLinkageData(count).Name, ErrorsFound); } break; default: // Nothing to do here @@ -5056,7 +4591,6 @@ namespace AirflowNetwork { } } } else { - if (distribution_simulated) { ShowSevereError(m_state, EnergyPlus::format(RoutineName) + "An " + CurrentModuleObject + " object is required but not found."); ErrorsFound = true; @@ -5155,47 +4689,29 @@ namespace AirflowNetwork { // } // Node and component validation - for (count = 1; count <= AirflowNetworkNumOfLinks; ++count) { - NodeFound = false; - for (int i = 1; i <= AirflowNetworkNumOfNodes; ++i) { - if (i == AirflowNetworkLinkageData(count).NodeNums[0]) { - NodeFound = true; - break; - } - } - if (!NodeFound) { - if (count <= AirflowNetworkNumOfSurfaces) { + // Helper: check that a linkage node number (nodeIdx=0 or 1) resolves to a valid node, + // emitting the appropriate diagnostic if not. The MULTIZONE:SURFACE error always reports + // NodeNames[0] regardless of which endpoint is checked (preserving original behavior). + auto checkLinkageNodeFound = [&](int linkCount, int nodeIdx) { + int nodeNum = AirflowNetworkLinkageData(linkCount).NodeNums[nodeIdx]; + bool isFound = (nodeNum >= 1 && nodeNum <= AirflowNetworkNumOfNodes); + if (!isFound) { + if (linkCount <= AirflowNetworkNumOfSurfaces) { ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + AirflowNetworkLinkageData(count).NodeNames[0] + - " in AIRFLOWNETWORK:MULTIZONE:SURFACE = " + AirflowNetworkLinkageData(count).Name + " is not found"); + EnergyPlus::format(RoutineName) + AirflowNetworkLinkageData(linkCount).NodeNames[0] + + " in AIRFLOWNETWORK:MULTIZONE:SURFACE = " + AirflowNetworkLinkageData(linkCount).Name + " is not found"); } else { ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + AirflowNetworkLinkageData(count).NodeNames[0] + - " in AIRFLOWNETWORK:DISTRIBUTION:LINKAGE = " + AirflowNetworkLinkageData(count).Name + - " is not found in AIRFLOWNETWORK:DISTRIBUTION:NODE objects."); - } - ErrorsFound = true; - } - NodeFound = false; - for (int i = 1; i <= AirflowNetworkNumOfNodes; ++i) { - if (i == AirflowNetworkLinkageData(count).NodeNums[1]) { - NodeFound = true; - break; - } - } - if (!NodeFound) { - if (count <= AirflowNetworkNumOfSurfaces) { - ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + AirflowNetworkLinkageData(count).NodeNames[0] + - " in AIRFLOWNETWORK:MULTIZONE:SURFACE = " + AirflowNetworkLinkageData(count).Name + " is not found"); - } else { - ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + AirflowNetworkLinkageData(count).NodeNames[1] + - " in AIRFLOWNETWORK:DISTRIBUTION:LINKAGE = " + AirflowNetworkLinkageData(count).Name + + EnergyPlus::format(RoutineName) + AirflowNetworkLinkageData(linkCount).NodeNames[nodeIdx] + + " in AIRFLOWNETWORK:DISTRIBUTION:LINKAGE = " + AirflowNetworkLinkageData(linkCount).Name + " is not found in AIRFLOWNETWORK:DISTRIBUTION:NODE objects."); } ErrorsFound = true; } + }; + for (count = 1; count <= AirflowNetworkNumOfLinks; ++count) { + checkLinkageNodeFound(count, 0); + checkLinkageNodeFound(count, 1); bool CompFound = false; for (int i = 1; i <= AirflowNetworkNumOfComps; ++i) { if (i == AirflowNetworkLinkageData(count).CompNum) { @@ -5313,24 +4829,17 @@ namespace AirflowNetwork { } } - if (DisSysCompHXData(i).CoilParentExists && count != 2) { + int const expectedCount = DisSysCompHXData(i).CoilParentExists ? 2 : 1; + if (count != expectedCount) { ShowSevereError(m_state, EnergyPlus::format(RoutineName) + "The inputs of component name field as a heat exchanger in " "AIRFLOWNETWORK:DISTRIBUTION:LINKAGE is not correct"); ShowContinueError(m_state, "The entered name of heat exchanger is " + DisSysCompHXData(i).name + " in AirflowNetwork:Distribution:Component:HeatExchanger objects"); - ShowContinueError(m_state, EnergyPlus::format("The correct appearance number is 2. The entered appearance number is {}", count)); - ErrorsFound = true; - } - if ((!DisSysCompHXData(i).CoilParentExists) && count != 1) { - ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + "The inputs of component name field as a heat exchanger in " - "AIRFLOWNETWORK:DISTRIBUTION:LINKAGE is not correct"); - ShowContinueError(m_state, - "The entered name of heat exchanger is " + DisSysCompHXData(i).name + - " in AirflowNetwork:Distribution:Component:HeatExchanger objects"); - ShowContinueError(m_state, EnergyPlus::format("The correct appearance number is 1. The entered appearance number is {}", count)); + ShowContinueError( + m_state, + EnergyPlus::format("The correct appearance number is {}. The entered appearance number is {}", expectedCount, count)); ErrorsFound = true; } } @@ -5338,57 +4847,32 @@ namespace AirflowNetwork { // Check node assignments using AirflowNetwork:Distribution:Component:OutdoorAirFlow or // AirflowNetwork:Distribution:Component:ReliefAirFlow + auto checkOANodeType = [&](int nodeNum, std::string_view requiredType, std::string_view position, std::string_view typeWord) { + if (!Util::SameString(DisSysNodeData(nodeNum - NumOfNodesMultiZone).EPlusType, std::string(requiredType))) { + ShowSevereError(m_state, + EnergyPlus::format(RoutineName) + + "AirflowNetwork:Distribution:Linkage: When the component type is " + "AirflowNetwork:Distribution:Component:OutdoorAirFlow at " + + AirflowNetworkNodeData(nodeNum).Name + ","); + ShowContinueError(m_state, + "the component " + std::string(typeWord) + " in the " + std::string(position) + " node should be " + + std::string(requiredType) + " at " + AirflowNetworkNodeData(nodeNum).Name); + ErrorsFound = true; + } + }; for (count = AirflowNetworkNumOfSurfaces + 1; count <= AirflowNetworkNumOfLinks; ++count) { int i = AirflowNetworkLinkageData(count).CompNum; j = AirflowNetworkLinkageData(count).NodeNums[0]; k = AirflowNetworkLinkageData(count).NodeNums[1]; if (AirflowNetworkCompData(i).CompTypeNum == iComponentTypeNum::OAF) { - if (!Util::SameString(DisSysNodeData(j - NumOfNodesMultiZone).EPlusType, "OAMixerOutdoorAirStreamNode")) { - ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + - "AirflowNetwork:Distribution:Linkage: When the component type is " - "AirflowNetwork:Distribution:Component:OutdoorAirFlow at " + - AirflowNetworkNodeData(j).Name + ","); - ShowContinueError( - m_state, "the component type in the first node should be OAMixerOutdoorAirStreamNode at " + AirflowNetworkNodeData(j).Name); - ErrorsFound = true; - } - if (!Util::SameString(DisSysNodeData(k - NumOfNodesMultiZone).EPlusType, "AirLoopHVAC:OutdoorAirSystem")) { - ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + - "AirflowNetwork:Distribution:Linkage: When the component type is " - "AirflowNetwork:Distribution:Component:OutdoorAirFlow at " + - AirflowNetworkNodeData(k).Name + ","); - ShowContinueError(m_state, - "the component object type in the second node should be AirLoopHVAC:OutdoorAirSystem at " + - AirflowNetworkNodeData(k).Name); - ErrorsFound = true; - } + checkOANodeType(j, "OAMixerOutdoorAirStreamNode", "first", "type"); + checkOANodeType(k, "AirLoopHVAC:OutdoorAirSystem", "second", "object type"); } if (AirflowNetworkCompData(i).CompTypeNum == iComponentTypeNum::REL) { - if (!Util::SameString(DisSysNodeData(j - NumOfNodesMultiZone).EPlusType, "AirLoopHVAC:OutdoorAirSystem")) { - ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + - "AirflowNetwork:Distribution:Linkage: When the component type is " - "AirflowNetwork:Distribution:Component:OutdoorAirFlow at " + - AirflowNetworkNodeData(j).Name + ","); - ShowContinueError(m_state, - "the component object type in the first node should be AirLoopHVAC:OutdoorAirSystem at " + - AirflowNetworkNodeData(j).Name); - ErrorsFound = true; - } - if (!Util::SameString(DisSysNodeData(k - NumOfNodesMultiZone).EPlusType, "OAMixerOutdoorAirStreamNode")) { - ShowSevereError(m_state, - EnergyPlus::format(RoutineName) + - "AirflowNetwork:Distribution:Linkage: When the component type is " - "AirflowNetwork:Distribution:Component:OutdoorAirFlow at " + - AirflowNetworkNodeData(k).Name + ","); - ShowContinueError( - m_state, "the component type in the second node should be OAMixerOutdoorAirStreamNode at " + AirflowNetworkNodeData(k).Name); - ErrorsFound = true; - } + checkOANodeType(j, "AirLoopHVAC:OutdoorAirSystem", "first", "object type"); + checkOANodeType(k, "OAMixerOutdoorAirStreamNode", "second", "type"); } } diff --git a/src/EnergyPlus/CondenserLoopTowers.cc b/src/EnergyPlus/CondenserLoopTowers.cc index a9ccaae742b..a8e07374b5a 100644 --- a/src/EnergyPlus/CondenserLoopTowers.cc +++ b/src/EnergyPlus/CondenserLoopTowers.cc @@ -184,6 +184,225 @@ namespace CondenserLoopTowers { } } + static constexpr std::string_view routineName = "GetTowerInput"; + + // Helper: parse water inlet/outlet node connections and test component set. + static void parseWaterNodes( + EnergyPlusData &state, CoolingTower &tower, Array1D_string const &AlphArray, Node::ConnectionObjectType connType, bool &ErrorsFound) + { + auto &s_ipsc = state.dataIPShortCut; + tower.WaterInletNodeNum = Node::GetOnlySingleNode(state, + AlphArray(2), + ErrorsFound, + connType, + tower.Name, + Node::FluidType::Water, + Node::ConnectionType::Inlet, + Node::CompFluidStream::Primary, + Node::ObjectIsNotParent); + tower.WaterOutletNodeNum = Node::GetOnlySingleNode(state, + AlphArray(3), + ErrorsFound, + connType, + tower.Name, + Node::FluidType::Water, + Node::ConnectionType::Outlet, + Node::CompFluidStream::Primary, + Node::ObjectIsNotParent); + Node::TestCompSet(state, s_ipsc->cCurrentModuleObject, tower.Name, AlphArray(2), AlphArray(3), "Chilled Water Nodes"); + } + + // Helper: parse design inlet conditions (DB temp, WB temp, approach, range) and derived water temps. + static void parseDesignConditions( + CoolingTower &tower, Array1D const &NumArray, int const dbIdx, int const wbIdx, int const appIdx, int const rangeIdx) + { + tower.DesInletAirDBTemp = NumArray(dbIdx); + if (tower.DesInletAirDBTemp == 0) { + tower.DesInletAirDBTemp = 35.0; + tower.TowerInletCondsAutoSize = true; + } + tower.DesignInletWB = NumArray(wbIdx); + if (tower.DesignInletWB == 0) { + tower.DesignInletWB = 25.6; + tower.TowerInletCondsAutoSize = true; + } + tower.DesignApproach = NumArray(appIdx); + if (tower.DesignApproach == DataSizing::AutoSize || tower.DesignApproach == 0) { + tower.DesignApproach = 3.9; + tower.TowerInletCondsAutoSize = true; + } + tower.DesignRange = NumArray(rangeIdx); + if (tower.DesignRange == DataSizing::AutoSize || tower.DesignRange == 0) { + tower.DesignRange = 5.5; + tower.TowerInletCondsAutoSize = true; + } + tower.DesOutletWaterTemp = tower.DesignInletWB + tower.DesignApproach; + tower.DesInletWaterTemp = tower.DesOutletWaterTemp + tower.DesignRange; + } + + // Helper: parse basin heater power, setpoint temperature, and schedule fields common to all tower types. + static void parseBasinHeaterFields(EnergyPlusData &state, + CoolingTower &tower, + ErrorObjectHeader const &eoh, + Array1D const &NumArray, + int const NumNums, + Array1D_string const &AlphArray, + int const powerIdx, + int const setptIdx, + int const schedAlpIdx, + bool &ErrorsFound) + { + auto &s_ipsc = state.dataIPShortCut; + tower.BasinHeaterPowerFTempDiff = NumArray(powerIdx); + if (NumArray(powerIdx) < 0.0) { + ShowSevereCustom(state, eoh, "Basin heater power as a function of temperature difference must be >= 0"); + ErrorsFound = true; + } + tower.BasinHeaterSetPointTemp = NumArray(setptIdx); + if (tower.BasinHeaterPowerFTempDiff > 0.0) { + if (NumNums < setptIdx) { + tower.BasinHeaterSetPointTemp = 2.0; + } + if (tower.BasinHeaterSetPointTemp < 2.0) { + ShowWarningCustom( + state, eoh, EnergyPlus::format("{} is less than 2 deg C. Freezing could occur.", s_ipsc->cNumericFieldNames(setptIdx))); + } + } + if (!AlphArray(schedAlpIdx).empty()) { + if ((tower.basinHeaterSched = Sched::GetSchedule(state, AlphArray(schedAlpIdx))) == nullptr) { + ShowWarningItemNotFound(state, + eoh, + s_ipsc->cAlphaFieldNames(schedAlpIdx), + AlphArray(schedAlpIdx), + "Basin heater operation will not be modeled and the simulation continues"); + } + } + } + + // Helper: parse evap loss, drift loss, blowdown, and sizing factor fields common to all tower types. + static void parseEvapAndBlowdownFields(EnergyPlusData &state, + CoolingTower &tower, + ErrorObjectHeader const &eoh, + Array1D const &NumArray, + Array1D_string const &AlphArray, + int const evapAlpIdx, + int const evapFactIdx, + int const driftIdx, + int const concIdx, + int const sizIdx, + int const bdModeAlpIdx, + int const bdSchedAlpIdx, + bool &ErrorsFound) + { + constexpr std::array(EvapLoss::Num)> EvapLossNamesUC{"LOSSFACTOR", "SATURATEDEXIT"}; + constexpr std::array(Blowdown::Num)> BlowDownNamesUC = {"CONCENTRATIONRATIO", "SCHEDULEDRATE"}; + auto &s_ipsc = state.dataIPShortCut; + tower.EvapLossMode = static_cast(getEnumValue(EvapLossNamesUC, Util::makeUPPER(AlphArray(evapAlpIdx)))); + tower.UserEvapLossFactor = NumArray(evapFactIdx); + tower.DriftLossFraction = NumArray(driftIdx) / 100.0; + tower.ConcentrationRatio = NumArray(concIdx); + tower.SizFac = NumArray(sizIdx); + if (tower.SizFac <= 0.0) { + tower.SizFac = 1.0; + } + tower.BlowdownMode = static_cast(getEnumValue(BlowDownNamesUC, Util::makeUPPER(AlphArray(bdModeAlpIdx)))); + if (tower.BlowdownMode == Blowdown::Schedule) { + if ((tower.blowdownSched = Sched::GetSchedule(state, AlphArray(bdSchedAlpIdx))) == nullptr) { + ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(bdSchedAlpIdx), AlphArray(bdSchedAlpIdx)); + ErrorsFound = true; + } + } + } + + // Helper: parse multi-cell fields common to all tower types. + static void parseMultiCellFields(EnergyPlusData &state, + CoolingTower &tower, + Array1D const &NumArray, + int const NumNums, + Array1D_string const &AlphArray, + int const cellIdx, + int const minIdx, + int const maxIdx, + int const ctrlAlpIdx) + { + constexpr std::array(CellCtrl::Num)> CellCtrlNamesUC = {"MINIMALCELL", "MAXIMALCELL"}; + auto &s_ipsc = state.dataIPShortCut; + tower.NumCell = NumArray(cellIdx); + if ((NumNums < cellIdx) && (tower.NumCell == 0)) { + tower.NumCell = 1; + } + tower.MinFracFlowRate = NumArray(minIdx); + if ((NumNums < minIdx) && (tower.MinFracFlowRate == 0.0)) { + tower.MinFracFlowRate = 0.33; + } + tower.MaxFracFlowRate = NumArray(maxIdx); + if ((NumNums < maxIdx) && (tower.MaxFracFlowRate == 0.0)) { + tower.MaxFracFlowRate = 2.5; + } + if (!s_ipsc->lAlphaFieldBlanks(ctrlAlpIdx)) { + tower.cellCtrl = static_cast(getEnumValue(CellCtrlNamesUC, Util::makeUPPER(AlphArray(ctrlAlpIdx)))); + } + } + + // Helper: parse water supply tank, outdoor air inlet node, and end-use subcategory fields. + static void parseWaterSupplyAndOAFields(EnergyPlusData &state, + CoolingTower &tower, + Array1D_string const &AlphArray, + int const NumAlphas, + int const waterAlpIdx, + int const oaAlpIdx, + Node::ConnectionObjectType connType, + int const endUseAlpIdx, + bool &ErrorsFound) + { + auto &s_ipsc = state.dataIPShortCut; + if (s_ipsc->lAlphaFieldBlanks(waterAlpIdx) || AlphArray(waterAlpIdx).empty()) { + tower.SuppliedByWaterSystem = false; + } else { + WaterManager::SetupTankDemandComponent(state, + AlphArray(1), + s_ipsc->cCurrentModuleObject, + AlphArray(waterAlpIdx), + ErrorsFound, + tower.WaterTankID, + tower.WaterTankDemandARRID); + tower.SuppliedByWaterSystem = true; + } + if (s_ipsc->lAlphaFieldBlanks(oaAlpIdx)) { + tower.OutdoorAirInletNodeNum = 0; + } else { + tower.OutdoorAirInletNodeNum = Node::GetOnlySingleNode(state, + AlphArray(oaAlpIdx), + ErrorsFound, + connType, + tower.Name, + Node::FluidType::Air, + Node::ConnectionType::OutsideAirReference, + Node::CompFluidStream::Primary, + Node::ObjectIsNotParent); + if (!OutAirNodeManager::CheckOutAirNodeNumber(state, tower.OutdoorAirInletNodeNum)) { + if (connType == Node::ConnectionObjectType::CoolingTowerSingleSpeed) { + ShowSevereCustom(state, + ErrorObjectHeader{routineName, s_ipsc->cCurrentModuleObject, tower.Name}, + EnergyPlus::format("Outdoor Air Inlet Node Name not valid Outdoor Air Node= {}" + "does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.", + AlphArray(oaAlpIdx))); + } else { + ShowSevereItemNotFound(state, + ErrorObjectHeader{routineName, s_ipsc->cCurrentModuleObject, tower.Name}, + s_ipsc->cAlphaFieldNames(oaAlpIdx), + AlphArray(oaAlpIdx)); + } + ErrorsFound = true; + } + } + if (NumAlphas >= endUseAlpIdx) { + tower.EndUseSubcategory = AlphArray(endUseAlpIdx); + } else { + tower.EndUseSubcategory = "General"; + } + } + void GetTowerInput(EnergyPlusData &state) { @@ -202,8 +421,6 @@ namespace CondenserLoopTowers { // METHODOLOGY EMPLOYED: // Uses "Get" routines to read in the data. - static constexpr std::string_view routineName = "GetTowerInput"; - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: int TowerNum; // Tower number, reference counter for towers data array int NumVSCoolToolsModelCoeffs = 0; // Number of CoolTools VS cooling tower coefficient objects @@ -223,10 +440,7 @@ namespace CondenserLoopTowers { std::unordered_map UniqueSimpleTowerNames; - constexpr std::array(EvapLoss::Num)> EvapLossNamesUC{"LOSSFACTOR", "SATURATEDEXIT"}; constexpr std::array(PIM::Num)> PIMNamesUC{"NOMINALCAPACITY", "UFACTORTIMESAREAANDDESIGNWATERFLOWRATE"}; - constexpr std::array(Blowdown::Num)> BlowDownNamesUC = {"CONCENTRATIONRATIO", "SCHEDULEDRATE"}; - constexpr std::array(CellCtrl::Num)> CellCtrlNamesUC = {"MINIMALCELL", "MAXIMALCELL"}; auto const &s_ip = state.dataInputProcessing->inputProcessor; auto &s_ipsc = state.dataIPShortCut; @@ -285,25 +499,7 @@ namespace CondenserLoopTowers { tower.Name = AlphArray(1); tower.TowerType = DataPlant::PlantEquipmentType::CoolingTower_SingleSpd; tower.TowerMassFlowRateMultiplier = 2.5; - tower.WaterInletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(2), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerSingleSpeed, - tower.Name, - Node::FluidType::Water, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - tower.WaterOutletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(3), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerSingleSpeed, - tower.Name, - Node::FluidType::Water, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - Node::TestCompSet(state, s_ipsc->cCurrentModuleObject, tower.Name, AlphArray(2), AlphArray(3), "Chilled Water Nodes"); + parseWaterNodes(state, tower, AlphArray, Node::ConnectionObjectType::CoolingTowerSingleSpeed, ErrorsFound); tower.DesignWaterFlowRate = NumArray(1); if (tower.DesignWaterFlowRate == DataSizing::AutoSize) { tower.DesignWaterFlowRateWasAutoSized = true; @@ -350,109 +546,11 @@ namespace CondenserLoopTowers { // Since Performance Input Method has been omitted then assume it to be UA and DESIGN WATER FLOW RATE tower.PerformanceInputMethod_Num = PIM::UFactor; } - // cooling tower design inlet conditions - tower.DesInletAirDBTemp = NumArray(13); - if (tower.DesInletAirDBTemp == 0) { - tower.DesInletAirDBTemp = 35.0; - tower.TowerInletCondsAutoSize = true; - } - tower.DesignInletWB = NumArray(14); - if (tower.DesignInletWB == 0) { - tower.DesignInletWB = 25.6; - tower.TowerInletCondsAutoSize = true; - } - tower.DesignApproach = NumArray(15); - if (tower.DesignApproach == DataSizing::AutoSize || tower.DesignApproach == 0) { - tower.DesignApproach = 3.9; - tower.TowerInletCondsAutoSize = true; - } - tower.DesignRange = NumArray(16); - if (tower.DesignRange == DataSizing::AutoSize || tower.DesignRange == 0) { - tower.DesignRange = 5.5; - tower.TowerInletCondsAutoSize = true; - } - // set tower design water outlet and inlet temperatures - tower.DesOutletWaterTemp = tower.DesignInletWB + tower.DesignApproach; - tower.DesInletWaterTemp = tower.DesOutletWaterTemp + tower.DesignRange; - // Basin heater power as a function of temperature must be greater than or equal to 0 - tower.BasinHeaterPowerFTempDiff = NumArray(17); - if (NumArray(17) < 0.0) { - ShowSevereCustom(state, eoh, "Basin heater power as a function of temperature difference must be >= 0"); - ErrorsFound = true; - } - - tower.BasinHeaterSetPointTemp = NumArray(18); - - if (tower.BasinHeaterPowerFTempDiff > 0.0) { - if (NumNums < 18) { - tower.BasinHeaterSetPointTemp = 2.0; - } - if (tower.BasinHeaterSetPointTemp < 2.0) { - ShowWarningCustom( - state, eoh, EnergyPlus::format("{} is less than 2 deg C. Freezing could occur.", s_ipsc->cNumericFieldNames(18))); - } - } - - if (!AlphArray(5).empty()) { - if ((tower.basinHeaterSched = Sched::GetSchedule(state, AlphArray(5))) == nullptr) { - ShowWarningItemNotFound(state, - eoh, - s_ipsc->cAlphaFieldNames(5), - AlphArray(5), - "Basin heater operation will not be modeled and the simulation continues"); - } - } - - // begin water use and systems get input - tower.EvapLossMode = static_cast(getEnumValue(EvapLossNamesUC, Util::makeUPPER(AlphArray(6)))); - - tower.UserEvapLossFactor = NumArray(19); // N11 , \field Evaporation Loss Factor - tower.DriftLossFraction = NumArray(20) / 100.0; // N12, \field Drift Loss Percent - tower.ConcentrationRatio = NumArray(21); // N13, \field Blowdown Concentration Ratio - tower.SizFac = NumArray(25); // N17 \field Sizing Factor - if (tower.SizFac <= 0.0) { - tower.SizFac = 1.0; - } - - tower.BlowdownMode = static_cast(getEnumValue(BlowDownNamesUC, Util::makeUPPER(AlphArray(7)))); - if (tower.BlowdownMode == Blowdown::Schedule) { - if ((tower.blowdownSched = Sched::GetSchedule(state, AlphArray(8))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(8), AlphArray(8)); - ErrorsFound = true; - } - } - - if (AlphArray(9).empty()) { - tower.SuppliedByWaterSystem = false; - } else { // water from storage tank - WaterManager::SetupTankDemandComponent( - state, AlphArray(1), s_ipsc->cCurrentModuleObject, AlphArray(9), ErrorsFound, tower.WaterTankID, tower.WaterTankDemandARRID); - tower.SuppliedByWaterSystem = true; - } - - // outdoor air inlet node - - if (s_ipsc->lAlphaFieldBlanks(10)) { - tower.OutdoorAirInletNodeNum = 0; - } else { - tower.OutdoorAirInletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(10), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerSingleSpeed, - tower.Name, - Node::FluidType::Air, - Node::ConnectionType::OutsideAirReference, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - if (!OutAirNodeManager::CheckOutAirNodeNumber(state, tower.OutdoorAirInletNodeNum)) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format("Outdoor Air Inlet Node Name not valid Outdoor Air Node= {}" - "does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.", - AlphArray(10))); - ErrorsFound = true; - } - } + parseDesignConditions(tower, NumArray, 13, 14, 15, 16); + parseBasinHeaterFields(state, tower, eoh, NumArray, NumNums, AlphArray, 17, 18, 5, ErrorsFound); + parseEvapAndBlowdownFields(state, tower, eoh, NumArray, AlphArray, 6, 19, 20, 21, 25, 7, 8, ErrorsFound); + parseWaterSupplyAndOAFields( + state, tower, AlphArray, NumAlphas, 9, 10, Node::ConnectionObjectType::CoolingTowerSingleSpeed, 13, ErrorsFound); // fluid bypass for single speed tower if (s_ipsc->lAlphaFieldBlanks(11) || AlphArray(11).empty()) { @@ -463,27 +561,7 @@ namespace CondenserLoopTowers { ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(11), AlphArray(11), "The default Fan Cycling is used."); } - // added for multi-cell - tower.NumCell = NumArray(22); - if ((NumNums < 22) && (tower.NumCell == 0)) { - // assume Number of Cells not entered and should be defaulted - tower.NumCell = 1; - } - tower.MinFracFlowRate = NumArray(23); - if ((NumNums < 23) && (tower.MinFracFlowRate == 0.0)) { - // assume Cell Minimum Water Flow Rate Fraction not entered and should be defaulted - tower.MinFracFlowRate = 0.33; - } - tower.MaxFracFlowRate = NumArray(24); - if ((NumNums < 24) && (tower.MaxFracFlowRate == 0.0)) { - // assume Cell Maximum Water Flow Rate Fraction not entered and should be defaulted - tower.MaxFracFlowRate = 2.5; - } - - // cell control for single speed tower - if (!s_ipsc->lAlphaFieldBlanks(12)) { - tower.cellCtrl = static_cast(getEnumValue(CellCtrlNamesUC, Util::makeUPPER(AlphArray(12)))); - } + parseMultiCellFields(state, tower, NumArray, NumNums, AlphArray, 22, 23, 24, 12); // High speed air flow rate must be greater than free convection air flow rate. // Can't tell yet if autosized, check later in initialize. @@ -551,11 +629,6 @@ namespace CondenserLoopTowers { ErrorsFound = true; } - if (NumAlphas > 12) { - tower.EndUseSubcategory = AlphArray(13); - } else { - tower.EndUseSubcategory = "General"; - } } // End Single-Speed Tower Loop s_ipsc->cCurrentModuleObject = cCoolingTower_TwoSpeed; @@ -583,25 +656,7 @@ namespace CondenserLoopTowers { tower.Name = AlphArray(1); tower.TowerType = DataPlant::PlantEquipmentType::CoolingTower_TwoSpd; tower.TowerMassFlowRateMultiplier = 2.5; - tower.WaterInletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(2), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerTwoSpeed, - tower.Name, - Node::FluidType::Water, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - tower.WaterOutletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(3), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerTwoSpeed, - tower.Name, - Node::FluidType::Water, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - Node::TestCompSet(state, s_ipsc->cCurrentModuleObject, AlphArray(1), AlphArray(2), AlphArray(3), "Chilled Water Nodes"); + parseWaterNodes(state, tower, AlphArray, Node::ConnectionObjectType::CoolingTowerTwoSpeed, ErrorsFound); if (NumAlphas >= 4) { tower.PerformanceInputMethod_Num = static_cast(getEnumValue(PIMNamesUC, Util::makeUPPER(AlphArray(4)))); @@ -664,124 +719,11 @@ namespace CondenserLoopTowers { tower.TowerFreeConvNomCapWasAutoSized = true; } tower.TowerFreeConvNomCapSizingFactor = NumArray(20); - // cooling tower design inlet conditions - tower.DesInletAirDBTemp = NumArray(21); - if (tower.DesInletAirDBTemp == 0) { - tower.DesInletAirDBTemp = 35.0; - tower.TowerInletCondsAutoSize = true; - } - tower.DesignInletWB = NumArray(22); - if (tower.DesignInletWB == 0) { - tower.DesignInletWB = 25.6; - tower.TowerInletCondsAutoSize = true; - } - tower.DesignApproach = NumArray(23); - if (tower.DesignApproach == DataSizing::AutoSize || tower.DesignApproach == 0) { - tower.DesignApproach = 3.9; - tower.TowerInletCondsAutoSize = true; - } - tower.DesignRange = NumArray(24); - if (tower.DesignRange == DataSizing::AutoSize || tower.DesignRange == 0) { - tower.DesignRange = 5.5; - tower.TowerInletCondsAutoSize = true; - } - // set tower design water outlet and inlet temperatures - tower.DesOutletWaterTemp = tower.DesignInletWB + tower.DesignApproach; - tower.DesInletWaterTemp = tower.DesOutletWaterTemp + tower.DesignRange; - // Basin heater power as a function of temperature must be greater than or equal to 0 - tower.BasinHeaterPowerFTempDiff = NumArray(25); - if (NumArray(25) < 0.0) { - ShowSevereCustom(state, eoh, "Basin heater power as a function of temperature difference must be >= 0"); - ErrorsFound = true; - } - - tower.BasinHeaterSetPointTemp = NumArray(26); - if (tower.BasinHeaterPowerFTempDiff > 0.0) { - if (NumNums < 26) { - tower.BasinHeaterSetPointTemp = 2.0; - } - if (tower.BasinHeaterSetPointTemp < 2.0) { - ShowWarningCustom( - state, eoh, EnergyPlus::format("{} is less than 2 deg C. Freezing could occur.", s_ipsc->cNumericFieldNames(26))); - } - } - - if (!AlphArray(5).empty()) { - if ((tower.basinHeaterSched = Sched::GetSchedule(state, AlphArray(5))) == nullptr) { - ShowWarningItemNotFound(state, - eoh, - s_ipsc->cAlphaFieldNames(5), - AlphArray(5), - "Basin heater operation will not be modeled and the simulation continues"); - } - } - - // begin water use and systems get input - tower.EvapLossMode = static_cast(getEnumValue(EvapLossNamesUC, Util::makeUPPER(AlphArray(6)))); - tower.UserEvapLossFactor = NumArray(27); // N23 , \field Evaporation Loss Factor - tower.DriftLossFraction = NumArray(28) / 100.0; // N24, \field Drift Loss Percent - tower.ConcentrationRatio = NumArray(29); // N17, \field Blowdown Concentration Ratio - tower.SizFac = NumArray(33); // N21 \field Sizing Factor - if (tower.SizFac <= 0.0) { - tower.SizFac = 1.0; - } - - tower.BlowdownMode = static_cast(getEnumValue(BlowDownNamesUC, Util::makeUPPER(AlphArray(7)))); - if (tower.BlowdownMode == Blowdown::Schedule) { - if ((tower.blowdownSched = Sched::GetSchedule(state, AlphArray(8))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(8), AlphArray(8)); - ErrorsFound = true; - } - } - - // added for multi-cell - tower.NumCell = NumArray(30); - if ((NumNums < 30) && (tower.NumCell == 0)) { - // assume Number of Cells not entered and should be defaulted - tower.NumCell = 1; - } - tower.MinFracFlowRate = NumArray(31); - if ((NumNums < 31) && (tower.MinFracFlowRate == 0.0)) { - // assume Cell Minimum Water Flow Rate Fraction not entered and should be defaulted - tower.MinFracFlowRate = 0.33; - } - tower.MaxFracFlowRate = NumArray(32); - if ((NumNums < 32) && (tower.MaxFracFlowRate == 0.0)) { - // assume Cell Maximum Water Flow Rate Fraction not entered and should be defaulted - tower.MaxFracFlowRate = 2.5; - } - - // cell control for two speed tower - if (!s_ipsc->lAlphaFieldBlanks(11)) { - tower.cellCtrl = static_cast(getEnumValue(CellCtrlNamesUC, Util::makeUPPER(AlphArray(11)))); - } - - if (s_ipsc->lAlphaFieldBlanks(9)) { - tower.SuppliedByWaterSystem = false; - } else { // water from storage tank - WaterManager::SetupTankDemandComponent( - state, AlphArray(1), s_ipsc->cCurrentModuleObject, AlphArray(9), ErrorsFound, tower.WaterTankID, tower.WaterTankDemandARRID); - tower.SuppliedByWaterSystem = true; - } - - // outdoor air inlet node - if (s_ipsc->lAlphaFieldBlanks(10)) { - tower.OutdoorAirInletNodeNum = 0; - } else { - tower.OutdoorAirInletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(10), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerTwoSpeed, - tower.Name, - Node::FluidType::Air, - Node::ConnectionType::OutsideAirReference, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - if (!OutAirNodeManager::CheckOutAirNodeNumber(state, tower.OutdoorAirInletNodeNum)) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(10), AlphArray(10)); - ErrorsFound = true; - } - } + parseDesignConditions(tower, NumArray, 21, 22, 23, 24); + parseBasinHeaterFields(state, tower, eoh, NumArray, NumNums, AlphArray, 25, 26, 5, ErrorsFound); + parseEvapAndBlowdownFields(state, tower, eoh, NumArray, AlphArray, 6, 27, 28, 29, 33, 7, 8, ErrorsFound); + parseMultiCellFields(state, tower, NumArray, NumNums, AlphArray, 30, 31, 32, 11); + parseWaterSupplyAndOAFields(state, tower, AlphArray, NumAlphas, 9, 10, Node::ConnectionObjectType::CoolingTowerTwoSpeed, 12, ErrorsFound); // High speed air flow rate must be greater than low speed air flow rate. // Can't tell yet if autosized, check later in initialize. @@ -973,25 +915,7 @@ namespace CondenserLoopTowers { auto &tower = state.dataCondenserLoopTowers->towers(TowerNum); tower.Name = AlphArray(1); tower.TowerType = DataPlant::PlantEquipmentType::CoolingTower_VarSpd; - tower.WaterInletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(2), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerVariableSpeed, - AlphArray(1), - Node::FluidType::Water, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - tower.WaterOutletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(3), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerVariableSpeed, - AlphArray(1), - Node::FluidType::Water, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - Node::TestCompSet(state, s_ipsc->cCurrentModuleObject, AlphArray(1), AlphArray(2), AlphArray(3), "Chilled Water Nodes"); + parseWaterNodes(state, tower, AlphArray, Node::ConnectionObjectType::CoolingTowerVariableSpeed, ErrorsFound); if ((Util::SameString(AlphArray(4), "CoolToolsUserDefined") || Util::SameString(AlphArray(4), "YorkCalcUserDefined")) && s_ipsc->lAlphaFieldBlanks(5)) { @@ -1328,109 +1252,16 @@ namespace CondenserLoopTowers { ErrorsFound = true; } - // Basin heater power as a function of temperature must be greater than or equal to 0 - tower.BasinHeaterPowerFTempDiff = NumArray(9); - if (NumArray(9) < 0.0) { - ShowSevereCustom(state, eoh, "Basin heater power as a function of temperature difference must be >= 0"); - ErrorsFound = true; - } - - tower.BasinHeaterSetPointTemp = NumArray(10); - if (tower.BasinHeaterPowerFTempDiff > 0.0) { - if (NumNums < 10) { - tower.BasinHeaterSetPointTemp = 2.0; - } - if (tower.BasinHeaterSetPointTemp < 2.0) { - ShowWarningCustom( - state, eoh, EnergyPlus::format("{} is less than 2 deg C. Freezing could occur.", s_ipsc->cNumericFieldNames(10))); - } - } + parseBasinHeaterFields(state, tower, eoh, NumArray, NumNums, AlphArray, 9, 10, 7, ErrorsFound); // Performance Input Method for Variable Speed Towers is assigned to be UA AND DESIGN WATER FLOW RATE // for autosizing calculations (see SizeTower) tower.PerformanceInputMethod_Num = PIM::UFactor; - if (!AlphArray(7).empty()) { - if ((tower.basinHeaterSched = Sched::GetSchedule(state, AlphArray(7))) == nullptr) { - ShowWarningItemNotFound(state, - eoh, - s_ipsc->cAlphaFieldNames(7), - AlphArray(7), - "Basin heater operation will not be modeled and the simulation continues."); - } - } - - // begin water use and systems get input - tower.EvapLossMode = static_cast(getEnumValue(EvapLossNamesUC, Util::makeUPPER(AlphArray(8)))); - tower.UserEvapLossFactor = NumArray(11); // N11 , \field Evaporation Loss Factor - tower.DriftLossFraction = NumArray(12) / 100.0; // N12, \field Drift Loss Percent - tower.ConcentrationRatio = NumArray(13); // N13, \field Blowdown Concentration Ratio - tower.SizFac = NumArray(17); // N14 \field Sizing Factor - if (tower.SizFac <= 0.0) { - tower.SizFac = 1.0; - } - - tower.BlowdownMode = static_cast(getEnumValue(BlowDownNamesUC, Util::makeUPPER(AlphArray(9)))); - if (tower.BlowdownMode == Blowdown::Schedule) { - if ((tower.blowdownSched = Sched::GetSchedule(state, AlphArray(10))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(10), AlphArray(10)); - ErrorsFound = true; - } - } - - // added for multi-cell - tower.NumCell = NumArray(14); - if ((NumNums < 14) && (tower.NumCell == 0)) { - // assume Number of Cells not entered and should be defaulted - tower.NumCell = 1; - } - tower.MinFracFlowRate = NumArray(15); - if ((NumNums < 15) && (tower.MinFracFlowRate == 0.0)) { - // assume Cell Minimum Water Flow Rate Fraction not entered and should be defaulted - tower.MinFracFlowRate = 0.33; - } - tower.MaxFracFlowRate = NumArray(16); - if ((NumNums < 16) && (tower.MaxFracFlowRate == 0.0)) { - // assume Cell Maximum Water Flow Rate Fraction not entered and should be defaulted - tower.MaxFracFlowRate = 2.5; - } - - // cell control for variable speed tower - if (!s_ipsc->lAlphaFieldBlanks(13)) { - tower.cellCtrl = static_cast(getEnumValue(CellCtrlNamesUC, Util::makeUPPER(AlphArray(13)))); - } - - if (s_ipsc->lAlphaFieldBlanks(11)) { - tower.SuppliedByWaterSystem = false; - } else { // water from storage tank - WaterManager::SetupTankDemandComponent( - state, AlphArray(1), s_ipsc->cCurrentModuleObject, AlphArray(11), ErrorsFound, tower.WaterTankID, tower.WaterTankDemandARRID); - tower.SuppliedByWaterSystem = true; - } - - // outdoor air inlet node - if (s_ipsc->lAlphaFieldBlanks(12)) { - tower.OutdoorAirInletNodeNum = 0; - } else { - tower.OutdoorAirInletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(12), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerVariableSpeed, - tower.Name, - Node::FluidType::Air, - Node::ConnectionType::OutsideAirReference, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - if (!OutAirNodeManager::CheckOutAirNodeNumber(state, tower.OutdoorAirInletNodeNum)) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(12), AlphArray(12)); - ErrorsFound = true; - } - } - if (NumAlphas > 13) { - tower.EndUseSubcategory = AlphArray(14); - } else { - tower.EndUseSubcategory = "General"; - } + parseEvapAndBlowdownFields(state, tower, eoh, NumArray, AlphArray, 8, 11, 12, 13, 17, 9, 10, ErrorsFound); + parseMultiCellFields(state, tower, NumArray, NumNums, AlphArray, 14, 15, 16, 13); + parseWaterSupplyAndOAFields( + state, tower, AlphArray, NumAlphas, 11, 12, Node::ConnectionObjectType::CoolingTowerVariableSpeed, 14, ErrorsFound); } // End Variable-Speed Tower Loop @@ -1456,25 +1287,7 @@ namespace CondenserLoopTowers { auto &tower = state.dataCondenserLoopTowers->towers(TowerNum); tower.Name = AlphArray(1); tower.TowerType = DataPlant::PlantEquipmentType::CoolingTower_VarSpdMerkel; - tower.WaterInletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(2), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerVariableSpeedMerkel, - AlphArray(1), - Node::FluidType::Water, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - tower.WaterOutletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(3), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerVariableSpeedMerkel, - AlphArray(1), - Node::FluidType::Water, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - Node::TestCompSet(state, s_ipsc->cCurrentModuleObject, AlphArray(1), AlphArray(2), AlphArray(3), "Chilled Water Nodes"); + parseWaterNodes(state, tower, AlphArray, Node::ConnectionObjectType::CoolingTowerVariableSpeedMerkel, ErrorsFound); if (Util::SameString(AlphArray(4), "UFactorTimesAreaAndDesignWaterFlowRate")) { tower.PerformanceInputMethod_Num = PIM::UFactor; @@ -1550,129 +1363,13 @@ namespace CondenserLoopTowers { ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(8), AlphArray(8)); ErrorsFound = true; } - // cooling tower design inlet conditions - tower.DesInletAirDBTemp = NumArray(17); - if (tower.DesInletAirDBTemp == 0) { - tower.DesInletAirDBTemp = 35.0; - tower.TowerInletCondsAutoSize = true; - } - tower.DesignInletWB = NumArray(18); - if (tower.DesignInletWB == 0) { - tower.DesignInletWB = 25.6; - tower.TowerInletCondsAutoSize = true; - } - tower.DesignApproach = NumArray(19); - if (tower.DesignApproach == DataSizing::AutoSize || tower.DesignApproach == 0) { - tower.DesignApproach = 3.9; - tower.TowerInletCondsAutoSize = true; - } - tower.DesignRange = NumArray(20); - if (tower.DesignRange == DataSizing::AutoSize || tower.DesignRange == 0) { - tower.DesignRange = 5.5; - tower.TowerInletCondsAutoSize = true; - } - // set tower design water outlet and inlet temperatures - tower.DesOutletWaterTemp = tower.DesignInletWB + tower.DesignApproach; - tower.DesInletWaterTemp = tower.DesOutletWaterTemp + tower.DesignRange; - // Basin heater power as a function of temperature must be greater than or equal to 0 - tower.BasinHeaterPowerFTempDiff = NumArray(21); - if (NumArray(21) < 0.0) { - ShowSevereCustom(state, eoh, "Basin heater power as a function of temperature difference must be >= 0"); - ErrorsFound = true; - } - - tower.BasinHeaterSetPointTemp = NumArray(22); - if (tower.BasinHeaterPowerFTempDiff > 0.0) { - if (NumNums < 22) { - tower.BasinHeaterSetPointTemp = 2.0; - } - if (tower.BasinHeaterSetPointTemp < 2.0) { - ShowWarningCustom( - state, eoh, EnergyPlus::format("{} is less than 2 deg C. Freezing could occur.", s_ipsc->cNumericFieldNames(22))); - } - } - - if (!AlphArray(9).empty()) { - if ((tower.basinHeaterSched = Sched::GetSchedule(state, AlphArray(9))) == nullptr) { - ShowWarningItemNotFound(state, - eoh, - s_ipsc->cAlphaFieldNames(9), - AlphArray(9), - "Basin heater operation will not be modeled and the simulation continues"); - } - } - - // begin water use and systems get input - tower.EvapLossMode = static_cast(getEnumValue(EvapLossNamesUC, Util::makeUPPER(AlphArray(10)))); - tower.UserEvapLossFactor = NumArray(23); // N23 , \field Evaporation Loss Factor - tower.DriftLossFraction = NumArray(24) / 100.0; // N24, \field Drift Loss Percent - tower.ConcentrationRatio = NumArray(25); // N25, \field Blowdown Concentration Ratio - tower.SizFac = NumArray(29); // N29 \field Sizing Factor - if (tower.SizFac <= 0.0) { - tower.SizFac = 1.0; - } - - tower.BlowdownMode = static_cast(getEnumValue(BlowDownNamesUC, Util::makeUPPER(AlphArray(11)))); - if (tower.BlowdownMode == Blowdown::Schedule) { - if ((tower.blowdownSched = Sched::GetSchedule(state, AlphArray(12))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(12), AlphArray(12)); - ErrorsFound = true; - } - } - - // added for multi-cell - tower.NumCell = NumArray(26); - if ((NumNums < 26) && (tower.NumCell == 0)) { - // assume Number of Cells not entered and should be defaulted - tower.NumCell = 1; - } - tower.MinFracFlowRate = NumArray(27); - if ((NumNums < 27) && (tower.MinFracFlowRate == 0.0)) { - // assume Cell Minimum Water Flow Rate Fraction not entered and should be defaulted - tower.MinFracFlowRate = 0.33; - } - tower.MaxFracFlowRate = NumArray(28); - if ((NumNums < 28) && (tower.MaxFracFlowRate == 0.0)) { - // assume Cell Maximum Water Flow Rate Fraction not entered and should be defaulted - tower.MaxFracFlowRate = 2.5; - } + parseDesignConditions(tower, NumArray, 17, 18, 19, 20); + parseBasinHeaterFields(state, tower, eoh, NumArray, NumNums, AlphArray, 21, 22, 9, ErrorsFound); + parseEvapAndBlowdownFields(state, tower, eoh, NumArray, AlphArray, 10, 23, 24, 25, 29, 11, 12, ErrorsFound); + parseMultiCellFields(state, tower, NumArray, NumNums, AlphArray, 26, 27, 28, 15); tower.TowerMassFlowRateMultiplier = tower.MaxFracFlowRate; - // cell control for variable speed Merkel tower - if (!s_ipsc->lAlphaFieldBlanks(15)) { - tower.cellCtrl = static_cast(getEnumValue(CellCtrlNamesUC, Util::makeUPPER(AlphArray(15)))); - } - - if (s_ipsc->lAlphaFieldBlanks(13)) { - tower.SuppliedByWaterSystem = false; - } else { // water from storage tank - WaterManager::SetupTankDemandComponent( - state, AlphArray(1), s_ipsc->cCurrentModuleObject, AlphArray(13), ErrorsFound, tower.WaterTankID, tower.WaterTankDemandARRID); - tower.SuppliedByWaterSystem = true; - } - - // outdoor air inlet node - if (s_ipsc->lAlphaFieldBlanks(14)) { - tower.OutdoorAirInletNodeNum = 0; - } else { - tower.OutdoorAirInletNodeNum = Node::GetOnlySingleNode(state, - AlphArray(14), - ErrorsFound, - Node::ConnectionObjectType::CoolingTowerVariableSpeedMerkel, - tower.Name, - Node::FluidType::Air, - Node::ConnectionType::OutsideAirReference, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - if (!OutAirNodeManager::CheckOutAirNodeNumber(state, tower.OutdoorAirInletNodeNum)) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(14), AlphArray(14)); - ErrorsFound = true; - } - } - if (NumAlphas > 15) { - tower.EndUseSubcategory = AlphArray(16); - } else { - tower.EndUseSubcategory = "General"; - } + parseWaterSupplyAndOAFields( + state, tower, AlphArray, NumAlphas, 13, 14, Node::ConnectionObjectType::CoolingTowerVariableSpeedMerkel, 16, ErrorsFound); } // end merkel vs tower loop @@ -2270,6 +1967,20 @@ namespace CondenserLoopTowers { this->Name); } + // Helper to report a sizing output for both final and initial reports. + // Combines the repeated pattern of checking PlantFinalSizesOkayToReport and + // PlantFirstSizesOkayToReport into a single call. + static void reportSizerOutputFinalAndInitial( + EnergyPlusData &state, std::string_view towerTypeName, std::string_view towerName, std::string_view label, Real64 value) + { + if (state.dataPlnt->PlantFinalSizesOkayToReport) { + BaseSizer::reportSizerOutput(state, towerTypeName, towerName, label, value); + } + if (state.dataPlnt->PlantFirstSizesOkayToReport) { + BaseSizer::reportSizerOutput(state, towerTypeName, towerName, EnergyPlus::format("Initial {}", label), value); + } + } + void CoolingTower::SizeTower(EnergyPlusData &state) { @@ -2423,20 +2134,11 @@ namespace CondenserLoopTowers { this->DesignWaterFlowRate = tmpDesignWaterFlowRate; } } - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Design Water Flow Rate [m3/s]", this->DesignWaterFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Design Water Flow Rate [m3/s]", - this->DesignWaterFlowRate); - } } else { if (state.dataPlnt->PlantFinalSizesOkayToReport) { ShowSevereError(state, EnergyPlus::format("Autosizing error for cooling tower object = {}", this->Name)); @@ -2450,35 +2152,17 @@ namespace CondenserLoopTowers { this->DesignWaterFlowRate = 5.382e-8 * this->TowerNominalCapacity; tmpDesignWaterFlowRate = this->DesignWaterFlowRate; if (Util::SameString(DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], "CoolingTower:SingleSpeed")) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Design Water Flow Rate based on tower nominal capacity [m3/s]", this->DesignWaterFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Design Water Flow Rate based on tower nominal capacity [m3/s]", - this->DesignWaterFlowRate); - } } else if (Util::SameString(DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], "CoolingTower:TwoSpeed")) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Design Water Flow Rate based on tower high-speed nominal capacity [m3/s]", this->DesignWaterFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Design Water Flow Rate based on tower high-speed nominal capacity [m3/s]", - this->DesignWaterFlowRate); - } } } @@ -2514,35 +2198,17 @@ namespace CondenserLoopTowers { } if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd || this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_VarSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Fan Power at Design Air Flow Rate [W]", this->HighSpeedFanPower); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Fan Power at Design Air Flow Rate [W]", - this->HighSpeedFanPower); - } } else if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Fan Power at High Fan Speed [W]", this->HighSpeedFanPower); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Fan Power at High Fan Speed [W]", - this->HighSpeedFanPower); - } } } @@ -2555,35 +2221,17 @@ namespace CondenserLoopTowers { if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd || this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_VarSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Design Air Flow Rate [m3/s]", this->HighSpeedAirFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Design Air Flow Rate [m3/s]", - this->HighSpeedAirFlowRate); - } } else if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Air Flow Rate at High Fan Speed [m3/s]", this->HighSpeedAirFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Air Flow Rate at High Fan Speed [m3/s]", - this->HighSpeedAirFlowRate); - } } } @@ -2650,35 +2298,17 @@ namespace CondenserLoopTowers { } } if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "U-Factor Times Area Value at Design Air Flow Rate [W/C]", this->HighSpeedTowerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial U-Factor Times Area Value at Design Air Flow Rate [W/C]", - this->HighSpeedTowerUA); - } } else if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "U-Factor Times Area Value at High Fan Speed [W/C]", this->HighSpeedTowerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial U-Factor Times Area Value at High Fan Speed [W/C]", - this->HighSpeedTowerUA); - } } } else { if (this->DesignWaterFlowRate >= HVAC::SmallWaterVolFlow) { @@ -2761,35 +2391,17 @@ namespace CondenserLoopTowers { } } if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "U-Factor Times Area Value at Design Air Flow Rate [W/C]", this->HighSpeedTowerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial U-Factor Times Area Value at Design Air Flow Rate [W/C]", - this->HighSpeedTowerUA); - } } else if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "U-Factor Times Area Value at High Fan Speed [W/C]", this->HighSpeedTowerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial U-Factor Times Area Value at High Fan Speed [W/C]", - this->HighSpeedTowerUA); - } } } } @@ -2832,35 +2444,17 @@ namespace CondenserLoopTowers { } } if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "U-Factor Times Area Value at Design Air Flow Rate [W/C]", this->HighSpeedTowerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial U-Factor Times Area Value at Design Air Flow Rate [W/C]", - this->HighSpeedTowerUA); - } } else if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "U-Factor Times Area Value at High Fan Speed [W/C]", this->HighSpeedTowerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial U-Factor Times Area Value at High Fan Speed [W/C]", - this->HighSpeedTowerUA); - } } } @@ -2869,20 +2463,11 @@ namespace CondenserLoopTowers { if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->LowSpeedAirFlowRate = this->LowSpeedAirFlowRateSizingFactor * this->HighSpeedAirFlowRate; tmpLowSpeedAirFlowRate = this->LowSpeedAirFlowRate; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Low Fan Speed Air Flow Rate [m3/s]", this->LowSpeedAirFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Low Fan Speed Air Flow Rate [m3/s]", - this->LowSpeedAirFlowRate); - } } else { tmpLowSpeedAirFlowRate = this->LowSpeedAirFlowRateSizingFactor * tmpHighSpeedAirFlowRate; } @@ -2891,78 +2476,42 @@ namespace CondenserLoopTowers { if (this->LowSpeedFanPowerWasAutoSized) { if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->LowSpeedFanPower = this->LowSpeedFanPowerSizingFactor * this->HighSpeedFanPower; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Fan Power at Low Fan Speed [W]", this->LowSpeedFanPower); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Fan Power at Low Fan Speed [W]", - this->LowSpeedFanPower); - } } } if (this->LowSpeedTowerUAWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->LowSpeedTowerUA = this->LowSpeedTowerUASizingFactor * this->HighSpeedTowerUA; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "U-Factor Times Area Value at Low Fan Speed [W/K]", this->LowSpeedTowerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial U-Factor Times Area Value at Low Fan Speed [W/K]", - this->LowSpeedTowerUA); - } } if (this->PerformanceInputMethod_Num == PIM::NominalCapacity) { if (this->TowerLowSpeedNomCapWasAutoSized) { if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->TowerLowSpeedNomCap = this->TowerLowSpeedNomCapSizingFactor * this->TowerNominalCapacity; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Low Speed Nominal Capacity [W]", this->TowerLowSpeedNomCap); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Low Speed Nominal Capacity [W]", - this->TowerLowSpeedNomCap); - } } } if (this->TowerFreeConvNomCapWasAutoSized) { if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->TowerFreeConvNomCap = this->TowerFreeConvNomCapSizingFactor * this->TowerNominalCapacity; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Free Convection Nominal Capacity [W]", this->TowerFreeConvNomCap); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Free Convection Nominal Capacity [W]", - this->TowerFreeConvNomCap); - } } } } @@ -3003,60 +2552,33 @@ namespace CondenserLoopTowers { } else { this->LowSpeedTowerUA = 0.0; } - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Low Fan Speed U-Factor Times Area Value [W/K]", this->LowSpeedTowerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Low Fan Speed U-Factor Times Area Value [W/K]", - this->LowSpeedTowerUA); - } } if (this->FreeConvAirFlowRateWasAutoSized) { this->FreeConvAirFlowRate = this->FreeConvAirFlowRateSizingFactor * tmpHighSpeedAirFlowRate; if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->FreeConvAirFlowRate = this->FreeConvAirFlowRateSizingFactor * this->HighSpeedAirFlowRate; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Free Convection Regime Air Flow Rate [m3/s]", this->FreeConvAirFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Free Convection Regime Air Flow Rate [m3/s]", - this->FreeConvAirFlowRate); - } } } if (this->FreeConvTowerUAWasAutoSized) { if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->FreeConvTowerUA = this->FreeConvTowerUASizingFactor * this->HighSpeedTowerUA; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Free Convection U-Factor Times Area Value [W/K]", this->FreeConvTowerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Free Convection U-Factor Times Area Value [W/K]", - this->FreeConvTowerUA); - } } } @@ -3115,20 +2637,11 @@ namespace CondenserLoopTowers { } else { this->FreeConvTowerUA = 0.0; } - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "U-Factor Times Area Value at Free Convection Air Flow Rate [W/C]", this->FreeConvTowerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial U-Factor Times Area Value at Free Convection Air Flow Rate [W/C]", - this->FreeConvTowerUA); - } } // calibrate variable speed tower model based on user input by finding calibration water flow rate ratio that @@ -3208,52 +2721,25 @@ namespace CondenserLoopTowers { this->plantLoc.loop->glycol->getSpecificHeat(state, (this->DesignInletWB + this->DesignApproach + this->DesignRange), RoutineName); this->TowerNominalCapacity = ((rho * tmpDesignWaterFlowRate) * Cp * this->DesignRange); - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Nominal Capacity [W]", this->TowerNominalCapacity); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Nominal Capacity [W]", - this->TowerNominalCapacity); - } this->FreeConvAirFlowRate = this->MinimumVSAirFlowFrac * this->HighSpeedAirFlowRate; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Air Flow Rate in free convection regime [m3/s]", this->FreeConvAirFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Air Flow Rate in free convection regime [m3/s]", - this->FreeConvAirFlowRate); - } this->TowerFreeConvNomCap = this->TowerNominalCapacity * this->FreeConvectionCapacityFraction; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, + reportSizerOutputFinalAndInitial(state, DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], this->Name, "Tower capacity in free convection regime at design conditions [W]", this->TowerFreeConvNomCap); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - DataPlant::PlantEquipTypeNames[static_cast(this->TowerType)], - this->Name, - "Initial Tower capacity in free convection regime at design conditions [W]", - this->TowerFreeConvNomCap); - } } if (state.dataPlnt->PlantFinalSizesOkayToReport) { // create predefined report diff --git a/src/EnergyPlus/CurveManager.cc b/src/EnergyPlus/CurveManager.cc index 9dc869f2e61..dab31d41b84 100644 --- a/src/EnergyPlus/CurveManager.cc +++ b/src/EnergyPlus/CurveManager.cc @@ -659,1555 +659,234 @@ namespace Curve { } } - void GetCurveInputData(EnergyPlusData &state, bool &ErrorsFound) + // Helper: validate input/output unit type alphas for a curve with 1-3 input dimensions. + // inputTypeStartAlpha is the 1-based alpha index where the first input unit type begins (typically 2). + // The output unit type alpha follows the last input unit type alpha. + // For numDims==1: checks X input type at inputTypeStartAlpha, output type at inputTypeStartAlpha+1 + // For numDims==2: checks X,Y input types, output type at inputTypeStartAlpha+2 + // For numDims==3: checks X,Y,Z input types, output type at inputTypeStartAlpha+3 + static void checkCurveUnitTypes(EnergyPlusData &state, + std::string const &CurrentModuleObject, + std::string const &curveName, + int NumAlphas, + Array1D_string const &Alphas, + int numDims, + int inputTypeStartAlpha) { - - // SUBROUTINE INFORMATION: - // AUTHOR Fred Buhl - // DATE WRITTEN May 2000 - // MODIFIED January 2006, Rick Strand, added a curve type (quadratic-linear) - // July 2006, L. Gu, added a curve type (bicubic) - // July 2006, BG added triquadratic. - // April 2008, LL Added Linear Curve; July 2008, restructure for easier renaming - // Feb 2009, R. Raustad - FSEC, added exponent curve - // 22Aug2010 Craig Wray, added new curves for fan component model: - // FanPressureRise, ExponentialSkewNormal, Sigmoid, RectangularHyperbola1, - // RectangularHyperbola2, ExponentialDecay - // Aug. 2014, Rongpeng Zhang, added a new curve type (ChillerPartLoadWithLift) - // Jan. 2017, Jason DeGraw, added WPC input into tables - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // Obtains input data for EnergyPlus equipment performance curves - - // METHODOLOGY EMPLOYED: - // Uses "Get" routines to read in data. - - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - constexpr std::string_view routineName = "GetCurveInputData"; - - Array1D_string Alphas(14); // Alpha items for object - Array1D Numbers(10000); // Numeric items for object - int NumAlphas; // Number of Alphas for each GetObjectItem call - int NumNumbers; // Number of Numbers for each GetObjectItem call - int IOStatus; // Used in GetObjectItem - std::string CurrentModuleObject; // for ease in renaming. - - // Find the number of each type of curve (note: Current Module object not used here, must rename manually) - - int const NumBiQuad = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Biquadratic"); - int const NumCubic = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Cubic"); - int const NumQuartic = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Quartic"); - int const NumQuad = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Quadratic"); - int const NumQLinear = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:QuadLinear"); - int const NumQuintLinear = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:QuintLinear"); - int const NumQuadLinear = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:QuadraticLinear"); - int const NumCubicLinear = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:CubicLinear"); - int const NumLinear = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Linear"); - int const NumBicubic = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Bicubic"); - int const NumTriQuad = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Triquadratic"); - int const NumExponent = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Exponent"); - int const NumTableLookup = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Table:Lookup"); - int const NumFanPressRise = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:FanPressureRise"); - int const NumExpSkewNorm = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:ExponentialSkewNormal"); - int const NumSigmoid = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Sigmoid"); - int const NumRectHyper1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:RectangularHyperbola1"); - int const NumRectHyper2 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:RectangularHyperbola2"); - int const NumExpDecay = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:ExponentialDecay"); - int const NumDoubleExpDecay = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:DoubleExponentialDecay"); - int const NumChillerPartLoadWithLift = - state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:ChillerPartLoadWithLift"); // zrp_Aug2014 - - int const NumWPCValTab = - state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirflowNetwork:MultiZone:WindPressureCoefficientValues"); - - // state.dataCurveManager->NumCurves = NumBiQuad + NumCubic + NumQuad + NumQuadLinear + NumCubicLinear + NumLinear + NumBicubic + NumTriQuad + - // NumExponent + NumQuartic + NumTableLookup + NumFanPressRise + NumExpSkewNorm + NumSigmoid + NumRectHyper1 + NumRectHyper2 + NumExpDecay - // + NumDoubleExpDecay + NumQLinear + NumQuintLinear + NumChillerPartLoadWithLift + NumWPCValTab; - - // Loop over biquadratic curves and load data - CurrentModuleObject = "Curve:Biquadratic"; - for (int CurveIndex = 1; CurveIndex <= NumBiQuad; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - // could add checks for blank numeric fields, and use field names for errors. - thisCurve->curveType = CurveType::BiQuadratic; - thisCurve->numDims = 2; - for (int in = 0; in < 6; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(7); - thisCurve->inputLimits[0].max = Numbers(8); - thisCurve->inputLimits[1].min = Numbers(9); - thisCurve->inputLimits[1].max = Numbers(10); - if (NumNumbers > 10 && !state.dataIPShortCut->lNumericFieldBlanks(11)) { - thisCurve->outputLimits.min = Numbers(11); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 11 && !state.dataIPShortCut->lNumericFieldBlanks(12)) { - thisCurve->outputLimits.max = Numbers(12); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(7) > Numbers(8)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(7), - Numbers(7), - state.dataIPShortCut->cNumericFieldNames(8), - Numbers(8))); - ErrorsFound = true; - } - if (Numbers(9) > Numbers(10)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(9), - Numbers(9), - state.dataIPShortCut->cNumericFieldNames(10), - Numbers(10))); - ErrorsFound = true; - } - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveInputTypeValid(Alphas(3))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 4) { - if (!IsCurveOutputTypeValid(Alphas(4))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } - - // Loop over ChillerPartLoadWithLift curves and load data //zrp_Aug2014 - CurrentModuleObject = "Curve:ChillerPartLoadWithLift"; - for (int CurveIndex = 1; CurveIndex <= NumChillerPartLoadWithLift; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::ChillerPartLoadWithLift; - thisCurve->numDims = 3; - - for (int in = 0; in < 12; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - - thisCurve->inputLimits[0].min = Numbers(13); - thisCurve->inputLimits[0].max = Numbers(14); - if (Numbers(13) > Numbers(14)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(13), - Numbers(13), - state.dataIPShortCut->cNumericFieldNames(14), - Numbers(14))); - ErrorsFound = true; - } - - thisCurve->inputLimits[1].min = Numbers(15); - thisCurve->inputLimits[1].max = Numbers(16); - if (Numbers(15) > Numbers(16)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(15), - Numbers(15), - state.dataIPShortCut->cNumericFieldNames(16), - Numbers(16))); - ErrorsFound = true; - } - - thisCurve->inputLimits[2].min = Numbers(17); - thisCurve->inputLimits[2].max = Numbers(18); - if (Numbers(17) > Numbers(18)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(17), - Numbers(17), - state.dataIPShortCut->cNumericFieldNames(18), - Numbers(18))); - ErrorsFound = true; - } - - if (NumNumbers > 18 && !state.dataIPShortCut->lNumericFieldBlanks(19)) { - thisCurve->outputLimits.min = Numbers(19); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 19 && !state.dataIPShortCut->lNumericFieldBlanks(20)) { - thisCurve->outputLimits.max = Numbers(20); - thisCurve->outputLimits.maxPresent = true; - } - - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveInputTypeValid(Alphas(3))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 4) { - if (!IsCurveInputTypeValid(Alphas(4))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for Z is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 5) { - if (!IsCurveOutputTypeValid(Alphas(5))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } - - // Loop over cubic curves and load data - CurrentModuleObject = "Curve:Cubic"; - for (int CurveIndex = 1; CurveIndex <= NumCubic; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::Cubic; - thisCurve->numDims = 1; - for (int in = 0; in < 4; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(5); - thisCurve->inputLimits[0].max = Numbers(6); - if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) { - thisCurve->outputLimits.min = Numbers(7); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 7 && !state.dataIPShortCut->lNumericFieldBlanks(8)) { - thisCurve->outputLimits.max = Numbers(8); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(5) > Numbers(6)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(5), - Numbers(5), - state.dataIPShortCut->cNumericFieldNames(6), - Numbers(6))); - ErrorsFound = true; - } - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveOutputTypeValid(Alphas(3))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } - - // Loop over quadrinomial curves and load data - CurrentModuleObject = "Curve:Quartic"; - for (int CurveIndex = 1; CurveIndex <= NumQuartic; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::Quartic; - thisCurve->numDims = 1; - for (int in = 0; in < 5; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(6); - thisCurve->inputLimits[0].max = Numbers(7); - if (NumNumbers > 7 && !state.dataIPShortCut->lNumericFieldBlanks(8)) { - thisCurve->outputLimits.min = Numbers(8); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 8 && !state.dataIPShortCut->lNumericFieldBlanks(9)) { - thisCurve->outputLimits.max = Numbers(9); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(6) > Numbers(7)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(6), - Numbers(6), - state.dataIPShortCut->cNumericFieldNames(7), - Numbers(7))); - ErrorsFound = true; - } - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveOutputTypeValid(Alphas(3))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } - - // Loop over quadratic curves and load data - CurrentModuleObject = "Curve:Quadratic"; - for (int CurveIndex = 1; CurveIndex <= NumQuad; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::Quadratic; - thisCurve->numDims = 1; - for (int in = 0; in < 3; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(4); - thisCurve->inputLimits[0].max = Numbers(5); - if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) { - thisCurve->outputLimits.min = Numbers(6); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) { - thisCurve->outputLimits.max = Numbers(7); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(4) > Numbers(5)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(4), - Numbers(4), - state.dataIPShortCut->cNumericFieldNames(5), - Numbers(5))); - ErrorsFound = true; - } - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveOutputTypeValid(Alphas(3))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } - - // Loop over quadratic-linear curves and load data - CurrentModuleObject = "Curve:QuadraticLinear"; - for (int CurveIndex = 1; CurveIndex <= NumQuadLinear; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::QuadraticLinear; - thisCurve->numDims = 2; - for (int in = 0; in < 6; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(7); - thisCurve->inputLimits[0].max = Numbers(8); - thisCurve->inputLimits[1].min = Numbers(9); - thisCurve->inputLimits[1].max = Numbers(10); - if (NumNumbers > 10 && !state.dataIPShortCut->lNumericFieldBlanks(11)) { - thisCurve->outputLimits.min = Numbers(11); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 11 && !state.dataIPShortCut->lNumericFieldBlanks(12)) { - thisCurve->outputLimits.max = Numbers(12); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(7) > Numbers(8)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(7), - Numbers(7), - state.dataIPShortCut->cNumericFieldNames(8), - Numbers(8))); - ErrorsFound = true; - } - if (Numbers(9) > Numbers(10)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(9), - Numbers(9), - state.dataIPShortCut->cNumericFieldNames(10), - Numbers(10))); - ErrorsFound = true; - } - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveInputTypeValid(Alphas(3))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 4) { - if (!IsCurveOutputTypeValid(Alphas(4))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } - - // Loop over cubic-linear curves and load data - CurrentModuleObject = "Curve:CubicLinear"; - for (int CurveIndex = 1; CurveIndex <= NumCubicLinear; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::CubicLinear; - thisCurve->numDims = 2; - for (int in = 0; in < 6; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(7); - thisCurve->inputLimits[0].max = Numbers(8); - thisCurve->inputLimits[1].min = Numbers(9); - thisCurve->inputLimits[1].max = Numbers(10); - if (NumNumbers > 10 && !state.dataIPShortCut->lNumericFieldBlanks(11)) { - thisCurve->outputLimits.min = Numbers(11); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 11 && !state.dataIPShortCut->lNumericFieldBlanks(12)) { - thisCurve->outputLimits.max = Numbers(12); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(7) > Numbers(8)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(7), - Numbers(7), - state.dataIPShortCut->cNumericFieldNames(8), - Numbers(8))); - ErrorsFound = true; - } - if (Numbers(9) > Numbers(10)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(9), - Numbers(9), - state.dataIPShortCut->cNumericFieldNames(10), - Numbers(10))); - ErrorsFound = true; - } - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveInputTypeValid(Alphas(3))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 4) { - if (!IsCurveOutputTypeValid(Alphas(4))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } - - // Loop over linear curves and load data - CurrentModuleObject = "Curve:Linear"; - for (int CurveIndex = 1; CurveIndex <= NumLinear; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::Linear; - thisCurve->numDims = 1; - for (int in = 0; in < 2; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(3); - thisCurve->inputLimits[0].max = Numbers(4); - if (NumNumbers > 4 && !state.dataIPShortCut->lNumericFieldBlanks(5)) { - thisCurve->outputLimits.min = Numbers(5); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) { - thisCurve->outputLimits.max = Numbers(6); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(3) > Numbers(4)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(3), - Numbers(3), - state.dataIPShortCut->cNumericFieldNames(4), - Numbers(4))); - ErrorsFound = true; - } - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveOutputTypeValid(Alphas(3))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } - - // Loop over bicubic curves and load data - CurrentModuleObject = "Curve:Bicubic"; - for (int CurveIndex = 1; CurveIndex <= NumBicubic; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::BiCubic; - thisCurve->numDims = 2; - for (int in = 0; in < 10; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(11); - thisCurve->inputLimits[0].max = Numbers(12); - thisCurve->inputLimits[1].min = Numbers(13); - thisCurve->inputLimits[1].max = Numbers(14); - if (NumNumbers > 14 && !state.dataIPShortCut->lNumericFieldBlanks(15)) { - thisCurve->outputLimits.min = Numbers(15); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 15 && !state.dataIPShortCut->lNumericFieldBlanks(16)) { - thisCurve->outputLimits.max = Numbers(16); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(11) > Numbers(12)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(11), - Numbers(11), - state.dataIPShortCut->cNumericFieldNames(12), - Numbers(12))); - ErrorsFound = true; - } - if (Numbers(13) > Numbers(14)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(13), - Numbers(13), - state.dataIPShortCut->cNumericFieldNames(14), - Numbers(14))); - ErrorsFound = true; - } - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveInputTypeValid(Alphas(3))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 4) { - if (!IsCurveOutputTypeValid(Alphas(4))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } - - // Loop over Triquadratic curves and load data - CurrentModuleObject = "Curve:Triquadratic"; - for (int CurveIndex = 1; CurveIndex <= NumTriQuad; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::TriQuadratic; - thisCurve->numDims = 3; - thisCurve->coeff[0] = Numbers(1); - thisCurve->coeff[1] = Numbers(2); - thisCurve->coeff[2] = Numbers(3); - thisCurve->coeff[3] = Numbers(4); - thisCurve->coeff[4] = Numbers(5); - thisCurve->coeff[5] = Numbers(6); - thisCurve->coeff[6] = Numbers(7); - thisCurve->coeff[7] = Numbers(8); - thisCurve->coeff[8] = Numbers(9); - thisCurve->coeff[9] = Numbers(10); - thisCurve->coeff[10] = Numbers(11); - thisCurve->coeff[11] = Numbers(12); - thisCurve->coeff[12] = Numbers(13); - thisCurve->coeff[13] = Numbers(14); - thisCurve->coeff[14] = Numbers(15); - thisCurve->coeff[15] = Numbers(16); - thisCurve->coeff[16] = Numbers(17); - thisCurve->coeff[17] = Numbers(18); - thisCurve->coeff[18] = Numbers(19); - thisCurve->coeff[19] = Numbers(20); - thisCurve->coeff[20] = Numbers(21); - thisCurve->coeff[21] = Numbers(22); - thisCurve->coeff[22] = Numbers(23); - thisCurve->coeff[23] = Numbers(24); - thisCurve->coeff[24] = Numbers(25); - thisCurve->coeff[25] = Numbers(26); - thisCurve->coeff[26] = Numbers(27); - thisCurve->inputLimits[0].min = Numbers(28); - thisCurve->inputLimits[0].max = Numbers(29); - thisCurve->inputLimits[1].min = Numbers(30); - thisCurve->inputLimits[1].max = Numbers(31); - thisCurve->inputLimits[2].min = Numbers(32); - thisCurve->inputLimits[2].max = Numbers(33); - if (NumNumbers > 33 && !state.dataIPShortCut->lNumericFieldBlanks(34)) { - thisCurve->outputLimits.min = Numbers(34); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 34 && !state.dataIPShortCut->lNumericFieldBlanks(35)) { - thisCurve->outputLimits.max = Numbers(35); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(28) > Numbers(29)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(28), - Numbers(28), - state.dataIPShortCut->cNumericFieldNames(29), - Numbers(29))); - ErrorsFound = true; - } - if (Numbers(30) > Numbers(31)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(30), - Numbers(30), - state.dataIPShortCut->cNumericFieldNames(31), - Numbers(31))); - ErrorsFound = true; - } - if (Numbers(32) > Numbers(33)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(32), - Numbers(32), - state.dataIPShortCut->cNumericFieldNames(33), - Numbers(33))); - ErrorsFound = true; - } - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveInputTypeValid(Alphas(3))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 4) { - if (!IsCurveInputTypeValid(Alphas(4))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for Z is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 5) { - if (!IsCurveOutputTypeValid(Alphas(5))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } - - // Loop over quad linear curves and load data - CurrentModuleObject = "Curve:QuadLinear"; - for (int CurveIndex = 1; CurveIndex <= NumQLinear; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::QuadLinear; - thisCurve->numDims = 4; - for (int in = 0; in < 5; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(6); - thisCurve->inputLimits[0].max = Numbers(7); - thisCurve->inputLimits[1].min = Numbers(8); - thisCurve->inputLimits[1].max = Numbers(9); - thisCurve->inputLimits[2].min = Numbers(10); - thisCurve->inputLimits[2].max = Numbers(11); - thisCurve->inputLimits[3].min = Numbers(12); - thisCurve->inputLimits[3].max = Numbers(13); - - if (NumNumbers > 13 && !state.dataIPShortCut->lNumericFieldBlanks(14)) { - thisCurve->outputLimits.min = Numbers(14); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 14 && !state.dataIPShortCut->lNumericFieldBlanks(15)) { - thisCurve->outputLimits.max = Numbers(15); - thisCurve->outputLimits.maxPresent = true; - } - - constexpr int NumVar = 4; - constexpr std::array VarNames{"w", "x", "y", "z"}; - for (int i = 1; i <= NumVar; ++i) { - int MinIndex = 2 * i + 4; - int MaxIndex = MinIndex + 1; - if (Numbers(MinIndex) > Numbers(MaxIndex)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(MinIndex), - Numbers(MinIndex), - state.dataIPShortCut->cNumericFieldNames(MaxIndex), - Numbers(MaxIndex))); - ErrorsFound = true; - } - int InputTypeIndex = i + 1; - if (NumAlphas >= InputTypeIndex) { - if (!IsCurveInputTypeValid(Alphas(InputTypeIndex))) { - ShowWarningError( - state, - EnergyPlus::format("In {} named {} the Input Unit Type for {} is invalid.", CurrentModuleObject, Alphas(1), VarNames[i])); - } - } - } - if (NumAlphas >= 6) { - if (!IsCurveOutputTypeValid(Alphas(6))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } - - // Loop over quint linear curves and load data - CurrentModuleObject = "Curve:QuintLinear"; - for (int CurveIndex = 1; CurveIndex <= NumQuintLinear; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::QuintLinear; - thisCurve->numDims = 5; - for (int in = 0; in < 6; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(7); - thisCurve->inputLimits[0].max = Numbers(8); - thisCurve->inputLimits[1].min = Numbers(9); - thisCurve->inputLimits[1].max = Numbers(10); - thisCurve->inputLimits[2].min = Numbers(11); - thisCurve->inputLimits[2].max = Numbers(12); - thisCurve->inputLimits[3].min = Numbers(13); - thisCurve->inputLimits[3].max = Numbers(14); - thisCurve->inputLimits[4].min = Numbers(15); - thisCurve->inputLimits[4].max = Numbers(16); - if (NumNumbers > 16 && !state.dataIPShortCut->lNumericFieldBlanks(17)) { - thisCurve->outputLimits.min = Numbers(17); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 17 && !state.dataIPShortCut->lNumericFieldBlanks(18)) { - thisCurve->outputLimits.max = Numbers(18); - thisCurve->outputLimits.maxPresent = true; - } - - constexpr int NumVar = 5; - constexpr std::array VarNames{"v", "w", "x", "y", "z"}; - for (int i = 1; i <= NumVar; ++i) { - int MinIndex = 2 * i + 5; - int MaxIndex = MinIndex + 1; - if (Numbers(MinIndex) > Numbers(MaxIndex)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(MinIndex), - Numbers(MinIndex), - state.dataIPShortCut->cNumericFieldNames(MaxIndex), - Numbers(MaxIndex))); - ErrorsFound = true; - } - int InputTypeIndex = i + 1; - if (NumAlphas >= InputTypeIndex) { - if (!IsCurveInputTypeValid(Alphas(InputTypeIndex))) { - ShowWarningError( - state, - EnergyPlus::format("In {} named {} the Input Unit Type for {} is invalid.", CurrentModuleObject, Alphas(1), VarNames[i])); - } - } - } - if (NumAlphas >= 7) { - if (!IsCurveOutputTypeValid(Alphas(7))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); + constexpr std::array dimLabels = {"X", "Y", "Z"}; + int const dimsToCheck = std::min(numDims, 3); + for (int d = 0; d < dimsToCheck; ++d) { + int alphaIdx = inputTypeStartAlpha + d; + if (NumAlphas >= alphaIdx) { + if (!IsCurveInputTypeValid(Alphas(alphaIdx))) { + ShowWarningError( + state, + EnergyPlus::format("In {} named {} the Input Unit Type for {} is invalid.", CurrentModuleObject, curveName, dimLabels[d])); } } } - - // Loop over Exponent curves and load data - CurrentModuleObject = "Curve:Exponent"; - for (int CurveIndex = 1; CurveIndex <= NumExponent; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::Exponent; - thisCurve->numDims = 1; - for (int in = 0; in < 3; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(4); - thisCurve->inputLimits[0].max = Numbers(5); - - if (Numbers(4) > Numbers(5)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(4), - Numbers(4), - state.dataIPShortCut->cNumericFieldNames(5), - Numbers(5))); - ErrorsFound = true; - } - - if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) { - thisCurve->outputLimits.min = Numbers(6); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) { - thisCurve->outputLimits.max = Numbers(7); - thisCurve->outputLimits.maxPresent = true; - } - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveOutputTypeValid(Alphas(3))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } + int outputAlphaIdx = inputTypeStartAlpha + dimsToCheck; + if (NumAlphas >= outputAlphaIdx) { + if (!IsCurveOutputTypeValid(Alphas(outputAlphaIdx))) { + ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, curveName)); } } + } - // Loop over Fan Pressure Rise curves and load data - CurrentModuleObject = "Curve:FanPressureRise"; - for (int CurveIndex = 1; CurveIndex <= NumFanPressRise; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - Curve *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::FanPressureRise; - thisCurve->numDims = 2; - for (int in = 0; in < 4; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(5); - thisCurve->inputLimits[0].max = Numbers(6); - thisCurve->inputLimits[1].min = Numbers(7); - thisCurve->inputLimits[1].max = Numbers(8); - - if (NumNumbers > 8 && !state.dataIPShortCut->lNumericFieldBlanks(9)) { - thisCurve->outputLimits.min = Numbers(9); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 9 && !state.dataIPShortCut->lNumericFieldBlanks(10)) { - thisCurve->outputLimits.max = Numbers(10); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(5) > Numbers(6)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(5), - Numbers(5), - state.dataIPShortCut->cNumericFieldNames(6), - Numbers(6))); - ErrorsFound = true; - } - if (Numbers(7) > Numbers(8)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(7), - Numbers(7), - state.dataIPShortCut->cNumericFieldNames(8), - Numbers(8))); - ErrorsFound = true; - } - - } // Fan Pressure Rise - - // Loop over Exponential Skew Normal curves and load data - CurrentModuleObject = "Curve:ExponentialSkewNormal"; - for (int CurveIndex = 1; CurveIndex <= NumExpSkewNorm; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::ExponentialSkewNormal; - thisCurve->numDims = 1; - for (int in = 0; in < 4; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(5); - thisCurve->inputLimits[0].max = Numbers(6); - - if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) { - thisCurve->outputLimits.min = Numbers(7); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 7 && !state.dataIPShortCut->lNumericFieldBlanks(8)) { - thisCurve->outputLimits.max = Numbers(8); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(5) > Numbers(6)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(5), - Numbers(5), - state.dataIPShortCut->cNumericFieldNames(6), - Numbers(6))); - ErrorsFound = true; - } - - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveOutputTypeValid(Alphas(3))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } // Exponential Skew Normal - - // Loop over Sigmoid curves and load data - CurrentModuleObject = "Curve:Sigmoid"; - for (int CurveIndex = 1; CurveIndex <= NumSigmoid; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::Sigmoid; - thisCurve->numDims = 1; - for (int in = 0; in < 5; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(6); - thisCurve->inputLimits[0].max = Numbers(7); - - if (NumNumbers > 7 && !state.dataIPShortCut->lNumericFieldBlanks(8)) { - thisCurve->outputLimits.min = Numbers(8); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 8 && !state.dataIPShortCut->lNumericFieldBlanks(9)) { - thisCurve->outputLimits.max = Numbers(9); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(6) > Numbers(7)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(6), - Numbers(6), - state.dataIPShortCut->cNumericFieldNames(7), - Numbers(7))); - ErrorsFound = true; - } - - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveOutputTypeValid(Alphas(3))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } // Sigmoid - - // Loop over Rectangular Hyperbola Type 1 curves and load data - CurrentModuleObject = "Curve:RectangularHyperbola1"; - for (int CurveIndex = 1; CurveIndex <= NumRectHyper1; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::RectangularHyperbola1; - thisCurve->numDims = 1; - for (int in = 0; in < 3; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(4); - thisCurve->inputLimits[0].max = Numbers(5); - - if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) { - thisCurve->outputLimits.min = Numbers(6); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) { - thisCurve->outputLimits.max = Numbers(7); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(4) > Numbers(5)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(4), - Numbers(4), - state.dataIPShortCut->cNumericFieldNames(5), - Numbers(5))); - ErrorsFound = true; - } - - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveOutputTypeValid(Alphas(3))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } // Rectangular Hyperbola Type 1 - - // Loop over Rectangular Hyperbola Type 2 curves and load data - CurrentModuleObject = "Curve:RectangularHyperbola2"; - for (int CurveIndex = 1; CurveIndex <= NumRectHyper2; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } - - auto *thisCurve = AddCurve(state, Alphas(1)); - - thisCurve->curveType = CurveType::RectangularHyperbola2; - thisCurve->numDims = 1; - for (int in = 0; in < 3; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(4); - thisCurve->inputLimits[0].max = Numbers(5); - - if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) { - thisCurve->outputLimits.min = Numbers(6); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) { - thisCurve->outputLimits.max = Numbers(7); - thisCurve->outputLimits.maxPresent = true; - } - - if (Numbers(4) > Numbers(5)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(4), - Numbers(4), - state.dataIPShortCut->cNumericFieldNames(5), - Numbers(5))); - ErrorsFound = true; - } - - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveOutputTypeValid(Alphas(3))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } // Rectangular Hyperbola Type 2 - - // Loop over Exponential Decay curves and load data - CurrentModuleObject = "Curve:ExponentialDecay"; - for (int CurveIndex = 1; CurveIndex <= NumExpDecay; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; + // Helper: read optional output min/max limits from numeric fields. + // minIdx is the 1-based index of the output-min field; maxIdx = minIdx+1 for the output-max field. + static void readOptionalOutputLimits(EnergyPlusData &state, Curve *thisCurve, int NumNumbers, Array1D const &Numbers, int minIdx) + { + int maxIdx = minIdx + 1; + if (NumNumbers > (minIdx - 1) && !state.dataIPShortCut->lNumericFieldBlanks(minIdx)) { + thisCurve->outputLimits.min = Numbers(minIdx); + thisCurve->outputLimits.minPresent = true; + } + if (NumNumbers > (maxIdx - 1) && !state.dataIPShortCut->lNumericFieldBlanks(maxIdx)) { + thisCurve->outputLimits.max = Numbers(maxIdx); + thisCurve->outputLimits.maxPresent = true; + } + } - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } + // Helper: read one curve object from input, check for duplicate name, and create/return a new Curve. + static Curve *readCurveObject(EnergyPlusData &state, + std::string_view routineName, + std::string const &CurrentModuleObject, + int CurveIndex, + Array1D_string &Alphas, + int &NumAlphas, + Array1D &Numbers, + int &NumNumbers, + int &IOStatus, + bool &ErrorsFound) + { + state.dataInputProcessing->inputProcessor->getObjectItem(state, + CurrentModuleObject, + CurveIndex, + Alphas, + NumAlphas, + Numbers, + NumNumbers, + IOStatus, + state.dataIPShortCut->lNumericFieldBlanks, + _, + state.dataIPShortCut->cAlphaFieldNames, + state.dataIPShortCut->cNumericFieldNames); + + ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; + + if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { + ShowSevereDuplicateName(state, eoh); + ErrorsFound = true; + } - auto *thisCurve = AddCurve(state, Alphas(1)); + return AddCurve(state, Alphas(1)); + } - thisCurve->curveType = CurveType::ExponentialDecay; - thisCurve->numDims = 1; - for (int in = 0; in < 3; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(4); - thisCurve->inputLimits[0].max = Numbers(5); + // Helper: validate that input-limit min <= max for a given numeric field pair, report error if not. + static void checkCurveInputLimits( + EnergyPlusData &state, std::string const &CurrentModuleObject, Array1D const &Numbers, int minIdx, int maxIdx, bool &ErrorsFound) + { + if (Numbers(minIdx) > Numbers(maxIdx)) { + ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); + ShowContinueError(state, + EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", + state.dataIPShortCut->cNumericFieldNames(minIdx), + Numbers(minIdx), + state.dataIPShortCut->cNumericFieldNames(maxIdx), + Numbers(maxIdx))); + ErrorsFound = true; + } + } - if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) { - thisCurve->outputLimits.min = Numbers(6); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) { - thisCurve->outputLimits.max = Numbers(7); - thisCurve->outputLimits.maxPresent = true; - } + // Helper: populate a simple polynomial/exponential curve from numeric fields. + // The layout is: numCoeffs coefficients starting at field 1, then numDims pairs of (min, max) input limits, + // then optional output min/max. Validates input limits and optionally validates unit-type alphas. + static void readSimpleCurveFields(EnergyPlusData &state, + Curve *thisCurve, + std::string const &CurrentModuleObject, + Array1D_string const &Alphas, + int NumAlphas, + Array1D const &Numbers, + int NumNumbers, + CurveType curveType, + int numDims, + int numCoeffs, + bool &ErrorsFound, + bool validateUnitTypes = true) + { + thisCurve->curveType = curveType; + thisCurve->numDims = numDims; + for (int in = 0; in < numCoeffs; ++in) { + thisCurve->coeff[in] = Numbers(in + 1); + } + int limBase = numCoeffs + 1; // 1-based index where input limits start + for (int d = 0; d < numDims; ++d) { + int minIdx = limBase + 2 * d; + int maxIdx = minIdx + 1; + thisCurve->inputLimits[d].min = Numbers(minIdx); + thisCurve->inputLimits[d].max = Numbers(maxIdx); + checkCurveInputLimits(state, CurrentModuleObject, Numbers, minIdx, maxIdx, ErrorsFound); + } + int outLimIdx = limBase + 2 * numDims; + readOptionalOutputLimits(state, thisCurve, NumNumbers, Numbers, outLimIdx); + if (validateUnitTypes) { + checkCurveUnitTypes(state, CurrentModuleObject, Alphas(1), NumAlphas, Alphas, numDims, 2); + } + } - if (Numbers(4) > Numbers(5)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(4), - Numbers(4), - state.dataIPShortCut->cNumericFieldNames(5), - Numbers(5))); - ErrorsFound = true; - } + void GetCurveInputData(EnergyPlusData &state, bool &ErrorsFound) + { - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } - } - if (NumAlphas >= 3) { - if (!IsCurveOutputTypeValid(Alphas(3))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } // Exponential Decay + // SUBROUTINE INFORMATION: + // AUTHOR Fred Buhl + // DATE WRITTEN May 2000 + // MODIFIED January 2006, Rick Strand, added a curve type (quadratic-linear) + // July 2006, L. Gu, added a curve type (bicubic) + // July 2006, BG added triquadratic. + // April 2008, LL Added Linear Curve; July 2008, restructure for easier renaming + // Feb 2009, R. Raustad - FSEC, added exponent curve + // 22Aug2010 Craig Wray, added new curves for fan component model: + // FanPressureRise, ExponentialSkewNormal, Sigmoid, RectangularHyperbola1, + // RectangularHyperbola2, ExponentialDecay + // Aug. 2014, Rongpeng Zhang, added a new curve type (ChillerPartLoadWithLift) + // Jan. 2017, Jason DeGraw, added WPC input into tables + // RE-ENGINEERED na - // ykt July,2011 Loop over DoubleExponential Decay curves and load data - CurrentModuleObject = "Curve:DoubleExponentialDecay"; - for (int CurveIndex = 1; CurveIndex <= NumDoubleExpDecay; ++CurveIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CurveIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - state.dataIPShortCut->lNumericFieldBlanks, - _, - state.dataIPShortCut->cAlphaFieldNames, - state.dataIPShortCut->cNumericFieldNames); - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; + // PURPOSE OF THIS SUBROUTINE: + // Obtains input data for EnergyPlus equipment performance curves - if (state.dataCurveManager->curveMap.find(Alphas(1)) != state.dataCurveManager->curveMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - } + // METHODOLOGY EMPLOYED: + // Uses "Get" routines to read in data. - auto *thisCurve = AddCurve(state, Alphas(1)); + // SUBROUTINE LOCAL VARIABLE DECLARATIONS: + constexpr std::string_view routineName = "GetCurveInputData"; - thisCurve->curveType = CurveType::DoubleExponentialDecay; - thisCurve->numDims = 1; - for (int in = 0; in < 5; ++in) { - thisCurve->coeff[in] = Numbers(in + 1); - } - thisCurve->inputLimits[0].min = Numbers(6); - thisCurve->inputLimits[0].max = Numbers(7); - - if (Numbers(6) > Numbers(7)) { // error - ShowSevereError(state, EnergyPlus::format("GetCurveInput: For {}: ", CurrentModuleObject)); - ShowContinueError(state, - EnergyPlus::format("{} [{:.2R}] > {} [{:.2R}]", - state.dataIPShortCut->cNumericFieldNames(6), - Numbers(6), - state.dataIPShortCut->cNumericFieldNames(7), - Numbers(7))); - ErrorsFound = true; - } + Array1D_string Alphas(14); // Alpha items for object + Array1D Numbers(10000); // Numeric items for object + int NumAlphas; // Number of Alphas for each GetObjectItem call + int NumNumbers; // Number of Numbers for each GetObjectItem call + int IOStatus; // Used in GetObjectItem + std::string CurrentModuleObject; // for ease in renaming. - if (NumNumbers > 7 && !state.dataIPShortCut->lNumericFieldBlanks(8)) { - thisCurve->outputLimits.min = Numbers(8); - thisCurve->outputLimits.minPresent = true; - } - if (NumNumbers > 8 && !state.dataIPShortCut->lNumericFieldBlanks(9)) { - thisCurve->outputLimits.max = Numbers(9); - thisCurve->outputLimits.maxPresent = true; - } + // Data table describing simple curve types that share the same read pattern. + struct SimpleCurveSpec + { + std::string_view objectName; + CurveType curveType; + int numDims; + int numCoeffs; + bool validateUnitTypes; + }; + static constexpr std::array simpleCurveSpecs{{ + {"Curve:Biquadratic", CurveType::BiQuadratic, 2, 6, true}, + {"Curve:ChillerPartLoadWithLift", CurveType::ChillerPartLoadWithLift, 3, 12, true}, + {"Curve:Cubic", CurveType::Cubic, 1, 4, true}, + {"Curve:Quartic", CurveType::Quartic, 1, 5, true}, + {"Curve:Quadratic", CurveType::Quadratic, 1, 3, true}, + {"Curve:QuadraticLinear", CurveType::QuadraticLinear, 2, 6, true}, + {"Curve:CubicLinear", CurveType::CubicLinear, 2, 6, true}, + {"Curve:Linear", CurveType::Linear, 1, 2, true}, + {"Curve:Bicubic", CurveType::BiCubic, 2, 10, true}, + {"Curve:Triquadratic", CurveType::TriQuadratic, 3, 27, true}, + {"Curve:QuadLinear", CurveType::QuadLinear, 4, 5, true}, + {"Curve:QuintLinear", CurveType::QuintLinear, 5, 6, true}, + {"Curve:Exponent", CurveType::Exponent, 1, 3, true}, + {"Curve:FanPressureRise", CurveType::FanPressureRise, 2, 4, false}, + {"Curve:ExponentialSkewNormal", CurveType::ExponentialSkewNormal, 1, 4, true}, + {"Curve:Sigmoid", CurveType::Sigmoid, 1, 5, true}, + {"Curve:RectangularHyperbola1", CurveType::RectangularHyperbola1, 1, 3, true}, + {"Curve:RectangularHyperbola2", CurveType::RectangularHyperbola2, 1, 3, true}, + {"Curve:ExponentialDecay", CurveType::ExponentialDecay, 1, 3, true}, + {"Curve:DoubleExponentialDecay", CurveType::DoubleExponentialDecay, 1, 5, true}, + }}; + + // Find the number of non-simple curve types (TableLookup, WPC) + int const NumTableLookup = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Table:Lookup"); + int const NumWPCValTab = + state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirflowNetwork:MultiZone:WindPressureCoefficientValues"); - if (NumAlphas >= 2) { - if (!IsCurveInputTypeValid(Alphas(2))) { - ShowWarningError(state, - EnergyPlus::format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1))); - } + // Read all simple curve types using the data table + for (auto const &spec : simpleCurveSpecs) { + CurrentModuleObject = spec.objectName; + int const numCurves = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject); + for (int CurveIndex = 1; CurveIndex <= numCurves; ++CurveIndex) { + auto *thisCurve = readCurveObject( + state, routineName, CurrentModuleObject, CurveIndex, Alphas, NumAlphas, Numbers, NumNumbers, IOStatus, ErrorsFound); + readSimpleCurveFields(state, + thisCurve, + CurrentModuleObject, + Alphas, + NumAlphas, + Numbers, + NumNumbers, + spec.curveType, + spec.numDims, + spec.numCoeffs, + ErrorsFound, + spec.validateUnitTypes); } - if (NumAlphas >= 3) { - if (!IsCurveOutputTypeValid(Alphas(3))) { - ShowWarningError(state, EnergyPlus::format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1))); - } - } - } // Exponential Decay + } // Loop over wind pressure coefficient tables and load data if (NumWPCValTab > 0) { @@ -2558,28 +1237,10 @@ namespace Curve { int numDims = state.dataCurveManager->btwxtManager.getNumGridDims(gridIndex); thisCurve->numDims = numDims; - for (int i = 1; i <= std::min(6, numDims); ++i) { - double vMin, vMax; - std::tie(vMin, vMax) = varListLimits.at(indVarListName)[i - 1]; - if (i == 1) { - thisCurve->inputLimits[0].min = vMin; - thisCurve->inputLimits[0].max = vMax; - } else if (i == 2) { - thisCurve->inputLimits[1].min = vMin; - thisCurve->inputLimits[1].max = vMax; - } else if (i == 3) { - thisCurve->inputLimits[2].min = vMin; - thisCurve->inputLimits[2].max = vMax; - } else if (i == 4) { - thisCurve->inputLimits[3].min = vMin; - thisCurve->inputLimits[3].max = vMax; - } else if (i == 5) { - thisCurve->inputLimits[4].min = vMin; - thisCurve->inputLimits[4].max = vMax; - } else if (i == 6) { - thisCurve->inputLimits[5].min = vMin; - thisCurve->inputLimits[5].max = vMax; - } + for (int i = 0; i < std::min(6, numDims); ++i) { + auto const &[vMin, vMax] = varListLimits.at(indVarListName)[i]; + thisCurve->inputLimits[i].min = vMin; + thisCurve->inputLimits[i].max = vMax; } if (fields.count("minimum_output") != 0u) { diff --git a/src/EnergyPlus/DXCoils.cc b/src/EnergyPlus/DXCoils.cc index a7356afb99f..d12742d5833 100644 --- a/src/EnergyPlus/DXCoils.cc +++ b/src/EnergyPlus/DXCoils.cc @@ -690,6 +690,695 @@ void SimDXCoilMultiMode(EnergyPlusData &state, ReportDXCoil(state, DXCoilNum); } +// Helper: allocate and populate single-performance-mode numeric field names for a coil. +// Eliminates the 3-line allocate/assign boilerplate repeated for each single-mode coil type. +static void +allocateSinglePerfModeNumericFields(EnergyPlusData &state, int const DXCoilNum, int const MaxNumbers, Array1D_string const &cNumericFields) +{ + state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); + state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); + state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; +} + +// Helper: emit "missing/blank" or "not found/invalid" severe error for a required curve field. +// Consolidates the 5-line if/else error block that appears whenever a required curve index is 0. +static void reportMissingOrInvalidCurve(EnergyPlusData &state, + bool const isBlank, + std::string_view const routineName, + std::string_view const objectType, + std::string_view const coilName, + std::string_view const fieldName, + std::string_view const alphaValue, + bool &ErrorsFound) +{ + if (isBlank) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", routineName, objectType, coilName)); + ShowContinueError(state, EnergyPlus::format("...required {} is blank.", fieldName)); + } else { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", routineName, objectType, coilName)); + ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", fieldName, alphaValue)); + } + ErrorsFound = true; +} + +// Helper: get and validate the optional crankcase heater capacity function of outdoor temperature curve. +// This consolidates the identical block repeated across coil-type parsers. +static void setupCrankcaseHeaterCapacityCurve(EnergyPlusData &state, + DXCoilData &thisDXCoil, + bool isBlank, + std::string const &curveName, + bool &ErrorsFound, + std::string_view const routineName, + std::string_view const objectType, + std::string_view const fieldName) +{ + if (isBlank) { + return; + } + thisDXCoil.CrankcaseHeaterCapacityCurveIndex = Curve::GetCurveIndex(state, curveName); + if (thisDXCoil.CrankcaseHeaterCapacityCurveIndex == 0) { + ShowSevereError(state, EnergyPlus::format("{} = {}: {} not found = {}", objectType, thisDXCoil.Name, fieldName, curveName)); + ErrorsFound = true; + } else { + ErrorsFound |= Curve::CheckCurveDims(state, + thisDXCoil.CrankcaseHeaterCapacityCurveIndex, // Curve index + {1}, // Valid dimensions + routineName, // Routine name + objectType, // Object Type + thisDXCoil.Name, // Object Name + fieldName); // Field Name + } +} + +// Helper: scan a PLF(PLR) curve over [0,1], cap if out of [0.7,1.0], and emit warnings. +// This consolidates the identical PLF validation block repeated across coil-type parsers. +static void validateAndCapPLFCurve(EnergyPlusData &state, + int const curveIndex, + bool &ErrorsFound, + std::string_view const routineName, + std::string_view const objectType, + std::string_view const coilName, + std::string_view const fieldName, + std::string_view const alphaValue) +{ + Real64 minCurveVal = 999.0; + Real64 maxCurveVal = -999.0; + Real64 minCurvePLR = 0.0; + Real64 maxCurvePLR = 0.0; + Real64 curveInput = 0.0; + while (curveInput <= 1.0) { + Real64 curveVal = Curve::CurveValue(state, curveIndex, curveInput); + if (curveVal < minCurveVal) { + minCurveVal = curveVal; + minCurvePLR = curveInput; + } + if (curveVal > maxCurveVal) { + maxCurveVal = curveVal; + maxCurvePLR = curveInput; + } + curveInput += 0.01; + } + if (minCurveVal < 0.7) { + ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", routineName, objectType, coilName)); + ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", fieldName, alphaValue)); + ShowContinueError(state, + EnergyPlus::format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", minCurvePLR, minCurveVal)); + ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues."); + Curve::SetCurveOutputMinValue(state, curveIndex, ErrorsFound, 0.7); + } + if (maxCurveVal > 1.0) { + ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", routineName, objectType, coilName)); + ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", fieldName, alphaValue)); + ShowContinueError(state, + EnergyPlus::format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", maxCurvePLR, maxCurveVal)); + ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues."); + Curve::SetCurveOutputMaxValue(state, curveIndex, ErrorsFound, 1.0); + } +} + +// Helper: look up a 1D flow-based curve, check dims={1}, and verify normalized to 1.0. +// Assigns the curve index to curveIdx. On missing/invalid curve, calls reportMissingOrInvalidCurve. +static void getAndCheckFlowCurve(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view const RoutineName, + std::string_view const CurrentModuleObject, + int &curveIdx, + int alphaFieldNum, + const std::string &coilName, + const Array1D_string &alphaArr, + const Array1D_bool &blankArr, + const Array1D_string &fieldNames) +{ + curveIdx = Curve::GetCurveIndex(state, alphaArr(alphaFieldNum)); + if (curveIdx == 0) { + reportMissingOrInvalidCurve(state, + blankArr(alphaFieldNum), + RoutineName, + CurrentModuleObject, + coilName, + fieldNames(alphaFieldNum), + alphaArr(alphaFieldNum), + ErrorsFound); + } else { + ErrorsFound |= Curve::CheckCurveDims(state, curveIdx, {1}, RoutineName, CurrentModuleObject, coilName, fieldNames(alphaFieldNum)); + if (!ErrorsFound) { + Curve::checkCurveIsNormalizedToOne(state, + std::string{RoutineName} + std::string{CurrentModuleObject}, + coilName, + curveIdx, + fieldNames(alphaFieldNum), + alphaArr(alphaFieldNum), + 1.0); + } + } +} + +// Helper: read an optional outdoor condenser inlet air node field. +// If blank, sets nodeNum to 0. Otherwise creates the node and warns if not outdoor. +static void readOutdoorCondenserNode(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view const RoutineName, + std::string_view const CurrentModuleObject, + int &nodeNum, + int alphaFieldNum, + Node::ConnectionObjectType connObjType, + const std::string &coilName, + const Array1D_string &Alphas, + const Array1D_bool &lAlphaBlanks, + const Array1D_string &cAlphaFields) +{ + if (lAlphaBlanks(alphaFieldNum)) { + nodeNum = 0; + } else { + nodeNum = Node::GetOnlySingleNode(state, + Alphas(alphaFieldNum), + ErrorsFound, + connObjType, + coilName, + Node::FluidType::Air, + Node::ConnectionType::OutsideAirReference, + Node::CompFluidStream::Primary, + Node::ObjectIsNotParent); + if (!OutAirNodeManager::CheckOutAirNodeNumber(state, nodeNum)) { + ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", may be invalid", RoutineName, CurrentModuleObject, coilName)); + ShowContinueError(state, + EnergyPlus::format("{}=\"{}\", node does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.", + cAlphaFields(alphaFieldNum), + Alphas(alphaFieldNum))); + ShowContinueError(state, + "This node needs to be included in an air system or the coil model will not be valid, and the simulation continues"); + } + } +} + +// Helper: look up a 2D cooling temperature curve, check dims={2}, and verify normalized +// to 1.0 at RatedInletWetBulbTemp and RatedOutdoorAirTemp. +static void getAndCheck2DCoolingTempCurve(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view const RoutineName, + std::string_view const CurrentModuleObject, + int &curveIdx, + int alphaFieldNum, + const std::string &coilName, + const Array1D_string &alphaArr, + const Array1D_bool &blankArr, + const Array1D_string &fieldNames) +{ + curveIdx = Curve::GetCurveIndex(state, alphaArr(alphaFieldNum)); + if (curveIdx == 0) { + reportMissingOrInvalidCurve(state, + blankArr(alphaFieldNum), + RoutineName, + CurrentModuleObject, + coilName, + fieldNames(alphaFieldNum), + alphaArr(alphaFieldNum), + ErrorsFound); + } else { + ErrorsFound |= Curve::CheckCurveDims(state, curveIdx, {2}, RoutineName, CurrentModuleObject, coilName, fieldNames(alphaFieldNum)); + if (!ErrorsFound) { + Curve::checkCurveIsNormalizedToOne(state, + std::string{RoutineName} + std::string{CurrentModuleObject}, + coilName, + curveIdx, + fieldNames(alphaFieldNum), + alphaArr(alphaFieldNum), + RatedInletWetBulbTemp, + RatedOutdoorAirTemp); + } + } +} + +// Helper: look up a 1D-or-2D heating temperature curve (MSCCapFTemp or MSEIRFTemp), +// validate dimensions, and check normalization at rated heating conditions. +static void getAndCheck2DHeatingTempCurve(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view const RoutineName, + std::string_view const CurrentModuleObject, + int &curveIdx, + int alphaFieldNum, + const std::string &coilName, + const Array1D_string &alphaArr, + const Array1D_bool &blankArr, + const Array1D_string &fieldNames) +{ + curveIdx = Curve::GetCurveIndex(state, alphaArr(alphaFieldNum)); + if (curveIdx == 0) { + reportMissingOrInvalidCurve(state, + blankArr(alphaFieldNum), + RoutineName, + CurrentModuleObject, + coilName, + fieldNames(alphaFieldNum), + alphaArr(alphaFieldNum), + ErrorsFound); + } else { + ErrorsFound |= Curve::CheckCurveDims(state, curveIdx, {1, 2}, RoutineName, CurrentModuleObject, coilName, fieldNames(alphaFieldNum)); + if (!ErrorsFound) { + if (state.dataCurveManager->curves(curveIdx)->numDims == 1) { + Curve::checkCurveIsNormalizedToOne(state, + std::string{RoutineName} + std::string{CurrentModuleObject}, + coilName, + curveIdx, + fieldNames(alphaFieldNum), + alphaArr(alphaFieldNum), + RatedOutdoorAirTempHeat); + } else { + Curve::checkCurveIsNormalizedToOne(state, + std::string{RoutineName} + std::string{CurrentModuleObject}, + coilName, + curveIdx, + fieldNames(alphaFieldNum), + alphaArr(alphaFieldNum), + RatedInletAirTempHeat, + RatedOutdoorAirTempHeat); + } + } + } +} + +// Helper: look up a PLF curve, check dims={1}, and validate/cap its range. +static void getAndCheckPLFCurve(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view const RoutineName, + std::string_view const CurrentModuleObject, + int &curveIdx, + int alphaFieldNum, + const std::string &coilName, + const Array1D_string &alphaArr, + const Array1D_bool &blankArr, + const Array1D_string &fieldNames) +{ + curveIdx = Curve::GetCurveIndex(state, alphaArr(alphaFieldNum)); + if (curveIdx == 0) { + reportMissingOrInvalidCurve(state, + blankArr(alphaFieldNum), + RoutineName, + CurrentModuleObject, + coilName, + fieldNames(alphaFieldNum), + alphaArr(alphaFieldNum), + ErrorsFound); + } else { + ErrorsFound |= Curve::CheckCurveDims(state, curveIdx, {1}, RoutineName, CurrentModuleObject, coilName, fieldNames(alphaFieldNum)); + if (!ErrorsFound) { + validateAndCapPLFCurve( + state, curveIdx, ErrorsFound, RoutineName, CurrentModuleObject, coilName, fieldNames(alphaFieldNum), alphaArr(alphaFieldNum)); + } + } +} + +// Setup the 8 standard output variables for single-speed and two-speed cooling coils +// (Total, Sensible, Latent cooling rate/energy + Electricity rate/energy) +static void setupStdCoolingOutputVars(EnergyPlusData &state, DXCoilData &thisDXCoil) +{ + SetupOutputVariable(state, + "Cooling Coil Total Cooling Rate", + Constant::Units::W, + thisDXCoil.TotalCoolingEnergyRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Total Cooling Energy", + Constant::Units::J, + thisDXCoil.TotalCoolingEnergy, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::EnergyTransfer, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::CoolingCoils); + SetupOutputVariable(state, + "Cooling Coil Sensible Cooling Rate", + Constant::Units::W, + thisDXCoil.SensCoolingEnergyRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Sensible Cooling Energy", + Constant::Units::J, + thisDXCoil.SensCoolingEnergy, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Latent Cooling Rate", + Constant::Units::W, + thisDXCoil.LatCoolingEnergyRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Latent Cooling Energy", + Constant::Units::J, + thisDXCoil.LatCoolingEnergy, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Electricity Rate", + Constant::Units::W, + thisDXCoil.ElecCoolingPower, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Electricity Energy", + Constant::Units::J, + thisDXCoil.ElecCoolingConsumption, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Cooling); +} + +// Setup the 7 standard output variables for VRF cooling coils +// (Total, Sensible, Latent cooling rate/energy + Runtime Fraction, no Electricity) +static void setupVRFCoolingOutputVars(EnergyPlusData &state, DXCoilData &thisDXCoil) +{ + SetupOutputVariable(state, + "Cooling Coil Total Cooling Rate", + Constant::Units::W, + thisDXCoil.TotalCoolingEnergyRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Total Cooling Energy", + Constant::Units::J, + thisDXCoil.TotalCoolingEnergy, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::EnergyTransfer, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::CoolingCoils); + SetupOutputVariable(state, + "Cooling Coil Sensible Cooling Rate", + Constant::Units::W, + thisDXCoil.SensCoolingEnergyRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Sensible Cooling Energy", + Constant::Units::J, + thisDXCoil.SensCoolingEnergy, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Latent Cooling Rate", + Constant::Units::W, + thisDXCoil.LatCoolingEnergyRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Latent Cooling Energy", + Constant::Units::J, + thisDXCoil.LatCoolingEnergy, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Runtime Fraction", + Constant::Units::None, + thisDXCoil.CoolingCoilRuntimeFraction, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); +} + +// Setup 4 common DX heating coil output variables (Heating Rate/Energy + Electricity Rate/Energy) +static void setupStdDXHeatingOutputVars(EnergyPlusData &state, DXCoilData &thisDXCoil) +{ + SetupOutputVariable(state, + "Heating Coil Heating Rate", + Constant::Units::W, + thisDXCoil.TotalHeatingEnergyRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Heating Coil Heating Energy", + Constant::Units::J, + thisDXCoil.TotalHeatingEnergy, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::EnergyTransfer, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::HeatingCoils); + SetupOutputVariable(state, + "Heating Coil Electricity Rate", + Constant::Units::W, + thisDXCoil.ElecHeatingPower, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Heating Coil Electricity Energy", + Constant::Units::J, + thisDXCoil.ElecHeatingConsumption, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Heating); +} + +// Setup crankcase heater and runtime fraction output variables common to heating coils +static void setupDXHeatingCrankcaseAndRuntimeOutputVars(EnergyPlusData &state, DXCoilData &thisDXCoil) +{ + SetupOutputVariable(state, + "Heating Coil Crankcase Heater Electricity Rate", + Constant::Units::W, + thisDXCoil.CrankcaseHeaterPower, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Heating Coil Crankcase Heater Electricity Energy", + Constant::Units::J, + thisDXCoil.CrankcaseHeaterConsumption, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Heating); + SetupOutputVariable(state, + "Heating Coil Runtime Fraction", + Constant::Units::None, + thisDXCoil.HeatingCoilRuntimeFraction, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); +} + +// Setup 3 standard VRF heating coil output variables (Heating Rate/Energy + Runtime Fraction) +static void setupVRFHeatingOutputVars(EnergyPlusData &state, DXCoilData &thisDXCoil) +{ + SetupOutputVariable(state, + "Heating Coil Heating Rate", + Constant::Units::W, + thisDXCoil.TotalHeatingEnergyRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Heating Coil Heating Energy", + Constant::Units::J, + thisDXCoil.TotalHeatingEnergy, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::EnergyTransfer, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::HeatingCoils); + SetupOutputVariable(state, + "Heating Coil Runtime Fraction", + Constant::Units::None, + thisDXCoil.HeatingCoilRuntimeFraction, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); +} + +// Setup condensate tank output variables (2 vars) when CondensateCollectMode == ToTank +static void setupCondensateTankOutputVars(EnergyPlusData &state, DXCoilData &thisDXCoil) +{ + if (thisDXCoil.CondensateCollectMode == CondensateCollectAction::ToTank) { + SetupOutputVariable(state, + "Cooling Coil Condensate Volume Flow Rate", + Constant::Units::m3_s, + thisDXCoil.CondensateVdot, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Condensate Volume", + Constant::Units::m3, + thisDXCoil.CondensateVol, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::OnSiteWater, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Condensate); + } +} + +// Setup secondary cooling coil heat rejection output variable +static void setupSecondaryCoolingHeatRejectionOutputVar(EnergyPlusData &state, DXCoilData &thisDXCoil) +{ + if (thisDXCoil.IsSecondaryDXCoilInZone) { + SetupOutputVariable(state, + "Secondary Coil Heat Rejection Rate", + Constant::Units::W, + thisDXCoil.SecCoilSensibleHeatGainRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + } +} + +static void setupEvapCondOutputVars(EnergyPlusData &state, DXCoilData &thisDXCoil) +{ + SetupOutputVariable(state, + "Cooling Coil Condenser Inlet Temperature", + Constant::Units::C, + thisDXCoil.CondInletTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Evaporative Condenser Water Volume", + Constant::Units::m3, + thisDXCoil.EvapWaterConsump, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::Water, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Cooling); + SetupOutputVariable(state, + "Cooling Coil Evaporative Condenser Mains Supply Water Volume", + Constant::Units::m3, + thisDXCoil.EvapWaterConsump, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::MainsWater, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Cooling); + SetupOutputVariable(state, + "Cooling Coil Evaporative Condenser Pump Electricity Rate", + Constant::Units::W, + thisDXCoil.EvapCondPumpElecPower, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Evaporative Condenser Pump Electricity Energy", + Constant::Units::J, + thisDXCoil.EvapCondPumpElecConsumption, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Cooling); + if (thisDXCoil.BasinHeaterPowerFTempDiff > 0.0) { + SetupOutputVariable(state, + "Cooling Coil Basin Heater Electricity Rate", + Constant::Units::W, + thisDXCoil.BasinHeaterPower, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Basin Heater Electricity Energy", + Constant::Units::J, + thisDXCoil.BasinHeaterConsumption, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + thisDXCoil.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Cooling); + } +} + +// Set the condensate collect mode on a coil and register its tank supply component when needed. +// Call after assigning thisDXCoil.CondensateCollectName from Alphas(N); pass lAlphaBlanks(N) as isBlank. +static void +setupCondensateTankSupply(EnergyPlusData &state, DXCoilData &thisDXCoil, bool isBlank, std::string const ¤tModuleObject, bool &errorsFound) +{ + if (isBlank) { + thisDXCoil.CondensateCollectMode = CondensateCollectAction::Discard; + } else { + thisDXCoil.CondensateCollectMode = CondensateCollectAction::ToTank; + WaterManager::SetupTankSupplyComponent(state, + thisDXCoil.Name, + currentModuleObject, + thisDXCoil.CondensateCollectName, + errorsFound, + thisDXCoil.CondensateTankID, + thisDXCoil.CondensateTankSupplyARRID); + } +} + +// Set evaporative water supply mode and register tank demand component when needed. +// Call after assigning thisDXCoil.EvapWaterSupplyName from Alphas(N); pass lAlphaBlanks(N) as isBlank. +static void +setupEvapWaterSupplyTank(EnergyPlusData &state, DXCoilData &thisDXCoil, bool isBlank, std::string const ¤tModuleObject, bool &errorsFound) +{ + if (isBlank) { + thisDXCoil.EvapWaterSupplyMode = EvapWaterSupply::FromMains; + } else { + thisDXCoil.EvapWaterSupplyMode = EvapWaterSupply::FromTank; + WaterManager::SetupTankDemandComponent(state, + thisDXCoil.Name, + currentModuleObject, + thisDXCoil.EvapWaterSupplyName, + errorsFound, + thisDXCoil.EvapWaterSupTankID, + thisDXCoil.EvapWaterTankDemandARRID); + } +} + +// Parse the condenser type string for a single-mode coil (CondenserType index 1). +// condenserTypeStr = Alphas(N), alphaFieldName = cAlphaFields(N). +// Sets CondenserType(1) and ReportEvapCondVars; logs error if unrecognised. +static void parseCondenserType(EnergyPlusData &state, + DXCoilData &thisDXCoil, + std::string_view routineName, + std::string const ¤tModuleObject, + std::string const &condenserTypeStr, + std::string const &alphaFieldName, + bool isBlank, + bool &errorsFound) +{ + if ((Util::SameString(condenserTypeStr, "AirCooled")) || isBlank) { + thisDXCoil.CondenserType(1) = DataHeatBalance::RefrigCondenserType::Air; + } else if (Util::SameString(condenserTypeStr, "EvaporativelyCooled")) { + thisDXCoil.CondenserType(1) = DataHeatBalance::RefrigCondenserType::Evap; + thisDXCoil.ReportEvapCondVars = true; + } else { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", routineName, currentModuleObject, thisDXCoil.Name)); + ShowContinueError(state, EnergyPlus::format("...{}=\"{}\":", alphaFieldName, condenserTypeStr)); + ShowContinueError(state, "...must be AirCooled or EvaporativelyCooled."); + errorsFound = true; + } +} + void GetDXCoils(EnergyPlusData &state) { @@ -800,52 +1489,30 @@ void GetDXCoils(EnergyPlusData &state) state.dataDXCoils->NumVRFHeatingFluidTCtrlCoils; // Determine max number of alpha and numeric arguments for all objects being read, in order to allocate local arrays - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Coil:Cooling:DX:SingleSpeed", TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = NumNumbers; - MaxAlphas = NumAlphas; - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Coil:Heating:DX:SingleSpeed", TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Coil:Cooling:DX:TwoSpeed", TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - state, "Coil:Cooling:DX:TwoStageWithHumidityControlMode", TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - state, HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterPumped), TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - state, HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterWrapped), TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Coil:Cooling:DX:MultiSpeed", TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Coil:Heating:DX:MultiSpeed", TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - state, HVAC::cAllCoilTypes(HVAC::CoilVRF_Cooling), TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - state, HVAC::cAllCoilTypes(HVAC::CoilVRF_Heating), TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - state, HVAC::cAllCoilTypes(HVAC::CoilVRF_FluidTCtrl_Cooling), TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( - state, HVAC::cAllCoilTypes(HVAC::CoilVRF_FluidTCtrl_Heating), TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "CoilPerformance:DX:Cooling", TotalArgs, NumAlphas, NumNumbers); - MaxNumbers = max(MaxNumbers, NumNumbers); - MaxAlphas = max(MaxAlphas, NumAlphas); + { + const std::array dxCoilObjectTypes = { + "Coil:Cooling:DX:SingleSpeed", + "Coil:Heating:DX:SingleSpeed", + "Coil:Cooling:DX:TwoSpeed", + "Coil:Cooling:DX:TwoStageWithHumidityControlMode", + std::string{HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterPumped)}, + std::string{HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterWrapped)}, + "Coil:Cooling:DX:MultiSpeed", + "Coil:Heating:DX:MultiSpeed", + std::string{HVAC::cAllCoilTypes(HVAC::CoilVRF_Cooling)}, + std::string{HVAC::cAllCoilTypes(HVAC::CoilVRF_Heating)}, + std::string{HVAC::cAllCoilTypes(HVAC::CoilVRF_FluidTCtrl_Cooling)}, + std::string{HVAC::cAllCoilTypes(HVAC::CoilVRF_FluidTCtrl_Heating)}, + "CoilPerformance:DX:Cooling", + }; + MaxNumbers = 0; + MaxAlphas = 0; + for (auto const &objType : dxCoilObjectTypes) { + state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, objType, TotalArgs, NumAlphas, NumNumbers); + MaxNumbers = max(MaxNumbers, NumNumbers); + MaxAlphas = max(MaxAlphas, NumAlphas); + } + } Alphas.allocate(MaxAlphas); cAlphaFields.allocate(MaxAlphas); @@ -893,13 +1560,12 @@ void GetDXCoils(EnergyPlusData &state) // initialize the coil counter DXCoilNum = 0; - // Loop over the Doe2 DX Coils and get & load the data - CurrentModuleObject = "Coil:Cooling:DX:SingleSpeed"; - for (DXCoilIndex = 1; DXCoilIndex <= state.dataDXCoils->NumDoe2DXCoils; ++DXCoilIndex) { - + // Helper lambda that wraps the repeated 11-argument getObjectItem call. + // CurrentModuleObject is captured by reference so each call site only needs the 1-based item number. + auto getItem = [&](int itemNum) { state.dataInputProcessing->inputProcessor->getObjectItem(state, CurrentModuleObject, - DXCoilIndex, + itemNum, Alphas, NumAlphas, Numbers, @@ -909,14 +1575,163 @@ void GetDXCoils(EnergyPlusData &state) lAlphaBlanks, cAlphaFields, cNumericFields); + }; + + // Helper lambda: abort when errors have been found after reading each object type. + auto checkAndFatal = [&]() { + if (ErrorsFound) { + ShowFatalError(state, + EnergyPlus::format( + "{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); + } + }; + + // Helper lambda: reads and validates the basin-heater power and set-point fields that appear in several coil-type sections. + // powFTempDiffNumIdx - 1-based Numbers() index for BasinHeaterPowerFTempDiff + // setPointNumIdx - 1-based Numbers() index for BasinHeaterSetPointTemp + auto readBasinHeaterPowerAndSetpoint = [&](DXCoilData &coil, int powFTempDiffNumIdx, int setPointNumIdx) { + coil.BasinHeaterPowerFTempDiff = Numbers(powFTempDiffNumIdx); + if (Numbers(powFTempDiffNumIdx) < 0.0) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, coil.Name)); + ShowContinueError(state, EnergyPlus::format("...{} must be >= 0.0.", cNumericFields(powFTempDiffNumIdx))); + ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(powFTempDiffNumIdx))); + ErrorsFound = true; + } + + coil.BasinHeaterSetPointTemp = Numbers(setPointNumIdx); + if (coil.BasinHeaterPowerFTempDiff > 0.0) { + if (NumNumbers < setPointNumIdx) { + coil.BasinHeaterSetPointTemp = 2.0; + } + if (coil.BasinHeaterSetPointTemp < 2.0) { + ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", freeze possible", RoutineName, CurrentModuleObject, coil.Name)); + ShowContinueError(state, EnergyPlus::format("...{} is < 2 {{C}}. Freezing could occur.", cNumericFields(setPointNumIdx))); + ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(setPointNumIdx))); + } + } + }; + + // Helper lambda: reads the optional basin-heater schedule field. + // schedAlphaIdx - 1-based Alphas() index for the schedule field + auto readBasinHeaterSchedule = [&](DXCoilData &coil, const ErrorObjectHeader &eohRef, int schedAlphaIdx) { + if (!lAlphaBlanks(schedAlphaIdx)) { + if ((coil.basinHeaterSched = Sched::GetSchedule(state, Alphas(schedAlphaIdx))) == nullptr) { + ShowWarningItemNotFound(state, + eohRef, + cAlphaFields(schedAlphaIdx), + Alphas(schedAlphaIdx), + "Basin heater will be available to operate throughout the simulation."); + } + } + }; + + // Helper lambda: convenience wrapper calling readBasinHeaterPowerAndSetpoint followed immediately by readBasinHeaterSchedule. + // Used in coil-type sections where the three basin-heater fields are adjacent (no intervening inputs). + auto readBasinHeaterInputs = + [&](DXCoilData &coil, const ErrorObjectHeader &eohRef, int powFTempDiffNumIdx, int setPointNumIdx, int schedAlphaIdx) { + readBasinHeaterPowerAndSetpoint(coil, powFTempDiffNumIdx, setPointNumIdx); + readBasinHeaterSchedule(coil, eohRef, schedAlphaIdx); + }; + + // Helper lambda: allocates the per-speed arrays that are common to both the MultiSpeed + // Cooling and MultiSpeed Heating coil input sections. Coil-type-specific arrays (e.g. + // evap-cond arrays for cooling, secondary-coil arrays for heating) are allocated by the + // respective calling section after this call. + auto allocateCommonMSArrays = [&](DXCoilData &coil) { + int n = coil.NumOfSpeeds; + coil.MSErrIndex.allocate(n); + coil.MSErrIndex = 0; + coil.MSRatedTotCap.allocate(n); + coil.MSRatedCOP.allocate(n); + coil.MSRatedAirVolFlowRate.allocate(n); + coil.MSRatedAirMassFlowRate.allocate(n); + coil.MSRatedAirMassFlowRate = 1.0; // avoid divide by 0, will get overwritten in InitDXCoil + coil.MSCCapFTemp.allocate(n); + coil.MSCCapFFlow.allocate(n); + coil.MSEIRFTemp.allocate(n); + coil.MSEIRFFlow.allocate(n); + coil.MSWasteHeat.allocate(n); + coil.MSPLFFPLR.allocate(n); + coil.MSRatedCBF.allocate(n); + coil.MSWasteHeatFrac.allocate(n); + coil.MSFanPowerPerEvapAirFlowRate.allocate(n); + coil.MSFanPowerPerEvapAirFlowRate_2023.allocate(n); + }; + + // Helper lambda: reads and validates the three evaporative-condenser fields (effectiveness, + // air-flow rate, pump nominal power) that store into EvapCondEffect(speedIdx), + // EvapCondAirFlow(speedIdx), and EvapCondPumpElecNomPower(speedIdx). + // All index arguments are 1-based Numbers() indices. + auto readEvapCondSpeedInputs = [&](DXCoilData &coil, int speedIdx, int effectNumIdx, int airFlowNumIdx, int pumpPowerNumIdx) { + coil.EvapCondEffect(speedIdx) = Numbers(effectNumIdx); + if (coil.EvapCondEffect(speedIdx) < 0.0 || coil.EvapCondEffect(speedIdx) > 1.0) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, coil.Name)); + ShowContinueError(state, EnergyPlus::format("...{} cannot be < 0.0 or > 1.0.", cNumericFields(effectNumIdx))); + ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(effectNumIdx))); + ErrorsFound = true; + } + + coil.EvapCondAirFlow(speedIdx) = Numbers(airFlowNumIdx); + if (coil.EvapCondAirFlow(speedIdx) < 0.0 && coil.EvapCondAirFlow(speedIdx) != AutoSize) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, coil.Name)); + ShowContinueError(state, EnergyPlus::format("...{} cannot be < 0.0.", cNumericFields(airFlowNumIdx))); + ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(airFlowNumIdx))); + ErrorsFound = true; + } + + coil.EvapCondPumpElecNomPower(speedIdx) = Numbers(pumpPowerNumIdx); + if (coil.EvapCondPumpElecNomPower(speedIdx) < 0.0 && coil.EvapCondPumpElecNomPower(speedIdx) != AutoSize) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, coil.Name)); + ShowContinueError(state, EnergyPlus::format("...{} cannot be < 0.0.", cNumericFields(pumpPowerNumIdx))); + ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(pumpPowerNumIdx))); + ErrorsFound = true; + } + }; + + // Helper lambda: parses and validates the DefrostStrategy (ReverseCycle/Resistive) and + // DefrostControl (Timed/OnDemand) alpha fields that appear identically in the SingleSpeed + // and MultiSpeed heating coil input sections. + // stratAlphaIdx - 1-based Alphas() index for DefrostStrategy field + // ctrlAlphaIdx - 1-based Alphas() index for DefrostControl field + auto parseDefrostStrategyAndControl = [&](DXCoilData &coil, int stratAlphaIdx, int ctrlAlphaIdx) { + if (Util::SameString(Alphas(stratAlphaIdx), "ReverseCycle")) { + coil.DefrostStrategy = StandardRatings::DefrostStrat::ReverseCycle; + } + if (Util::SameString(Alphas(stratAlphaIdx), "Resistive")) { + coil.DefrostStrategy = StandardRatings::DefrostStrat::Resistive; + } + if (coil.DefrostStrategy == StandardRatings::DefrostStrat::Invalid) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, coil.Name)); + ShowContinueError(state, EnergyPlus::format("...illegal {}=\"{}\".", cAlphaFields(stratAlphaIdx), Alphas(stratAlphaIdx))); + ShowContinueError(state, "...valid values for this field are ReverseCycle or Resistive."); + ErrorsFound = true; + } + + if (Util::SameString(Alphas(ctrlAlphaIdx), "Timed")) { + coil.DefrostControl = StandardRatings::HPdefrostControl::Timed; + } + if (Util::SameString(Alphas(ctrlAlphaIdx), "OnDemand")) { + coil.DefrostControl = StandardRatings::HPdefrostControl::OnDemand; + } + if (coil.DefrostControl == StandardRatings::HPdefrostControl::Invalid) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, coil.Name)); + ShowContinueError(state, EnergyPlus::format("...illegal {}=\"{}\".", cAlphaFields(ctrlAlphaIdx), Alphas(ctrlAlphaIdx))); + ShowContinueError(state, "...valid values for this field are Timed or OnDemand."); + ErrorsFound = true; + } + }; + + // Loop over the Doe2 DX Coils and get & load the data + CurrentModuleObject = "Coil:Cooling:DX:SingleSpeed"; + for (DXCoilIndex = 1; DXCoilIndex <= state.dataDXCoils->NumDoe2DXCoils; ++DXCoilIndex) { + + getItem(DXCoilIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; ++DXCoilNum; // allocate single performance mode for numeric field strings used for sizing routine - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; + allocateSinglePerfModeNumericFields(state, DXCoilNum, MaxNumbers, cNumericFields); // ErrorsFound will be set to True if problem was found, left untouched otherwise VerifyUniqueCoilName(state, CurrentModuleObject, Alphas(1), ErrorsFound, CurrentModuleObject + " Name"); @@ -968,178 +1783,20 @@ void GetDXCoils(EnergyPlusData &state) TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes"); - thisDXCoil.CCapFTemp(1) = GetCurveIndex(state, Alphas(5)); // convert curve name to number - if (thisDXCoil.CCapFTemp(1) == 0) { - if (lAlphaBlanks(5)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(5))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(5), Alphas(5))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CCapFTemp(1), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(5)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.CCapFTemp(1), - cAlphaFields(5), - Alphas(5), - RatedInletWetBulbTemp, - RatedOutdoorAirTemp); - } - } - - thisDXCoil.CCapFFlow(1) = GetCurveIndex(state, Alphas(6)); // convert curve name to number - if (thisDXCoil.CCapFFlow(1) == 0) { - if (lAlphaBlanks(6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(6), Alphas(6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CCapFFlow(1), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(6)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne( - state, std::string{RoutineName} + CurrentModuleObject, thisDXCoil.Name, thisDXCoil.CCapFFlow(1), cAlphaFields(6), Alphas(6), 1.0); - } - } - - thisDXCoil.EIRFTemp(1) = GetCurveIndex(state, Alphas(7)); // convert curve name to number - if (thisDXCoil.EIRFTemp(1) == 0) { - if (lAlphaBlanks(7)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(7))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(7), Alphas(7))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.EIRFTemp(1), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(7)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.EIRFTemp(1), - cAlphaFields(7), - Alphas(7), - RatedInletWetBulbTemp, - RatedOutdoorAirTemp); - } - } - - thisDXCoil.EIRFFlow(1) = GetCurveIndex(state, Alphas(8)); // convert curve name to number - if (thisDXCoil.EIRFFlow(1) == 0) { - if (lAlphaBlanks(8)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(8))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(8), Alphas(8))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.EIRFFlow(1), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(8)); // Field Name + getAndCheck2DCoolingTempCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.CCapFTemp(1), 5, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - if (!ErrorsFound) { - checkCurveIsNormalizedToOne( - state, std::string{RoutineName} + CurrentModuleObject, thisDXCoil.Name, thisDXCoil.EIRFFlow(1), cAlphaFields(8), Alphas(8), 1.0); - } - } + getAndCheckFlowCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.CCapFFlow(1), 6, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - thisDXCoil.PLFFPLR(1) = GetCurveIndex(state, Alphas(9)); // convert curve name to number - if (thisDXCoil.PLFFPLR(1) == 0) { - if (lAlphaBlanks(9)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(9))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(9), Alphas(9))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal types are Quadratic or Cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.PLFFPLR(1), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(9)); // Field Name + getAndCheck2DCoolingTempCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.EIRFTemp(1), 7, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - if (!ErrorsFound) { - // Test PLF curve minimum and maximum. Cap if less than 0.7 or greater than 1.0. - MinCurveVal = 999.0; - MaxCurveVal = -999.0; - CurveInput = 0.0; - while (CurveInput <= 1.0) { - CurveVal = CurveValue(state, thisDXCoil.PLFFPLR(1), CurveInput); - if (CurveVal < MinCurveVal) { - MinCurveVal = CurveVal; - MinCurvePLR = CurveInput; - } - if (CurveVal > MaxCurveVal) { - MaxCurveVal = CurveVal; - MaxCurvePLR = CurveInput; - } - CurveInput += 0.01; - } - if (MinCurveVal < 0.7) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{}=\"{}\" has out of range values.", cAlphaFields(9), Alphas(9))); - ShowContinueError( - state, EnergyPlus::format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", MinCurvePLR, MinCurveVal)); - ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues."); - Curve::SetCurveOutputMinValue(state, thisDXCoil.PLFFPLR(1), ErrorsFound, 0.7); - } + getAndCheckFlowCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.EIRFFlow(1), 8, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - if (MaxCurveVal > 1.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", cAlphaFields(9), Alphas(9))); - ShowContinueError( - state, EnergyPlus::format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", MaxCurvePLR, MaxCurveVal)); - ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues."); - Curve::SetCurveOutputMaxValue(state, thisDXCoil.PLFFPLR(1), ErrorsFound, 1.0); - } - } - } + getAndCheckPLFCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.PLFFPLR(1), 9, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); // Set minimum OAT for compressor operation thisDXCoil.MinOATCompressor = Numbers(7); @@ -1160,66 +1817,21 @@ void GetDXCoils(EnergyPlusData &state) ShowContinueError(state, "...is set to zero. Therefore, the latent degradation model will not be used for this simulation."); } - // outdoor condenser node - if (lAlphaBlanks(10)) { - thisDXCoil.CondenserInletNodeNum(1) = 0; - } else { - thisDXCoil.CondenserInletNodeNum(1) = GetOnlySingleNode(state, - Alphas(10), - ErrorsFound, - Node::ConnectionObjectType::CoilCoolingDXSingleSpeed, - thisDXCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::OutsideAirReference, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - - if (!CheckOutAirNodeNumber(state, thisDXCoil.CondenserInletNodeNum(1))) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", may be invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("{}=\"{}\", node does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.", - cAlphaFields(10), - Alphas(10))); - ShowContinueError( - state, "This node needs to be included in an air system or the coil model will not be valid, and the simulation continues"); - } - } - - if ((Util::SameString(Alphas(11), "AirCooled")) || lAlphaBlanks(11)) { - thisDXCoil.CondenserType(1) = DataHeatBalance::RefrigCondenserType::Air; - } else if (Util::SameString(Alphas(11), "EvaporativelyCooled")) { - thisDXCoil.CondenserType(1) = DataHeatBalance::RefrigCondenserType::Evap; - thisDXCoil.ReportEvapCondVars = true; - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{}=\"{}\":", cAlphaFields(11), Alphas(11))); - ShowContinueError(state, "...must be AirCooled or EvaporativelyCooled."); - ErrorsFound = true; - } - - thisDXCoil.EvapCondEffect(1) = Numbers(12); - if (thisDXCoil.EvapCondEffect(1) < 0.0 || thisDXCoil.EvapCondEffect(1) > 1.0) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} cannot be < 0.0 or > 1.0.", cNumericFields(11))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(12))); - ErrorsFound = true; - } + readOutdoorCondenserNode(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.CondenserInletNodeNum(1), + 10, + Node::ConnectionObjectType::CoilCoolingDXSingleSpeed, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); - thisDXCoil.EvapCondAirFlow(1) = Numbers(13); - if (thisDXCoil.EvapCondAirFlow(1) < 0.0 && thisDXCoil.EvapCondAirFlow(1) != AutoSize) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} cannot be < 0.0.", cNumericFields(12))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(13))); - ErrorsFound = true; - } + parseCondenserType(state, thisDXCoil, RoutineName, CurrentModuleObject, Alphas(11), cAlphaFields(11), lAlphaBlanks(11), ErrorsFound); - thisDXCoil.EvapCondPumpElecNomPower(1) = Numbers(14); - if (thisDXCoil.EvapCondPumpElecNomPower(1) < 0.0 && thisDXCoil.EvapCondPumpElecNomPower(1) != AutoSize) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} cannot be < 0.0.", cNumericFields(13))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(14))); - ErrorsFound = true; - } + readEvapCondSpeedInputs(thisDXCoil, 1, 12, 13, 14); // Set crankcase heater capacity thisDXCoil.CrankcaseHeaterCapacity = Numbers(15); @@ -1238,81 +1850,20 @@ void GetDXCoils(EnergyPlusData &state) } // A12, \field Crankcase Heater Capacity Function of Outdoor Temperature Curve Name - if (!lAlphaBlanks(12)) { - thisDXCoil.CrankcaseHeaterCapacityCurveIndex = Curve::GetCurveIndex(state, Alphas(12)); - if (thisDXCoil.CrankcaseHeaterCapacityCurveIndex == 0) { // can't find the curve - ShowSevereError( - state, EnergyPlus::format("{} = {}: {} not found = {}", CurrentModuleObject, thisDXCoil.Name, cAlphaFields(12), Alphas(12))); - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CrankcaseHeaterCapacityCurveIndex, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(12)); // Field Name - } - } + setupCrankcaseHeaterCapacityCurve( + state, thisDXCoil, lAlphaBlanks(12), Alphas(12), ErrorsFound, RoutineName, CurrentModuleObject, cAlphaFields(12)); // Get Water System tank connections // A13, \field Name of Water Storage Tank for Supply thisDXCoil.EvapWaterSupplyName = Alphas(13); - if (lAlphaBlanks(13)) { - thisDXCoil.EvapWaterSupplyMode = EvapWaterSupply::FromMains; - } else { - thisDXCoil.EvapWaterSupplyMode = EvapWaterSupply::FromTank; - SetupTankDemandComponent(state, - thisDXCoil.Name, - CurrentModuleObject, - thisDXCoil.EvapWaterSupplyName, - ErrorsFound, - thisDXCoil.EvapWaterSupTankID, - thisDXCoil.EvapWaterTankDemandARRID); - } + setupEvapWaterSupplyTank(state, thisDXCoil, lAlphaBlanks(13), CurrentModuleObject, ErrorsFound); // A14; \field Name of Water Storage Tank for Condensate Collection thisDXCoil.CondensateCollectName = Alphas(14); - if (lAlphaBlanks(14)) { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::Discard; - } else { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::ToTank; - SetupTankSupplyComponent(state, - thisDXCoil.Name, - CurrentModuleObject, - thisDXCoil.CondensateCollectName, - ErrorsFound, - thisDXCoil.CondensateTankID, - thisDXCoil.CondensateTankSupplyARRID); - } + setupCondensateTankSupply(state, thisDXCoil, lAlphaBlanks(14), CurrentModuleObject, ErrorsFound); // Basin heater power as a function of temperature must be greater than or equal to 0 - thisDXCoil.BasinHeaterPowerFTempDiff = Numbers(17); - if (Numbers(17) < 0.0) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} must be >= 0.0.", cNumericFields(16))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(17))); - ErrorsFound = true; - } - - thisDXCoil.BasinHeaterSetPointTemp = Numbers(18); - if (thisDXCoil.BasinHeaterPowerFTempDiff > 0.0) { - if (NumNumbers < 18) { - thisDXCoil.BasinHeaterSetPointTemp = 2.0; - } - if (thisDXCoil.BasinHeaterSetPointTemp < 2.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", freeze possible", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} is < 2 {{C}}. Freezing could occur.", cNumericFields(17))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(18))); - } - } - - if (!lAlphaBlanks(15)) { - if ((thisDXCoil.basinHeaterSched = Sched::GetSchedule(state, Alphas(15))) == nullptr) { - ShowWarningItemNotFound( - state, eoh, cAlphaFields(15), Alphas(15), "Basin heater will be available to operate throughout the simulation."); - } - } + readBasinHeaterInputs(thisDXCoil, eoh, 17, 18, 15); if (!lAlphaBlanks(16) && NumAlphas > 15) { thisDXCoil.SHRFTemp(1) = GetCurveIndex(state, Alphas(16)); // convert curve name to number @@ -1380,28 +1931,13 @@ void GetDXCoils(EnergyPlusData &state) } // end of the Doe2 DX coil loop - if (ErrorsFound) { - ShowFatalError( - state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); - } + checkAndFatal(); // Loop over the Multimode DX Coils and get & load the data CurrentModuleObject = "Coil:Cooling:DX:TwoStageWithHumidityControlMode"; for (DXCoilIndex = 1; DXCoilIndex <= state.dataDXCoils->NumDXMulModeCoils; ++DXCoilIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - DXCoilIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(DXCoilIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; ++DXCoilNum; @@ -1445,22 +1981,8 @@ void GetDXCoils(EnergyPlusData &state) TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes"); // A5; \field Crankcase Heater Capacity Function of Outdoor Temperature Curve Name - if (!lAlphaBlanks(5)) { - thisDXCoil.CrankcaseHeaterCapacityCurveIndex = Curve::GetCurveIndex(state, Alphas(5)); - if (thisDXCoil.CrankcaseHeaterCapacityCurveIndex == 0) { // can't find the curve - ShowSevereError(state, - EnergyPlus::format("{} = {}: {} not found = {}", CurrentModuleObject, thisDXCoil.Name, cAlphaFields(5), Alphas(5))); - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CrankcaseHeaterCapacityCurveIndex, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(5)); // Field Name - } - } + setupCrankcaseHeaterCapacityCurve( + state, thisDXCoil, lAlphaBlanks(5), Alphas(5), ErrorsFound, RoutineName, CurrentModuleObject, cAlphaFields(5)); // Set crankcase heater capacity thisDXCoil.CrankcaseHeaterCapacity = Numbers(1); @@ -1704,42 +2226,14 @@ void GetDXCoils(EnergyPlusData &state) if (!ErrorsFound) { // Test PLF curve minimum and maximum. Cap if less than 0.7 or greater than 1.0. - MinCurveVal = 999.0; - MaxCurveVal = -999.0; - CurveInput = 0.0; - while (CurveInput <= 1.0) { - CurveVal = CurveValue(state, thisDXCoil.PLFFPLR(PerfModeNum), CurveInput); - if (CurveVal < MinCurveVal) { - MinCurveVal = CurveVal; - MinCurvePLR = CurveInput; - } - if (CurveVal > MaxCurveVal) { - MaxCurveVal = CurveVal; - MaxCurvePLR = CurveInput; - } - CurveInput += 0.01; - } - if (MinCurveVal < 0.7) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, PerfObjectType, PerfObjectName)); - ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", cAlphaFields2(6), Alphas2(6))); - ShowContinueError(state, - EnergyPlus::format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", - MinCurvePLR, - MinCurveVal)); - ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues."); - Curve::SetCurveOutputMinValue(state, thisDXCoil.PLFFPLR(PerfModeNum), ErrorsFound, 0.7); - } - - if (MaxCurveVal > 1.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, PerfObjectType, PerfObjectName)); - ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", cAlphaFields2(6), Alphas2(6))); - ShowContinueError(state, - EnergyPlus::format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", - MaxCurvePLR, - MaxCurveVal)); - ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues."); - Curve::SetCurveOutputMaxValue(state, thisDXCoil.PLFFPLR(PerfModeNum), ErrorsFound, 1.0); - } + validateAndCapPLFCurve(state, + thisDXCoil.PLFFPLR(PerfModeNum), + ErrorsFound, + RoutineName, + PerfObjectType, + PerfObjectName, + cAlphaFields2(6), + Alphas2(6)); } } @@ -1880,33 +2374,11 @@ void GetDXCoils(EnergyPlusData &state) // Get Water System tank connections // A14, \field Name of Water Storage Tank for Supply thisDXCoil.EvapWaterSupplyName = Alphas(14); - if (lAlphaBlanks(14)) { - thisDXCoil.EvapWaterSupplyMode = EvapWaterSupply::FromMains; - } else { - thisDXCoil.EvapWaterSupplyMode = EvapWaterSupply::FromTank; - SetupTankDemandComponent(state, - thisDXCoil.Name, - CurrentModuleObject, - thisDXCoil.EvapWaterSupplyName, - ErrorsFound, - thisDXCoil.EvapWaterSupTankID, - thisDXCoil.EvapWaterTankDemandARRID); - } + setupEvapWaterSupplyTank(state, thisDXCoil, lAlphaBlanks(14), CurrentModuleObject, ErrorsFound); // A15; \field Name of Water Storage Tank for Condensate Collection thisDXCoil.CondensateCollectName = Alphas(15); - if (lAlphaBlanks(15)) { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::Discard; - } else { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::ToTank; - SetupTankSupplyComponent(state, - thisDXCoil.Name, - CurrentModuleObject, - thisDXCoil.CondensateCollectName, - ErrorsFound, - thisDXCoil.CondensateTankID, - thisDXCoil.CondensateTankSupplyARRID); - } + setupCondensateTankSupply(state, thisDXCoil, lAlphaBlanks(15), CurrentModuleObject, ErrorsFound); // Set minimum OAT for compressor operation thisDXCoil.MinOATCompressor = Numbers(5); @@ -1915,40 +2387,11 @@ void GetDXCoils(EnergyPlusData &state) } // Basin heater power as a function of temperature must be greater than or equal to 0 - thisDXCoil.BasinHeaterPowerFTempDiff = Numbers(6); - if (Numbers(6) < 0.0) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} must be >= 0.", cNumericFields(6))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(6))); - ErrorsFound = true; - } - - thisDXCoil.BasinHeaterSetPointTemp = Numbers(7); - if (thisDXCoil.BasinHeaterPowerFTempDiff > 0.0) { - if (NumNumbers < 7) { - thisDXCoil.BasinHeaterSetPointTemp = 2.0; - } - if (thisDXCoil.BasinHeaterSetPointTemp < 2.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", freeze possible", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} is < 2 {{C}}. Freezing could occur.", cNumericFields(7))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(7))); - } - } - - if (!lAlphaBlanks(16)) { - if ((thisDXCoil.basinHeaterSched = Sched::GetSchedule(state, Alphas(16))) == nullptr) { - ShowWarningItemNotFound( - state, eoh, cAlphaFields(16), Alphas(16), "Basin heater will be available to operate throughout the simulation."); - } - } + readBasinHeaterInputs(thisDXCoil, eoh, 6, 7, 16); } // end of the Multimode DX coil loop - if (ErrorsFound) { - ShowFatalError( - state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); - } + checkAndFatal(); //************* Read Heat Pump (DX Heating Coil) Input ********** CurrentModuleObject = "Coil:Heating:DX:SingleSpeed"; @@ -1956,24 +2399,11 @@ void GetDXCoils(EnergyPlusData &state) ++DXCoilNum; - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - DXCoilIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(DXCoilIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; // allocate single performance mode for numeric field strings used for sizing routine - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; + allocateSinglePerfModeNumericFields(state, DXCoilNum, MaxNumbers, cNumericFields); // ErrorsFound will be set to True if problem was found, left untouched otherwise VerifyUniqueCoilName(state, CurrentModuleObject, Alphas(1), ErrorsFound, CurrentModuleObject + " Name"); @@ -2010,218 +2440,26 @@ void GetDXCoils(EnergyPlusData &state) TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes"); - thisDXCoil.CCapFTemp(1) = GetCurveIndex(state, Alphas(5)); // convert curve name to number - if (thisDXCoil.CCapFTemp(1) == 0) { - if (lAlphaBlanks(5)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(5))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(5), Alphas(5))); - } - ErrorsFound = true; - } else { - // only legal types are Quadratic, BiQuadratic and Cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CCapFTemp(1), // Curve index - {1, 2}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(5)); // Field Name - - if (!ErrorsFound) { - if (state.dataCurveManager->curves(thisDXCoil.CCapFTemp(1))->numDims == 1) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.CCapFTemp(1), - cAlphaFields(5), - Alphas(5), - RatedOutdoorAirTempHeat); - } else { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.CCapFTemp(1), - cAlphaFields(5), - Alphas(5), - RatedInletAirTempHeat, - RatedOutdoorAirTempHeat); - } - } - } - - thisDXCoil.CCapFFlow(1) = GetCurveIndex(state, Alphas(6)); // convert curve name to number - if (thisDXCoil.CCapFFlow(1) == 0) { - if (lAlphaBlanks(6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(6), Alphas(6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CCapFFlow(1), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(6)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne( - state, std::string{RoutineName} + CurrentModuleObject, thisDXCoil.Name, thisDXCoil.CCapFFlow(1), cAlphaFields(6), Alphas(6), 1.0); - } - } - - thisDXCoil.EIRFTemp(1) = GetCurveIndex(state, Alphas(7)); // convert curve name to number - if (thisDXCoil.EIRFTemp(1) == 0) { - if (lAlphaBlanks(7)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(7))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(7), Alphas(7))); - } - ErrorsFound = true; - } else { - // only legal types are Quadratic, BiQuadratic and Cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.EIRFTemp(1), // Curve index - {1, 2}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(7)); // Field Name - - if (!ErrorsFound) { - if (state.dataCurveManager->curves(thisDXCoil.EIRFTemp(1))->numDims == 1) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.EIRFTemp(1), - cAlphaFields(7), - Alphas(7), - RatedOutdoorAirTempHeat); - } else { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.EIRFTemp(1), - cAlphaFields(7), - Alphas(7), - RatedInletAirTempHeat, - RatedOutdoorAirTempHeat); - } - } - } - - thisDXCoil.EIRFFlow(1) = GetCurveIndex(state, Alphas(8)); // convert curve name to number - if (thisDXCoil.EIRFFlow(1) == 0) { - if (lAlphaBlanks(8)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(8))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(8), Alphas(8))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic or Cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.EIRFFlow(1), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(8)); // Field Name + getAndCheck2DHeatingTempCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.CCapFTemp(1), 5, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - if (!ErrorsFound) { - checkCurveIsNormalizedToOne( - state, std::string{RoutineName} + CurrentModuleObject, thisDXCoil.Name, thisDXCoil.EIRFFlow(1), cAlphaFields(8), Alphas(8), 1.0); - } - } + getAndCheckFlowCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.CCapFFlow(1), 6, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - thisDXCoil.PLFFPLR(1) = GetCurveIndex(state, Alphas(9)); // convert curve name to number - if (thisDXCoil.PLFFPLR(1) == 0) { - if (lAlphaBlanks(9)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(9))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(9), Alphas(9))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal types are Quadratic or Cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.PLFFPLR(1), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(9)); // Field Name + getAndCheck2DHeatingTempCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.EIRFTemp(1), 7, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - if (!ErrorsFound) { - // Test PLF curve minimum and maximum. Cap if less than 0.7 or greater than 1.0. - MinCurveVal = 999.0; - MaxCurveVal = -999.0; - CurveInput = 0.0; - while (CurveInput <= 1.0) { - CurveVal = CurveValue(state, thisDXCoil.PLFFPLR(1), CurveInput); - if (CurveVal < MinCurveVal) { - MinCurveVal = CurveVal; - MinCurvePLR = CurveInput; - } - if (CurveVal > MaxCurveVal) { - MaxCurveVal = CurveVal; - MaxCurvePLR = CurveInput; - } - CurveInput += 0.01; - } - if (MinCurveVal < 0.7) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", cAlphaFields(9), Alphas(9))); - ShowContinueError( - state, EnergyPlus::format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", MinCurvePLR, MinCurveVal)); - ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues."); - Curve::SetCurveOutputMinValue(state, thisDXCoil.PLFFPLR(1), ErrorsFound, 0.7); - } + getAndCheckFlowCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.EIRFFlow(1), 8, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - if (MaxCurveVal > 1.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", cAlphaFields(9), Alphas(9))); - ShowContinueError( - state, EnergyPlus::format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", MaxCurvePLR, MaxCurveVal)); - ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues."); - Curve::SetCurveOutputMaxValue(state, thisDXCoil.PLFFPLR(1), ErrorsFound, 1.0); - } - } - } + getAndCheckPLFCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.PLFFPLR(1), 9, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); // Only required for reverse cycle heat pumps thisDXCoil.DefrostEIRFT = GetCurveIndex(state, Alphas(10)); // convert curve name to number // A11; \field Crankcase Heater Capacity Function of Outdoor Temperature Curve Name - if (!lAlphaBlanks(11)) { - thisDXCoil.CrankcaseHeaterCapacityCurveIndex = Curve::GetCurveIndex(state, Alphas(11)); - if (thisDXCoil.CrankcaseHeaterCapacityCurveIndex == 0) { // can't find the curve - ShowSevereError( - state, EnergyPlus::format("{} = {}: {} not found = {}", CurrentModuleObject, thisDXCoil.Name, cAlphaFields(11), Alphas(11))); - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CrankcaseHeaterCapacityCurveIndex, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(11)); // Field Name - } - } + setupCrankcaseHeaterCapacityCurve( + state, thisDXCoil, lAlphaBlanks(11), Alphas(11), ErrorsFound, RoutineName, CurrentModuleObject, cAlphaFields(11)); if (Util::SameString(Alphas(12), "ReverseCycle")) { @@ -2258,32 +2496,7 @@ void GetDXCoils(EnergyPlusData &state) } } - if (Util::SameString(Alphas(12), "ReverseCycle")) { - thisDXCoil.DefrostStrategy = StandardRatings::DefrostStrat::ReverseCycle; - } - if (Util::SameString(Alphas(12), "Resistive")) { - thisDXCoil.DefrostStrategy = StandardRatings::DefrostStrat::Resistive; - } - - if (thisDXCoil.DefrostStrategy == StandardRatings::DefrostStrat::Invalid) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...illegal {}=\"{}\".", cAlphaFields(12), Alphas(12))); - ShowContinueError(state, "...valid values for this field are ReverseCycle or Resistive."); - ErrorsFound = true; - } - - if (Util::SameString(Alphas(13), "Timed")) { - thisDXCoil.DefrostControl = StandardRatings::HPdefrostControl::Timed; - } - if (Util::SameString(Alphas(13), "OnDemand")) { - thisDXCoil.DefrostControl = StandardRatings::HPdefrostControl::OnDemand; - } - if (thisDXCoil.DefrostControl == StandardRatings::HPdefrostControl::Invalid) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...illegal {}=\"{}\".", cAlphaFields(13), Alphas(13))); - ShowContinueError(state, "...valid values for this field are Timed or OnDemand."); - ErrorsFound = true; - } + parseDefrostStrategyAndControl(thisDXCoil, 12, 13); thisDXCoil.RatedSHR(1) = 1.0; thisDXCoil.RatedTotCap(1) = Numbers(1); @@ -2345,30 +2558,17 @@ void GetDXCoils(EnergyPlusData &state) thisDXCoil.RatedEIR(1) = 1.0 / thisDXCoil.RatedCOP(1); - // A14 is optional evaporator node name - if (lAlphaBlanks(14)) { - thisDXCoil.CondenserInletNodeNum(1) = 0; - } else { - thisDXCoil.CondenserInletNodeNum(1) = GetOnlySingleNode(state, - Alphas(14), - ErrorsFound, - Node::ConnectionObjectType::CoilHeatingDXSingleSpeed, - thisDXCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::OutsideAirReference, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - // warn if not an outdoor node, but allow - if (!CheckOutAirNodeNumber(state, thisDXCoil.CondenserInletNodeNum(1))) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", may be invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("{}=\"{}\", node does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.", - cAlphaFields(14), - Alphas(14))); - ShowContinueError( - state, "This node needs to be included in an air system or the coil model will not be valid, and the simulation continues"); - } - } + readOutdoorCondenserNode(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.CondenserInletNodeNum(1), + 14, + Node::ConnectionObjectType::CoilHeatingDXSingleSpeed, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); // A14, \field Zone Name for Evaporator Placement if (!lAlphaBlanks(15) && NumAlphas > 14) { @@ -2423,36 +2623,19 @@ void GetDXCoils(EnergyPlusData &state) } // end of the DX heating coil loop - if (ErrorsFound) { - ShowFatalError( - state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); - } + checkAndFatal(); CurrentModuleObject = "Coil:Cooling:DX:TwoSpeed"; for (DXCoilIndex = 1; DXCoilIndex <= state.dataDXCoils->NumDXMulSpeedCoils; ++DXCoilIndex) { ++DXCoilNum; - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - DXCoilIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(DXCoilIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; // allocate single performance mode for numeric field strings used for sizing routine - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; + allocateSinglePerfModeNumericFields(state, DXCoilNum, MaxNumbers, cNumericFields); // ErrorsFound will be set to True if problem was found, left untouched otherwise VerifyUniqueCoilName(state, CurrentModuleObject, Alphas(1), ErrorsFound, CurrentModuleObject + " Name"); @@ -2507,180 +2690,22 @@ void GetDXCoils(EnergyPlusData &state) TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes"); - thisDXCoil.CCapFTemp(1) = GetCurveIndex(state, Alphas(5)); // convert curve name to number - if (thisDXCoil.CCapFTemp(1) == 0) { - if (lAlphaBlanks(5)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(5))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(5), Alphas(5))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CCapFTemp(1), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(5)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.CCapFTemp(1), - cAlphaFields(5), - Alphas(5), - RatedInletWetBulbTemp, - RatedOutdoorAirTemp); - } - } + getAndCheck2DCoolingTempCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.CCapFTemp(1), 5, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - thisDXCoil.CCapFFlow(1) = GetCurveIndex(state, Alphas(6)); // convert curve name to number - if (thisDXCoil.CCapFFlow(1) == 0) { - if (lAlphaBlanks(6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(6), Alphas(6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CCapFFlow(1), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(6)); // Field Name + getAndCheckFlowCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.CCapFFlow(1), 6, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - if (!ErrorsFound) { - checkCurveIsNormalizedToOne( - state, std::string{RoutineName} + CurrentModuleObject, thisDXCoil.Name, thisDXCoil.CCapFFlow(1), cAlphaFields(6), Alphas(6), 1.0); - } - } + getAndCheck2DCoolingTempCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.EIRFTemp(1), 7, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - thisDXCoil.EIRFTemp(1) = GetCurveIndex(state, Alphas(7)); // convert curve name to number - if (thisDXCoil.EIRFTemp(1) == 0) { - if (lAlphaBlanks(7)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(7))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(7), Alphas(7))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.EIRFTemp(1), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(7)); // Field Name + getAndCheckFlowCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.EIRFFlow(1), 8, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.EIRFTemp(1), - cAlphaFields(7), - Alphas(7), - RatedInletWetBulbTemp, - RatedOutdoorAirTemp); - } - } + getAndCheckPLFCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.PLFFPLR(1), 9, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - thisDXCoil.EIRFFlow(1) = GetCurveIndex(state, Alphas(8)); // convert curve name to number - if (thisDXCoil.EIRFFlow(1) == 0) { - if (lAlphaBlanks(8)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(8))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(8), Alphas(8))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.EIRFFlow(1), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(8)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne( - state, std::string{RoutineName} + CurrentModuleObject, thisDXCoil.Name, thisDXCoil.EIRFFlow(1), cAlphaFields(8), Alphas(8), 1.0); - } - } - - thisDXCoil.PLFFPLR(1) = GetCurveIndex(state, Alphas(9)); // convert curve name to number - if (thisDXCoil.PLFFPLR(1) == 0) { - if (lAlphaBlanks(9)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(9))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(9), Alphas(9))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal types are Quadratic or Cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.PLFFPLR(1), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(9)); // Field Name - - if (!ErrorsFound) { - // Test PLF curve minimum and maximum. Cap if less than 0.7 or greater than 1.0. - MinCurveVal = 999.0; - MaxCurveVal = -999.0; - CurveInput = 0.0; - while (CurveInput <= 1.0) { - CurveVal = CurveValue(state, thisDXCoil.PLFFPLR(1), CurveInput); - if (CurveVal < MinCurveVal) { - MinCurveVal = CurveVal; - MinCurvePLR = CurveInput; - } - if (CurveVal > MaxCurveVal) { - MaxCurveVal = CurveVal; - MaxCurvePLR = CurveInput; - } - CurveInput += 0.01; - } - if (MinCurveVal < 0.7) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", cAlphaFields(9), Alphas(9))); - ShowContinueError( - state, EnergyPlus::format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", MinCurvePLR, MinCurveVal)); - ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues."); - Curve::SetCurveOutputMinValue(state, thisDXCoil.PLFFPLR(1), ErrorsFound, 0.7); - } - - if (MaxCurveVal > 1.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", cAlphaFields(9), Alphas(9))); - ShowContinueError( - state, EnergyPlus::format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", MaxCurvePLR, MaxCurveVal)); - ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues."); - Curve::SetCurveOutputMaxValue(state, thisDXCoil.PLFFPLR(1), ErrorsFound, 1.0); - } - } - } - - thisDXCoil.RatedEIR(1) = 1.0 / thisDXCoil.RatedCOP(1); + thisDXCoil.RatedEIR(1) = 1.0 / thisDXCoil.RatedCOP(1); thisDXCoil.RatedTotCap2 = Numbers(8); thisDXCoil.RatedSHR2 = Numbers(9); @@ -2696,129 +2721,27 @@ void GetDXCoils(EnergyPlusData &state) thisDXCoil.MinOATCompressor = Numbers(14); } - thisDXCoil.CCapFTemp2 = GetCurveIndex(state, Alphas(10)); // convert curve name to number - if (thisDXCoil.CCapFTemp2 == 0) { - if (lAlphaBlanks(10)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(10))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(10), Alphas(10))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CCapFTemp2, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(10)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.CCapFTemp2, - cAlphaFields(10), - Alphas(10), - RatedInletWetBulbTemp, - RatedOutdoorAirTemp); - } - } - - thisDXCoil.EIRFTemp2 = GetCurveIndex(state, Alphas(11)); // convert curve name to number - if (thisDXCoil.EIRFTemp2 == 0) { - if (lAlphaBlanks(11)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(11))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(11), Alphas(11))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.EIRFTemp2, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(11)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.EIRFTemp2, - cAlphaFields(11), - Alphas(11), - RatedInletWetBulbTemp, - RatedOutdoorAirTemp); - } - } - - // outdoor condenser node - if (lAlphaBlanks(12)) { - thisDXCoil.CondenserInletNodeNum(1) = 0; - } else { - thisDXCoil.CondenserInletNodeNum(1) = GetOnlySingleNode(state, - Alphas(12), - ErrorsFound, - Node::ConnectionObjectType::CoilCoolingDXTwoSpeed, - thisDXCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::OutsideAirReference, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - if (!CheckOutAirNodeNumber(state, thisDXCoil.CondenserInletNodeNum(1))) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", may be invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("{}=\"{}\", node does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.", - cAlphaFields(12), - Alphas(12))); - ShowContinueError( - state, "This node needs to be included in an air system or the coil model will not be valid, and the simulation continues"); - } - } + getAndCheck2DCoolingTempCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.CCapFTemp2, 10, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - if ((Util::SameString(Alphas(13), "AirCooled")) || lAlphaBlanks(13)) { - thisDXCoil.CondenserType(1) = DataHeatBalance::RefrigCondenserType::Air; - } else if (Util::SameString(Alphas(13), "EvaporativelyCooled")) { - thisDXCoil.CondenserType(1) = DataHeatBalance::RefrigCondenserType::Evap; - thisDXCoil.ReportEvapCondVars = true; - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{}=\"{}\":", cAlphaFields(13), Alphas(13))); - ShowContinueError(state, "...must be AirCooled or EvaporativelyCooled."); - ErrorsFound = true; - } + getAndCheck2DCoolingTempCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.EIRFTemp2, 11, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); - thisDXCoil.EvapCondEffect(1) = Numbers(15); - if (thisDXCoil.EvapCondEffect(1) < 0.0 || thisDXCoil.EvapCondEffect(1) > 1.0) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} cannot be < 0.0 or > 1.0.", cNumericFields(15))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(15))); - ErrorsFound = true; - } + readOutdoorCondenserNode(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.CondenserInletNodeNum(1), + 12, + Node::ConnectionObjectType::CoilCoolingDXTwoSpeed, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); - thisDXCoil.EvapCondAirFlow(1) = Numbers(16); - if (thisDXCoil.EvapCondAirFlow(1) < 0.0 && thisDXCoil.EvapCondAirFlow(1) != AutoSize) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} cannot be < 0.0.", cNumericFields(16))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(16))); - ErrorsFound = true; - } + parseCondenserType(state, thisDXCoil, RoutineName, CurrentModuleObject, Alphas(13), cAlphaFields(13), lAlphaBlanks(13), ErrorsFound); - thisDXCoil.EvapCondPumpElecNomPower(1) = Numbers(17); - if (thisDXCoil.EvapCondPumpElecNomPower(1) < 0.0 && thisDXCoil.EvapCondPumpElecNomPower(1) != AutoSize) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} cannot be < 0.0.", cNumericFields(17))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(17))); - ErrorsFound = true; - } + readEvapCondSpeedInputs(thisDXCoil, 1, 15, 16, 17); thisDXCoil.EvapCondEffect2 = Numbers(18); if (thisDXCoil.EvapCondEffect2 < 0.0 || thisDXCoil.EvapCondEffect2 > 1.0) { @@ -2849,61 +2772,14 @@ void GetDXCoils(EnergyPlusData &state) // Get Water System tank connections // A14, \field Name of Water Storage Tank for Supply thisDXCoil.EvapWaterSupplyName = Alphas(14); - if (lAlphaBlanks(14)) { - thisDXCoil.EvapWaterSupplyMode = EvapWaterSupply::FromMains; - } else { - thisDXCoil.EvapWaterSupplyMode = EvapWaterSupply::FromTank; - SetupTankDemandComponent(state, - thisDXCoil.Name, - CurrentModuleObject, - thisDXCoil.EvapWaterSupplyName, - ErrorsFound, - thisDXCoil.EvapWaterSupTankID, - thisDXCoil.EvapWaterTankDemandARRID); - } + setupEvapWaterSupplyTank(state, thisDXCoil, lAlphaBlanks(14), CurrentModuleObject, ErrorsFound); // A15; \field Name of Water Storage Tank for Condensate Collection thisDXCoil.CondensateCollectName = Alphas(15); - if (lAlphaBlanks(15)) { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::Discard; - } else { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::ToTank; - SetupTankSupplyComponent(state, - thisDXCoil.Name, - CurrentModuleObject, - thisDXCoil.CondensateCollectName, - ErrorsFound, - thisDXCoil.CondensateTankID, - thisDXCoil.CondensateTankSupplyARRID); - } + setupCondensateTankSupply(state, thisDXCoil, lAlphaBlanks(15), CurrentModuleObject, ErrorsFound); // Basin heater power as a function of temperature must be greater than or equal to 0 - thisDXCoil.BasinHeaterPowerFTempDiff = Numbers(21); - if (Numbers(21) < 0.0) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} must be >= 0.0.", cNumericFields(21))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(21))); - ErrorsFound = true; - } - - thisDXCoil.BasinHeaterSetPointTemp = Numbers(22); - if (thisDXCoil.BasinHeaterPowerFTempDiff > 0.0) { - if (NumNumbers < 22) { - thisDXCoil.BasinHeaterSetPointTemp = 2.0; - } - if (thisDXCoil.BasinHeaterSetPointTemp < 2.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", freeze possible", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} is < 2 {{C}}. Freezing could occur.", cNumericFields(22))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(22))); - } - } - - if (!lAlphaBlanks(16)) { - if ((thisDXCoil.basinHeaterSched = Sched::GetSchedule(state, Alphas(16))) == nullptr) { - ShowWarningItemNotFound( - state, eoh, cAlphaFields(16), Alphas(16), "Basin heater will be available to operate throughout the simulation."); - } - } + readBasinHeaterInputs(thisDXCoil, eoh, 21, 22, 16); if (!lAlphaBlanks(17) && NumAlphas > 16) { thisDXCoil.SHRFTemp(1) = GetCurveIndex(state, Alphas(17)); // convert curve name to number @@ -2996,11 +2872,7 @@ void GetDXCoils(EnergyPlusData &state) } } - if (ErrorsFound) { - ShowFatalError( - state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); - } + checkAndFatal(); // Loop over the Pumped DX Water Heater Coils and get & load the data CurrentModuleObject = HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterPumped); @@ -3017,9 +2889,7 @@ void GetDXCoils(EnergyPlusData &state) s_ip->markObjectAsUsed(CurrentModuleObject, thisObjectName); // allocate single performance mode for numeric field strings used for sizing routine - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; + allocateSinglePerfModeNumericFields(state, DXCoilNum, MaxNumbers, cNumericFields); auto &thisDXCoil = state.dataDXCoils->DXCoil(DXCoilNum); thisDXCoil.Name = Util::makeUPPER(thisObjectName); @@ -3538,11 +3408,7 @@ void GetDXCoils(EnergyPlusData &state) } //} // end of the DX water heater coil loop - if (ErrorsFound) { - ShowFatalError( - state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); - } + checkAndFatal(); // Loop over the Wrapped DX Water Heater Coils and get & load the data CurrentModuleObject = HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterWrapped); auto const instances_whWrapped = s_ip->epJSON.find(CurrentModuleObject); @@ -3557,9 +3423,7 @@ void GetDXCoils(EnergyPlusData &state) s_ip->markObjectAsUsed(CurrentModuleObject, thisObjectName); // allocate single performance mode for numeric field strings used for sizing routine - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; + allocateSinglePerfModeNumericFields(state, DXCoilNum, MaxNumbers, cNumericFields); auto &thisDXCoil = state.dataDXCoils->DXCoil(DXCoilNum); thisDXCoil.Name = Util::makeUPPER(thisObjectName); @@ -3729,22 +3593,8 @@ void GetDXCoils(EnergyPlusData &state) std::string const whCapFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, "crankcase_heater_capacity_function_of_temperature_curve_name"); // Coil:WaterHeating:AirToWaterHeatPump:Wrapped - if (!whCapFTCurveName.empty()) { - thisDXCoil.CrankcaseHeaterCapacityCurveIndex = Curve::GetCurveIndex(state, whCapFTCurveName); - if (thisDXCoil.CrankcaseHeaterCapacityCurveIndex == 0) { // can't find the curve - ShowSevereError( - state, EnergyPlus::format("{} = {}: {} not found = {}", CurrentModuleObject, thisDXCoil.Name, cFieldName, whCapFTCurveName)); - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CrankcaseHeaterCapacityCurveIndex, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cFieldName); // Field Name - } - } + setupCrankcaseHeaterCapacityCurve( + state, thisDXCoil, whCapFTCurveName.empty(), whCapFTCurveName, ErrorsFound, RoutineName, CurrentModuleObject, cFieldName); cFieldName = "Evaporator Air Temperature Type for Curve Objects"; // Alphas(6) fieldValue = s_ip->getAlphaFieldValue(fields, schemaProps, "evaporator_air_temperature_type_for_curve_objects"); @@ -3958,11 +3808,7 @@ void GetDXCoils(EnergyPlusData &state) } //} // end of the DX water heater wrapped coil loop - if (ErrorsFound) { - ShowFatalError( - state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); - } + checkAndFatal(); // DX Multispeed cooling coil CurrentModuleObject = "Coil:Cooling:DX:MultiSpeed"; @@ -3970,24 +3816,11 @@ void GetDXCoils(EnergyPlusData &state) ++DXCoilNum; - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - DXCoilIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(DXCoilIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; // allocate single performance mode for numeric field strings used for sizing routine (all fields are in this object) - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; + allocateSinglePerfModeNumericFields(state, DXCoilNum, MaxNumbers, cNumericFields); // ErrorsFound will be set to True if problem was found, left untouched otherwise VerifyUniqueCoilName(state, CurrentModuleObject, Alphas(1), ErrorsFound, CurrentModuleObject + " Name"); @@ -4028,71 +3861,28 @@ void GetDXCoils(EnergyPlusData &state) TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes"); // outdoor condenser node - if (lAlphaBlanks(5)) { - thisDXCoil.CondenserInletNodeNum(1) = 0; - } else { - thisDXCoil.CondenserInletNodeNum(1) = GetOnlySingleNode(state, - Alphas(5), - ErrorsFound, - Node::ConnectionObjectType::CoilCoolingDXMultiSpeed, - thisDXCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::OutsideAirReference, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - if (!CheckOutAirNodeNumber(state, thisDXCoil.CondenserInletNodeNum(1))) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", may be invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("{}=\"{}\", node does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.", - cAlphaFields(5), - Alphas(5))); - ShowContinueError( - state, "This node needs to be included in an air system or the coil model will not be valid, and the simulation continues"); - } - } + readOutdoorCondenserNode(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.CondenserInletNodeNum(1), + 5, + Node::ConnectionObjectType::CoilCoolingDXMultiSpeed, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); - if ((Util::SameString(Alphas(6), "AirCooled")) || lAlphaBlanks(6)) { - thisDXCoil.CondenserType(1) = DataHeatBalance::RefrigCondenserType::Air; - } else if (Util::SameString(Alphas(6), "EvaporativelyCooled")) { - thisDXCoil.CondenserType(1) = DataHeatBalance::RefrigCondenserType::Evap; - thisDXCoil.ReportEvapCondVars = true; - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{}=\"{}\":", cAlphaFields(6), Alphas(6))); - ShowContinueError(state, "...must be AirCooled or EvaporativelyCooled."); - ErrorsFound = true; - } + parseCondenserType(state, thisDXCoil, RoutineName, CurrentModuleObject, Alphas(6), cAlphaFields(6), lAlphaBlanks(6), ErrorsFound); // Get Water System tank connections // A8, \field Name of Water Storage Tank for Supply thisDXCoil.EvapWaterSupplyName = Alphas(7); - if (lAlphaBlanks(7)) { - thisDXCoil.EvapWaterSupplyMode = EvapWaterSupply::FromMains; - } else { - thisDXCoil.EvapWaterSupplyMode = EvapWaterSupply::FromTank; - SetupTankDemandComponent(state, - thisDXCoil.Name, - CurrentModuleObject, - thisDXCoil.EvapWaterSupplyName, - ErrorsFound, - thisDXCoil.EvapWaterSupTankID, - thisDXCoil.EvapWaterTankDemandARRID); - } + setupEvapWaterSupplyTank(state, thisDXCoil, lAlphaBlanks(7), CurrentModuleObject, ErrorsFound); // A9; \field Name of Water Storage Tank for Condensate Collection thisDXCoil.CondensateCollectName = Alphas(8); - if (lAlphaBlanks(8)) { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::Discard; - } else { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::ToTank; - SetupTankSupplyComponent(state, - thisDXCoil.Name, - CurrentModuleObject, - thisDXCoil.CondensateCollectName, - ErrorsFound, - thisDXCoil.CondensateTankID, - thisDXCoil.CondensateTankSupplyARRID); - } + setupCondensateTankSupply(state, thisDXCoil, lAlphaBlanks(8), CurrentModuleObject, ErrorsFound); // Set minimum OAT for compressor operation thisDXCoil.MinOATCompressor = Numbers(1); @@ -4132,48 +3922,12 @@ void GetDXCoils(EnergyPlusData &state) } // Basin heater power as a function of temperature must be greater than or equal to 0 - thisDXCoil.BasinHeaterPowerFTempDiff = Numbers(4); - if (Numbers(4) < 0.0) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} must be >= 0.0, entered value=[{:.3T}].", cNumericFields(4), Numbers(4))); - ErrorsFound = true; - } - - thisDXCoil.BasinHeaterSetPointTemp = Numbers(5); - if (thisDXCoil.BasinHeaterPowerFTempDiff > 0.0) { - if (NumNumbers < 5) { - thisDXCoil.BasinHeaterSetPointTemp = 2.0; - } - if (thisDXCoil.BasinHeaterSetPointTemp < 2.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", freeze possible", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} is less than 2 {{C}}. Freezing could occur.", cNumericFields(5))); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", Numbers(5))); - } - } + readBasinHeaterPowerAndSetpoint(thisDXCoil, 4, 5); - if (!lAlphaBlanks(11)) { - thisDXCoil.CrankcaseHeaterCapacityCurveIndex = Curve::GetCurveIndex(state, Alphas(11)); - if (thisDXCoil.CrankcaseHeaterCapacityCurveIndex == 0) { // can't find the curve - ShowSevereError( - state, EnergyPlus::format("{} = {}: {} not found = {}", CurrentModuleObject, thisDXCoil.Name, cAlphaFields(11), Alphas(11))); - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CrankcaseHeaterCapacityCurveIndex, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(11)); // Field Name - } - } + setupCrankcaseHeaterCapacityCurve( + state, thisDXCoil, lAlphaBlanks(11), Alphas(11), ErrorsFound, RoutineName, CurrentModuleObject, cAlphaFields(11)); - if (!lAlphaBlanks(12)) { - if ((thisDXCoil.basinHeaterSched = Sched::GetSchedule(state, Alphas(12))) == nullptr) { - ShowWarningItemNotFound( - state, eoh, cAlphaFields(12), Alphas(12), "Basin heater will be available to operate throughout the simulation."); - } - } + readBasinHeaterSchedule(thisDXCoil, eoh, 12); // A13; \field Fuel type, Validate fuel type input thisDXCoil.FuelType = static_cast(getEnumValue(Constant::eFuelNamesUC, Alphas(13))); @@ -4186,32 +3940,17 @@ void GetDXCoils(EnergyPlusData &state) } // Allocate arrays based on the number of speeds - thisDXCoil.MSErrIndex.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSErrIndex = 0; - thisDXCoil.MSRatedTotCap.allocate(thisDXCoil.NumOfSpeeds); + allocateCommonMSArrays(thisDXCoil); + // Cooling-specific per-speed arrays thisDXCoil.MSRatedTotCapDes.allocate(thisDXCoil.NumOfSpeeds); thisDXCoil.MSRatedSHR.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSRatedCOP.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSRatedAirVolFlowRate.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSRatedAirMassFlowRate.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSRatedAirMassFlowRate = 1.0; // avoid divide by 0, will get overwritten in InitDXCoil - thisDXCoil.MSCCapFTemp.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSCCapFFlow.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSEIRFTemp.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSEIRFFlow.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSWasteHeat.allocate(thisDXCoil.NumOfSpeeds); thisDXCoil.MSEvapCondEffect.allocate(thisDXCoil.NumOfSpeeds); thisDXCoil.MSEvapCondAirFlow.allocate(thisDXCoil.NumOfSpeeds); thisDXCoil.MSEvapCondPumpElecNomPower.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSRatedCBF.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSWasteHeatFrac.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSPLFFPLR.allocate(thisDXCoil.NumOfSpeeds); thisDXCoil.MSTwet_Rated.allocate(thisDXCoil.NumOfSpeeds); thisDXCoil.MSGamma_Rated.allocate(thisDXCoil.NumOfSpeeds); thisDXCoil.MSMaxONOFFCyclesperHour.allocate(thisDXCoil.NumOfSpeeds); thisDXCoil.MSLatentCapacityTimeConstant.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSFanPowerPerEvapAirFlowRate.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSFanPowerPerEvapAirFlowRate_2023.allocate(thisDXCoil.NumOfSpeeds); for (I = 1; I <= thisDXCoil.NumOfSpeeds; ++I) { thisDXCoil.MSRatedTotCap(I) = Numbers(7 + (I - 1) * 14); @@ -4221,194 +3960,60 @@ void GetDXCoils(EnergyPlusData &state) thisDXCoil.MSFanPowerPerEvapAirFlowRate(I) = Numbers(11 + (I - 1) * 14); thisDXCoil.MSFanPowerPerEvapAirFlowRate_2023(I) = Numbers(12 + (I - 1) * 14); - thisDXCoil.MSCCapFTemp(I) = GetCurveIndex(state, Alphas(14 + (I - 1) * 6)); // convert curve name to number - if (thisDXCoil.MSCCapFTemp(I) == 0) { - if (lAlphaBlanks(14 + (I - 1) * 6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(14 + (I - 1) * 6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(14 + (I - 1) * 6), Alphas(14 + (I - 1) * 6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.MSCCapFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(14 + (I - 1) * 6)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.MSCCapFTemp(I), - cAlphaFields(14 + (I - 1) * 6), - Alphas(14 + (I - 1) * 6), - RatedInletWetBulbTemp, - RatedOutdoorAirTemp); - } - } - - thisDXCoil.MSCCapFFlow(I) = GetCurveIndex(state, Alphas(15 + (I - 1) * 6)); // convert curve name to number - if (thisDXCoil.MSCCapFFlow(I) == 0) { - if (lAlphaBlanks(15 + (I - 1) * 6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(15 + (I - 1) * 6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(15 + (I - 1) * 6), Alphas(15 + (I - 1) * 6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.MSCCapFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(15 + (I - 1) * 6)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.MSCCapFFlow(I), - cAlphaFields(15 + (I - 1) * 6), - Alphas(15 + (I - 1) * 6), - 1.0); - } - } - - thisDXCoil.MSEIRFTemp(I) = GetCurveIndex(state, Alphas(16 + (I - 1) * 6)); // convert curve name to number - if (thisDXCoil.MSEIRFTemp(I) == 0) { - if (lAlphaBlanks(16 + (I - 1) * 6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(16 + (I - 1) * 6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(16 + (I - 1) * 6), Alphas(16 + (I - 1) * 6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.MSEIRFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(16 + (I - 1) * 6)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.MSEIRFTemp(I), - cAlphaFields(16 + (I - 1) * 6), - Alphas(16 + (I - 1) * 6), - RatedInletWetBulbTemp, - RatedOutdoorAirTemp); - } - } - - thisDXCoil.MSEIRFFlow(I) = GetCurveIndex(state, Alphas(17 + (I - 1) * 6)); // convert curve name to number - if (thisDXCoil.MSEIRFFlow(I) == 0) { - if (lAlphaBlanks(17 + (I - 1) * 6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(17 + (I - 1) * 6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(17 + (I - 1) * 6), Alphas(17 + (I - 1) * 6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.MSEIRFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(17 + (I - 1) * 6)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.MSEIRFFlow(I), - cAlphaFields(17 + (I - 1) * 6), - Alphas(17 + (I - 1) * 6), - 1.0); - } - } - - thisDXCoil.MSPLFFPLR(I) = GetCurveIndex(state, Alphas(18 + (I - 1) * 6)); // convert curve name to number - if (thisDXCoil.MSPLFFPLR(I) == 0) { - if (lAlphaBlanks(18 + (I - 1) * 6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(18 + (I - 1) * 6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(18 + (I - 1) * 6), Alphas(18 + (I - 1) * 6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal types are Quadratic or Cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.MSPLFFPLR(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(18 + (I - 1) * 6)); // Field Name - - if (!ErrorsFound) { - // Test PLF curve minimum and maximum. Cap if less than 0.7 or greater than 1.0. - MinCurveVal = 999.0; - MaxCurveVal = -999.0; - CurveInput = 0.0; - while (CurveInput <= 1.0) { - CurveVal = CurveValue(state, thisDXCoil.MSPLFFPLR(I), CurveInput); - if (CurveVal < MinCurveVal) { - MinCurveVal = CurveVal; - MinCurvePLR = CurveInput; - } - if (CurveVal > MaxCurveVal) { - MaxCurveVal = CurveVal; - MaxCurvePLR = CurveInput; - } - CurveInput += 0.01; - } - if (MinCurveVal < 0.7) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} = {} has out of range value.", cAlphaFields2(18 + (I - 1) * 6), Alphas2(18 + (I - 1) * 6))); - ShowContinueError( - state, - EnergyPlus::format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", MinCurvePLR, MinCurveVal)); - ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues."); - Curve::SetCurveOutputMinValue(state, thisDXCoil.PLFFPLR(PerfModeNum), ErrorsFound, 0.7); - } + getAndCheck2DCoolingTempCurve(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.MSCCapFTemp(I), + 14 + (I - 1) * 6, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); + + getAndCheckFlowCurve(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.MSCCapFFlow(I), + 15 + (I - 1) * 6, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); + + getAndCheck2DCoolingTempCurve(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.MSEIRFTemp(I), + 16 + (I - 1) * 6, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); + + getAndCheckFlowCurve(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.MSEIRFFlow(I), + 17 + (I - 1) * 6, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); - if (MaxCurveVal > 1.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} = {} has out of range value.", cAlphaFields2(18 + (I - 1) * 6), Alphas2(18 + (I - 1) * 6))); - ShowContinueError( - state, - EnergyPlus::format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", MaxCurvePLR, MaxCurveVal)); - ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues."); - Curve::SetCurveOutputMaxValue(state, thisDXCoil.MSPLFFPLR(I), ErrorsFound, 1.0); - } - } - } + getAndCheckPLFCurve(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.MSPLFFPLR(I), + 18 + (I - 1) * 6, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); // read data for latent degradation thisDXCoil.MSTwet_Rated(I) = Numbers(13 + (I - 1) * 14); @@ -4525,11 +4130,7 @@ void GetDXCoils(EnergyPlusData &state) } } - if (ErrorsFound) { - ShowFatalError( - state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); - } + checkAndFatal(); // DX multispeed heating coil CurrentModuleObject = "Coil:Heating:DX:MultiSpeed"; @@ -4537,26 +4138,13 @@ void GetDXCoils(EnergyPlusData &state) ++DXCoilNum; - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - DXCoilIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(DXCoilIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; // *** will have to circle back to this one to fix since the multispeed coil has all fields in this coil object *** // allocate single performance mode for numeric field strings used for sizing routine - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; + allocateSinglePerfModeNumericFields(state, DXCoilNum, MaxNumbers, cNumericFields); // ErrorsFound will be set to True if problem was found, left untouched otherwise VerifyUniqueCoilName(state, CurrentModuleObject, Alphas(1), ErrorsFound, CurrentModuleObject + " Name"); @@ -4612,35 +4200,15 @@ void GetDXCoils(EnergyPlusData &state) // Set crankcase heater cutout temperature thisDXCoil.MaxOATCrankcaseHeater = Numbers(4); - if (!lAlphaBlanks(5)) { - thisDXCoil.CrankcaseHeaterCapacityCurveIndex = Curve::GetCurveIndex(state, Alphas(5)); - if (thisDXCoil.CrankcaseHeaterCapacityCurveIndex == 0) { // can't find the curve - ShowSevereError(state, - EnergyPlus::format("{} = {}: {} not found = {}", CurrentModuleObject, thisDXCoil.Name, cAlphaFields(5), Alphas(5))); - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CrankcaseHeaterCapacityCurveIndex, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(5)); // Field Name - } - } + setupCrankcaseHeaterCapacityCurve( + state, thisDXCoil, lAlphaBlanks(5), Alphas(5), ErrorsFound, RoutineName, CurrentModuleObject, cAlphaFields(5)); // Only required for reverse cycle heat pumps thisDXCoil.DefrostEIRFT = GetCurveIndex(state, Alphas(6)); // convert curve name to number if (Util::SameString(Alphas(7), "ReverseCycle")) { if (thisDXCoil.DefrostEIRFT == 0) { - if (lAlphaBlanks(6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(6), Alphas(6))); - } - ErrorsFound = true; + reportMissingOrInvalidCurve( + state, lAlphaBlanks(6), RoutineName, CurrentModuleObject, thisDXCoil.Name, cAlphaFields(6), Alphas(6), ErrorsFound); } else { // Verify Curve Object, only legal type is BiQuadratic ErrorsFound |= Curve::CheckCurveDims(state, @@ -4664,31 +4232,7 @@ void GetDXCoils(EnergyPlusData &state) } } - if (Util::SameString(Alphas(7), "ReverseCycle")) { - thisDXCoil.DefrostStrategy = StandardRatings::DefrostStrat::ReverseCycle; - } - if (Util::SameString(Alphas(7), "Resistive")) { - thisDXCoil.DefrostStrategy = StandardRatings::DefrostStrat::Resistive; - } - if (thisDXCoil.DefrostStrategy == StandardRatings::DefrostStrat::Invalid) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...illegal {}=\"{}\".", cAlphaFields(7), Alphas(7))); - ShowContinueError(state, "...valid values for this field are ReverseCycle or Resistive."); - ErrorsFound = true; - } - - if (Util::SameString(Alphas(8), "Timed")) { - thisDXCoil.DefrostControl = StandardRatings::HPdefrostControl::Timed; - } - if (Util::SameString(Alphas(8), "OnDemand")) { - thisDXCoil.DefrostControl = StandardRatings::HPdefrostControl::OnDemand; - } - if (thisDXCoil.DefrostControl == StandardRatings::HPdefrostControl::Invalid) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...illegal {}=\"{}\".", cAlphaFields(8), Alphas(8))); - ShowContinueError(state, "...valid values for this field are Timed or OnDemand."); - ErrorsFound = true; - } + parseDefrostStrategyAndControl(thisDXCoil, 7, 8); // Set maximum outdoor temp for defrost to occur thisDXCoil.MaxOATDefrost = Numbers(5); @@ -4730,23 +4274,8 @@ void GetDXCoils(EnergyPlusData &state) } // Allocate arrays based on the number of speeds - thisDXCoil.MSErrIndex.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSErrIndex = 0; - thisDXCoil.MSRatedTotCap.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSRatedCOP.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSRatedAirVolFlowRate.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSRatedAirMassFlowRate.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSRatedAirMassFlowRate = 1.0; // avoid divide by 0, will get overwritten in InitDXCoil - thisDXCoil.MSCCapFTemp.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSCCapFFlow.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSEIRFTemp.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSEIRFFlow.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSWasteHeat.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSPLFFPLR.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSRatedCBF.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSWasteHeatFrac.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSFanPowerPerEvapAirFlowRate.allocate(thisDXCoil.NumOfSpeeds); - thisDXCoil.MSFanPowerPerEvapAirFlowRate_2023.allocate(thisDXCoil.NumOfSpeeds); + allocateCommonMSArrays(thisDXCoil); + // Heating-specific per-speed arrays thisDXCoil.MSSecCoilSHRFT.allocate(thisDXCoil.NumOfSpeeds); thisDXCoil.MSSecCoilSHRFF.allocate(thisDXCoil.NumOfSpeeds); thisDXCoil.MSSecCoilAirFlow.allocate(thisDXCoil.NumOfSpeeds); @@ -4763,213 +4292,60 @@ void GetDXCoils(EnergyPlusData &state) thisDXCoil.MSFanPowerPerEvapAirFlowRate_2023(I) = Numbers(14 + (I - 1) * 6); thisDXCoil.MSWasteHeatFrac(I) = Numbers(15 + (I - 1) * 6); - thisDXCoil.MSCCapFTemp(I) = GetCurveIndex(state, Alphas(11 + (I - 1) * 6)); // convert curve name to number - if (thisDXCoil.MSCCapFTemp(I) == 0) { - ShowSevereError(state, - EnergyPlus::format("{}, \"{}\" {} not found:{}", - CurrentModuleObject, - thisDXCoil.Name, - cAlphaFields(11 + (I - 1) * 6), - Alphas(11 + (I - 1) * 6))); - ErrorsFound = true; - } else { - // only legal types are Quadratic, BiQuadratic and Cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.MSCCapFTemp(I), // Curve index - {1, 2}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(11 + (I - 1) * 6)); // Field Name - - if (!ErrorsFound) { - if (state.dataCurveManager->curves(thisDXCoil.MSCCapFTemp(I))->numDims == 1) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.MSCCapFTemp(I), - cAlphaFields(11 + (I - 1) * 6), - Alphas(11 + (I - 1) * 6), - RatedOutdoorAirTempHeat); - } else { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.MSCCapFTemp(I), - cAlphaFields(11 + (I - 1) * 6), - Alphas(11 + (I - 1) * 6), - RatedInletAirTempHeat, - RatedOutdoorAirTempHeat); - } - } - } - - thisDXCoil.MSCCapFFlow(I) = GetCurveIndex(state, Alphas(12 + (I - 1) * 6)); // convert curve name to number - if (thisDXCoil.MSCCapFFlow(I) == 0) { - if (lAlphaBlanks(12 + (I - 1) * 6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(12 + (I - 1) * 6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(12 + (I - 1) * 6), Alphas(12 + (I - 1) * 6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.MSCCapFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(12 + (I - 1) * 6)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.MSCCapFFlow(I), - cAlphaFields(12 + (I - 1) * 6), - Alphas(12 + (I - 1) * 6), - 1.0); - } - } - - thisDXCoil.MSEIRFTemp(I) = GetCurveIndex(state, Alphas(13 + (I - 1) * 6)); // convert curve name to number - if (thisDXCoil.MSEIRFTemp(I) == 0) { - if (lAlphaBlanks(13 + (I - 1) * 6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(13 + (I - 1) * 6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(13 + (I - 1) * 6), Alphas(13 + (I - 1) * 6))); - } - ErrorsFound = true; - } else { - // only legal types are Quadratic, BiQuadratic and Cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.MSEIRFTemp(I), // Curve index - {1, 2}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(13 + (I - 1) * 6)); // Field Name - - if (!ErrorsFound) { - if (state.dataCurveManager->curves(thisDXCoil.MSEIRFTemp(I))->numDims == 1) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.MSEIRFTemp(I), - cAlphaFields(13 + (I - 1) * 6), - Alphas(13 + (I - 1) * 6), - RatedOutdoorAirTempHeat); - } else { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.MSEIRFTemp(I), - cAlphaFields(13 + (I - 1) * 6), - Alphas(13 + (I - 1) * 6), - RatedInletAirTempHeat, - RatedOutdoorAirTempHeat); - } - } - } - - thisDXCoil.MSEIRFFlow(I) = GetCurveIndex(state, Alphas(14 + (I - 1) * 6)); // convert curve name to number - if (thisDXCoil.MSEIRFFlow(I) == 0) { - if (lAlphaBlanks(14 + (I - 1) * 6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(14 + (I - 1) * 6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(14 + (I - 1) * 6), Alphas(14 + (I - 1) * 6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.MSEIRFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(14 + (I - 1) * 6)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + CurrentModuleObject, - thisDXCoil.Name, - thisDXCoil.MSEIRFFlow(I), - cAlphaFields(14 + (I - 1) * 6), - Alphas(14 + (I - 1) * 6), - 1.0); - } - } - - thisDXCoil.MSPLFFPLR(I) = GetCurveIndex(state, Alphas(15 + (I - 1) * 6)); // convert curve name to number - if (thisDXCoil.MSPLFFPLR(I) == 0) { - if (lAlphaBlanks(15 + (I - 1) * 6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(15 + (I - 1) * 6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(15 + (I - 1) * 6), Alphas(15 + (I - 1) * 6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal types are Quadratic or Cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.MSPLFFPLR(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(15 + (I - 1) * 6)); // Field Name - - if (!ErrorsFound) { - // Test PLF curve minimum and maximum. Cap if less than 0.7 or greater than 1.0. - MinCurveVal = 999.0; - MaxCurveVal = -999.0; - CurveInput = 0.0; - while (CurveInput <= 1.0) { - CurveVal = CurveValue(state, thisDXCoil.MSPLFFPLR(I), CurveInput); - if (CurveVal < MinCurveVal) { - MinCurveVal = CurveVal; - MinCurvePLR = CurveInput; - } - if (CurveVal > MaxCurveVal) { - MaxCurveVal = CurveVal; - MaxCurvePLR = CurveInput; - } - CurveInput += 0.01; - } - if (MinCurveVal < 0.7) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} = {} has out of range value.", cAlphaFields(15 + (I - 1) * 6), Alphas(15 + (I - 1) * 6))); - ShowContinueError( - state, - EnergyPlus::format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", MinCurvePLR, MinCurveVal)); - ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues."); - Curve::SetCurveOutputMinValue(state, thisDXCoil.MSPLFFPLR(I), ErrorsFound, 0.7); - } + getAndCheck2DHeatingTempCurve(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.MSCCapFTemp(I), + 11 + (I - 1) * 6, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); + + getAndCheckFlowCurve(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.MSCCapFFlow(I), + 12 + (I - 1) * 6, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); + + getAndCheck2DHeatingTempCurve(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.MSEIRFTemp(I), + 13 + (I - 1) * 6, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); + + getAndCheckFlowCurve(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.MSEIRFFlow(I), + 14 + (I - 1) * 6, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); - if (MaxCurveVal > 1.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} = {} has out of range value.", cAlphaFields(15 + (I - 1) * 6), Alphas(15 + (I - 1) * 6))); - ShowContinueError( - state, - EnergyPlus::format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", MaxCurvePLR, MaxCurveVal)); - ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues."); - Curve::SetCurveOutputMaxValue(state, thisDXCoil.MSPLFFPLR(I), ErrorsFound, 1.0); - } - } - } + getAndCheckPLFCurve(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + thisDXCoil.MSPLFFPLR(I), + 15 + (I - 1) * 6, + thisDXCoil.Name, + Alphas, + lAlphaBlanks, + cAlphaFields); // Read waste heat modifier curve name thisDXCoil.MSWasteHeat(I) = GetCurveIndex(state, Alphas(16 + (I - 1) * 6)); // convert curve name to number @@ -5046,27 +4422,14 @@ void GetDXCoils(EnergyPlusData &state) CurrentModuleObject = HVAC::cAllCoilTypes(HVAC::CoilVRF_Cooling); for (DXCoilIndex = 1; DXCoilIndex <= state.dataDXCoils->NumVRFCoolingCoils; ++DXCoilIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - DXCoilIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(DXCoilIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; ++DXCoilNum; // allocate single performance mode for numeric field strings used for sizing routine - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; + allocateSinglePerfModeNumericFields(state, DXCoilNum, MaxNumbers, cNumericFields); // ErrorsFound will be set to True if problem was found, left untouched otherwise VerifyUniqueCoilName(state, CurrentModuleObject, Alphas(1), ErrorsFound, CurrentModuleObject + " Name"); @@ -5116,31 +4479,8 @@ void GetDXCoils(EnergyPlusData &state) } } - thisDXCoil.CCapFFlow(1) = GetCurveIndex(state, Alphas(4)); // convert curve name to number - if (thisDXCoil.CCapFFlow(1) == 0) { - if (lAlphaBlanks(4)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(4))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(4), Alphas(4))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Linear, Quadratic or Cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CCapFFlow(1), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(4)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne( - state, std::string{RoutineName} + CurrentModuleObject, thisDXCoil.Name, thisDXCoil.CCapFFlow(1), cAlphaFields(4), Alphas(4), 1.0); - } - } + getAndCheckFlowCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.CCapFFlow(1), 4, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); thisDXCoil.AirInNode = GetOnlySingleNode(state, Alphas(5), @@ -5165,50 +4505,22 @@ void GetDXCoils(EnergyPlusData &state) TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(5), Alphas(6), "Air Nodes"); thisDXCoil.CondensateCollectName = Alphas(7); - if (lAlphaBlanks(7)) { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::Discard; - } else { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::ToTank; - SetupTankSupplyComponent(state, - thisDXCoil.Name, - CurrentModuleObject, - thisDXCoil.CondensateCollectName, - ErrorsFound, - thisDXCoil.CondensateTankID, - thisDXCoil.CondensateTankSupplyARRID); - } + setupCondensateTankSupply(state, thisDXCoil, lAlphaBlanks(7), CurrentModuleObject, ErrorsFound); } - if (ErrorsFound) { - ShowFatalError( - state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); - } + checkAndFatal(); // Loop over the VRF Heating Coils and get & load the data CurrentModuleObject = HVAC::cAllCoilTypes(HVAC::CoilVRF_Heating); for (DXCoilIndex = 1; DXCoilIndex <= state.dataDXCoils->NumVRFHeatingCoils; ++DXCoilIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - DXCoilIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(DXCoilIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; ++DXCoilNum; // allocate single performance mode for numeric field strings used for sizing routine - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; + allocateSinglePerfModeNumericFields(state, DXCoilNum, MaxNumbers, cNumericFields); // ErrorsFound will be set to True if problem was found, left untouched otherwise VerifyUniqueCoilName(state, CurrentModuleObject, Alphas(1), ErrorsFound, CurrentModuleObject + " Name"); @@ -5249,14 +4561,8 @@ void GetDXCoils(EnergyPlusData &state) thisDXCoil.CCapFTemp = GetCurveIndex(state, Alphas(5)); if (thisDXCoil.CCapFTemp(1) == 0) { - if (lAlphaBlanks(5)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(5))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(5), Alphas(5))); - } - ErrorsFound = true; + reportMissingOrInvalidCurve( + state, lAlphaBlanks(5), RoutineName, CurrentModuleObject, thisDXCoil.Name, cAlphaFields(5), Alphas(5), ErrorsFound); } else { ErrorsFound |= Curve::CheckCurveDims(state, thisDXCoil.CCapFTemp(1), // Curve index @@ -5282,63 +4588,23 @@ void GetDXCoils(EnergyPlusData &state) } } - thisDXCoil.CCapFFlow(1) = GetCurveIndex(state, Alphas(6)); // convert curve name to number - if (thisDXCoil.CCapFFlow(1) == 0) { - if (lAlphaBlanks(6)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(6))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(6), Alphas(6))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisDXCoil.CCapFFlow(1), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - thisDXCoil.Name, // Object Name - cAlphaFields(6)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne( - state, std::string{RoutineName} + CurrentModuleObject, thisDXCoil.Name, thisDXCoil.CCapFFlow(1), cAlphaFields(6), Alphas(6), 1.0); - } - } + getAndCheckFlowCurve( + state, ErrorsFound, RoutineName, CurrentModuleObject, thisDXCoil.CCapFFlow(1), 6, thisDXCoil.Name, Alphas, lAlphaBlanks, cAlphaFields); } - if (ErrorsFound) { - ShowFatalError( - state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); - } + checkAndFatal(); // Loop over the VRF Cooling Coils for VRF FluidTCtrl Model_zrp 2015 CurrentModuleObject = HVAC::cAllCoilTypes(HVAC::CoilVRF_FluidTCtrl_Cooling); for (DXCoilIndex = 1; DXCoilIndex <= state.dataDXCoils->NumVRFCoolingFluidTCtrlCoils; ++DXCoilIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - DXCoilIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(DXCoilIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; ++DXCoilNum; // allocate single performance mode for numeric field strings used for sizing routine - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; + allocateSinglePerfModeNumericFields(state, DXCoilNum, MaxNumbers, cNumericFields); // ErrorsFound will be set to True if problem was found, left untouched otherwise VerifyUniqueCoilName(state, CurrentModuleObject, Alphas(1), ErrorsFound, CurrentModuleObject + " Name"); @@ -5382,14 +4648,8 @@ void GetDXCoils(EnergyPlusData &state) int indexSHCurve = GetCurveIndex(state, Alphas(5)); // convert curve name to index number // Verify curve name and type if (indexSHCurve == 0) { - if (lAlphaBlanks(5)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(5))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(5), Alphas(5))); - } - ErrorsFound = true; + reportMissingOrInvalidCurve( + state, lAlphaBlanks(5), RoutineName, CurrentModuleObject, thisDXCoil.Name, cAlphaFields(5), Alphas(5), ErrorsFound); } else { { if (state.dataCurveManager->curves(indexSHCurve)->curveType == Curve::CurveType::Quadratic) { @@ -5411,50 +4671,22 @@ void GetDXCoils(EnergyPlusData &state) } thisDXCoil.CondensateCollectName = Alphas(6); - if (lAlphaBlanks(6)) { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::Discard; - } else { - thisDXCoil.CondensateCollectMode = CondensateCollectAction::ToTank; - SetupTankSupplyComponent(state, - thisDXCoil.Name, - CurrentModuleObject, - thisDXCoil.CondensateCollectName, - ErrorsFound, - thisDXCoil.CondensateTankID, - thisDXCoil.CondensateTankSupplyARRID); - } + setupCondensateTankSupply(state, thisDXCoil, lAlphaBlanks(6), CurrentModuleObject, ErrorsFound); } - if (ErrorsFound) { - ShowFatalError( - state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); - } + checkAndFatal(); // Loop over the VRF Heating Coils for VRF FluidTCtrl Model_zrp 2015 CurrentModuleObject = HVAC::cAllCoilTypes(HVAC::CoilVRF_FluidTCtrl_Heating); for (DXCoilIndex = 1; DXCoilIndex <= state.dataDXCoils->NumVRFHeatingFluidTCtrlCoils; ++DXCoilIndex) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - DXCoilIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); + getItem(DXCoilIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; ++DXCoilNum; // allocate single performance mode for numeric field strings used for sizing routine - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode.allocate(1); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames.allocate(MaxNumbers); - state.dataDXCoils->DXCoilNumericFields(DXCoilNum).PerfMode(1).FieldNames = cNumericFields; + allocateSinglePerfModeNumericFields(state, DXCoilNum, MaxNumbers, cNumericFields); // ErrorsFound will be set to True if problem was found, left untouched otherwise VerifyUniqueCoilName(state, CurrentModuleObject, Alphas(1), ErrorsFound, CurrentModuleObject + " Name"); @@ -5496,14 +4728,8 @@ void GetDXCoils(EnergyPlusData &state) int indexSCCurve = GetCurveIndex(state, Alphas(5)); // convert curve name to index number // Verify curve name and type if (indexSCCurve == 0) { - if (lAlphaBlanks(5)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...required {} is blank.", cAlphaFields(5))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...not found {}=\"{}\".", cAlphaFields(5), Alphas(5))); - } - ErrorsFound = true; + reportMissingOrInvalidCurve( + state, lAlphaBlanks(5), RoutineName, CurrentModuleObject, thisDXCoil.Name, cAlphaFields(5), Alphas(5), ErrorsFound); } else { { if (state.dataCurveManager->curves(indexSCCurve)->curveType == Curve::CurveType::Quadratic) { @@ -5525,11 +4751,7 @@ void GetDXCoils(EnergyPlusData &state) } } - if (ErrorsFound) { - ShowFatalError( - state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", RoutineName, CurrentModuleObject)); - } + checkAndFatal(); for (DXCoilNum = 1; DXCoilNum <= state.dataDXCoils->NumDXCoils; ++DXCoilNum) { @@ -5538,239 +4760,57 @@ void GetDXCoils(EnergyPlusData &state) if (thisDXCoil.DXCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed || thisDXCoil.DXCoilType_Num == HVAC::CoilDX_CoolingTwoStageWHumControl) { // Setup Report Variables for Cooling Equipment // CurrentModuleObject='Coil:Cooling:DX:SingleSpeed/Coil:Cooling:DX:TwoStageWithHumidityControlMode' + setupStdCoolingOutputVars(state, thisDXCoil); SetupOutputVariable(state, - "Cooling Coil Total Cooling Rate", - Constant::Units::W, - thisDXCoil.TotalCoolingEnergyRate, + "Cooling Coil Runtime Fraction", + Constant::Units::None, + thisDXCoil.CoolingCoilRuntimeFraction, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, thisDXCoil.Name); + setupSecondaryCoolingHeatRejectionOutputVar(state, thisDXCoil); + + // do we report these even if no storage tank? + setupCondensateTankOutputVars(state, thisDXCoil); + + if (thisDXCoil.ReportEvapCondVars) { + setupEvapCondOutputVars(state, thisDXCoil); + } + + if (thisDXCoil.DXCoilType_Num == HVAC::CoilDX_CoolingTwoStageWHumControl) { + // Setup Report Variables for Cooling Equipment + // CurrentModuleObject='Cooling:DX:TwoStageWithHumidityControlMode' + SetupOutputVariable(state, + "Cooling Coil Stage 2 Runtime Fraction", + Constant::Units::None, + thisDXCoil.CoolingCoilStg2RuntimeFrac, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Dehumidification Mode", + Constant::Units::None, + thisDXCoil.DehumidificationMode, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisDXCoil.Name); + } + + } + + else if (thisDXCoil.DXCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { + // Setup Report Variables for Heating Equipment + // CurrentModuleObject='Coil:Heating:DX:SingleSpeed' + setupStdDXHeatingOutputVars(state, thisDXCoil); SetupOutputVariable(state, - "Cooling Coil Total Cooling Energy", - Constant::Units::J, - thisDXCoil.TotalCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::CoolingCoils); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Rate", + "Heating Coil Defrost Electricity Rate", Constant::Units::W, - thisDXCoil.SensCoolingEnergyRate, + thisDXCoil.DefrostPower, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, thisDXCoil.Name); SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Energy", - Constant::Units::J, - thisDXCoil.SensCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Rate", - Constant::Units::W, - thisDXCoil.LatCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Energy", - Constant::Units::J, - thisDXCoil.LatCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Electricity Rate", - Constant::Units::W, - thisDXCoil.ElecCoolingPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Electricity Energy", - Constant::Units::J, - thisDXCoil.ElecCoolingConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - SetupOutputVariable(state, - "Cooling Coil Runtime Fraction", - Constant::Units::None, - thisDXCoil.CoolingCoilRuntimeFraction, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - if (thisDXCoil.IsSecondaryDXCoilInZone) { - SetupOutputVariable(state, - "Secondary Coil Heat Rejection Rate", - Constant::Units::W, - thisDXCoil.SecCoilSensibleHeatGainRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - } - - // do we report these even if no storage tank? - if (thisDXCoil.CondensateCollectMode == CondensateCollectAction::ToTank) { - SetupOutputVariable(state, - "Cooling Coil Condensate Volume Flow Rate", - Constant::Units::m3_s, - thisDXCoil.CondensateVdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Condensate Volume", - Constant::Units::m3, - thisDXCoil.CondensateVol, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::OnSiteWater, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Condensate); - } - - if (thisDXCoil.ReportEvapCondVars) { - SetupOutputVariable(state, - "Cooling Coil Condenser Inlet Temperature", - Constant::Units::C, - thisDXCoil.CondInletTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Water Volume", - Constant::Units::m3, - thisDXCoil.EvapWaterConsump, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Water, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Mains Supply Water Volume", - Constant::Units::m3, - thisDXCoil.EvapWaterConsump, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::MainsWater, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Pump Electricity Rate", - Constant::Units::W, - thisDXCoil.EvapCondPumpElecPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Pump Electricity Energy", - Constant::Units::J, - thisDXCoil.EvapCondPumpElecConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - if (thisDXCoil.BasinHeaterPowerFTempDiff > 0.0) { - SetupOutputVariable(state, - "Cooling Coil Basin Heater Electricity Rate", - Constant::Units::W, - thisDXCoil.BasinHeaterPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Basin Heater Electricity Energy", - Constant::Units::J, - thisDXCoil.BasinHeaterConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - } - } - - if (thisDXCoil.DXCoilType_Num == HVAC::CoilDX_CoolingTwoStageWHumControl) { - // Setup Report Variables for Cooling Equipment - // CurrentModuleObject='Cooling:DX:TwoStageWithHumidityControlMode' - SetupOutputVariable(state, - "Cooling Coil Stage 2 Runtime Fraction", - Constant::Units::None, - thisDXCoil.CoolingCoilStg2RuntimeFrac, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Dehumidification Mode", - Constant::Units::None, - thisDXCoil.DehumidificationMode, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - } - - } - - else if (thisDXCoil.DXCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { - // Setup Report Variables for Heating Equipment - // CurrentModuleObject='Coil:Heating:DX:SingleSpeed' - SetupOutputVariable(state, - "Heating Coil Heating Rate", - Constant::Units::W, - thisDXCoil.TotalHeatingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Heating Coil Heating Energy", - Constant::Units::J, - thisDXCoil.TotalHeatingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::HeatingCoils); - SetupOutputVariable(state, - "Heating Coil Electricity Rate", - Constant::Units::W, - thisDXCoil.ElecHeatingPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Heating Coil Electricity Energy", - Constant::Units::J, - thisDXCoil.ElecHeatingConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Defrost Electricity Rate", - Constant::Units::W, - thisDXCoil.DefrostPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Heating Coil Defrost Electricity Energy", + "Heating Coil Defrost Electricity Energy", Constant::Units::J, thisDXCoil.DefrostConsumption, OutputProcessor::TimeStepType::System, @@ -5779,30 +4819,7 @@ void GetDXCoils(EnergyPlusData &state) Constant::eResource::Electricity, OutputProcessor::Group::HVAC, OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Crankcase Heater Electricity Rate", - Constant::Units::W, - thisDXCoil.CrankcaseHeaterPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Heating Coil Crankcase Heater Electricity Energy", - Constant::Units::J, - thisDXCoil.CrankcaseHeaterConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Runtime Fraction", - Constant::Units::None, - thisDXCoil.HeatingCoilRuntimeFraction, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); + setupDXHeatingCrankcaseAndRuntimeOutputVars(state, thisDXCoil); if (thisDXCoil.IsSecondaryDXCoilInZone) { SetupOutputVariable(state, "Secondary Coil Total Heat Removal Rate", @@ -5862,68 +4879,7 @@ void GetDXCoils(EnergyPlusData &state) else if (thisDXCoil.DXCoilType_Num == HVAC::CoilDX_CoolingTwoSpeed) { // Setup Report Variables for Cooling Equipment // CurrentModuleObject='Coil:Cooling:DX:TwoSpeed' - SetupOutputVariable(state, - "Cooling Coil Total Cooling Rate", - Constant::Units::W, - thisDXCoil.TotalCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Total Cooling Energy", - Constant::Units::J, - thisDXCoil.TotalCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::CoolingCoils); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Rate", - Constant::Units::W, - thisDXCoil.SensCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Energy", - Constant::Units::J, - thisDXCoil.SensCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Rate", - Constant::Units::W, - thisDXCoil.LatCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Energy", - Constant::Units::J, - thisDXCoil.LatCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Electricity Rate", - Constant::Units::W, - thisDXCoil.ElecCoolingPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Electricity Energy", - Constant::Units::J, - thisDXCoil.ElecCoolingConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); + setupStdCoolingOutputVars(state, thisDXCoil); SetupOutputVariable(state, "Cooling Coil Runtime Fraction", Constant::Units::None, @@ -5931,100 +4887,12 @@ void GetDXCoils(EnergyPlusData &state) OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, thisDXCoil.Name); - if (thisDXCoil.IsSecondaryDXCoilInZone) { - SetupOutputVariable(state, - "Secondary Coil Heat Rejection Rate", - Constant::Units::W, - thisDXCoil.SecCoilSensibleHeatGainRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - } + setupSecondaryCoolingHeatRejectionOutputVar(state, thisDXCoil); - if (thisDXCoil.CondensateCollectMode == CondensateCollectAction::ToTank) { - SetupOutputVariable(state, - "Cooling Coil Condensate Volume Flow Rate", - Constant::Units::m3_s, - thisDXCoil.CondensateVdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Condensate Volume", - Constant::Units::m3, - thisDXCoil.CondensateVol, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::OnSiteWater, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Condensate); - } + setupCondensateTankOutputVars(state, thisDXCoil); if (thisDXCoil.ReportEvapCondVars) { - SetupOutputVariable(state, - "Cooling Coil Condenser Inlet Temperature", - Constant::Units::C, - thisDXCoil.CondInletTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Water Volume", - Constant::Units::m3, - thisDXCoil.EvapWaterConsump, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Water, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Mains Supply Water Volume", - Constant::Units::m3, - thisDXCoil.EvapWaterConsump, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::MainsWater, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Pump Electricity Rate", - Constant::Units::W, - thisDXCoil.EvapCondPumpElecPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Pump Electricity Energy", - Constant::Units::J, - thisDXCoil.EvapCondPumpElecConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - if (thisDXCoil.BasinHeaterPowerFTempDiff > 0.0) { - SetupOutputVariable(state, - "Cooling Coil Basin Heater Electricity Rate", - Constant::Units::W, - thisDXCoil.BasinHeaterPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Basin Heater Electricity Energy", - Constant::Units::J, - thisDXCoil.BasinHeaterConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - } + setupEvapCondOutputVars(state, thisDXCoil); } } @@ -6133,92 +5001,31 @@ void GetDXCoils(EnergyPlusData &state) thisDXCoil.TotalHeatingEnergy, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Sum, - thisDXCoil.Name); //, & - // ResourceTypeKey='ENERGYTRANSFER',EndUseKey='HEATING',GroupKey='Plant') - SetupOutputVariable(state, - "Cooling Coil Water Heating Electricity Rate", - Constant::Units::W, - thisDXCoil.ElecWaterHeatingPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Water Heating Electricity Energy", - Constant::Units::J, - thisDXCoil.ElecWaterHeatingConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::WaterSystem); // DHW - } - - else if (thisDXCoil.DXCoilType_Num == HVAC::CoilDX_MultiSpeedCooling) { - // Setup Report Variables for Cooling Equipment: - // CurrentModuleObject='Coil:Cooling:DX:MultiSpeed' - SetupOutputVariable(state, - "Cooling Coil Total Cooling Rate", - Constant::Units::W, - thisDXCoil.TotalCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Total Cooling Energy", - Constant::Units::J, - thisDXCoil.TotalCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::CoolingCoils); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Rate", - Constant::Units::W, - thisDXCoil.SensCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Energy", - Constant::Units::J, - thisDXCoil.SensCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Rate", - Constant::Units::W, - thisDXCoil.LatCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Energy", - Constant::Units::J, - thisDXCoil.LatCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name); + thisDXCoil.Name); //, & + // ResourceTypeKey='ENERGYTRANSFER',EndUseKey='HEATING',GroupKey='Plant') SetupOutputVariable(state, - "Cooling Coil Electricity Rate", + "Cooling Coil Water Heating Electricity Rate", Constant::Units::W, - thisDXCoil.ElecCoolingPower, + thisDXCoil.ElecWaterHeatingPower, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, thisDXCoil.Name); SetupOutputVariable(state, - "Cooling Coil Electricity Energy", + "Cooling Coil Water Heating Electricity Energy", Constant::Units::J, - thisDXCoil.ElecCoolingConsumption, + thisDXCoil.ElecWaterHeatingConsumption, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Sum, thisDXCoil.Name, Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); + OutputProcessor::Group::Plant, + OutputProcessor::EndUseCat::WaterSystem); // DHW + } + + else if (thisDXCoil.DXCoilType_Num == HVAC::CoilDX_MultiSpeedCooling) { + // Setup Report Variables for Cooling Equipment: + // CurrentModuleObject='Coil:Cooling:DX:MultiSpeed' + setupStdCoolingOutputVars(state, thisDXCoil); if (thisDXCoil.FuelType != Constant::eFuel::Electricity) { std::string_view sFuelType = Constant::eFuelNames[static_cast(thisDXCoil.FuelType)]; @@ -6250,119 +5057,16 @@ void GetDXCoils(EnergyPlusData &state) thisDXCoil.Name); if (thisDXCoil.ReportEvapCondVars) { - SetupOutputVariable(state, - "Cooling Coil Condenser Inlet Temperature", - Constant::Units::C, - thisDXCoil.CondInletTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Water Volume", - Constant::Units::m3, - thisDXCoil.EvapWaterConsump, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Water, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Mains Supply Water Volume", - Constant::Units::m3, - thisDXCoil.EvapWaterConsump, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::MainsWater, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Pump Electricity Rate", - Constant::Units::W, - thisDXCoil.EvapCondPumpElecPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Evaporative Condenser Pump Electricity Energy", - Constant::Units::J, - thisDXCoil.EvapCondPumpElecConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - if (thisDXCoil.BasinHeaterPowerFTempDiff > 0.0) { - SetupOutputVariable(state, - "Cooling Coil Basin Heater Electricity Rate", - Constant::Units::W, - thisDXCoil.BasinHeaterPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Basin Heater Electricity Energy", - Constant::Units::J, - thisDXCoil.BasinHeaterConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - } - } - if (thisDXCoil.IsSecondaryDXCoilInZone) { - SetupOutputVariable(state, - "Secondary Coil Heat Rejection Rate", - Constant::Units::W, - thisDXCoil.SecCoilSensibleHeatGainRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); + setupEvapCondOutputVars(state, thisDXCoil); } + setupSecondaryCoolingHeatRejectionOutputVar(state, thisDXCoil); } else if (thisDXCoil.DXCoilType_Num == HVAC::CoilDX_MultiSpeedHeating) { // Setup Report Variables for Heating Equipment: // CurrentModuleObject='Coil:Heating:DX:MultiSpeed' - SetupOutputVariable(state, - "Heating Coil Heating Rate", - Constant::Units::W, - thisDXCoil.TotalHeatingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Heating Coil Heating Energy", - Constant::Units::J, - thisDXCoil.TotalHeatingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::HeatingCoils); - SetupOutputVariable(state, - "Heating Coil Electricity Rate", - Constant::Units::W, - thisDXCoil.ElecHeatingPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Heating Coil Electricity Energy", - Constant::Units::J, - thisDXCoil.ElecHeatingConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); + setupStdDXHeatingOutputVars(state, thisDXCoil); if (thisDXCoil.FuelType != Constant::eFuel::Electricity) { std::string_view sFuelType = Constant::eFuelNames[static_cast(thisDXCoil.FuelType)]; @@ -6424,30 +5128,7 @@ void GetDXCoils(EnergyPlusData &state) OutputProcessor::EndUseCat::Heating); } - SetupOutputVariable(state, - "Heating Coil Crankcase Heater Electricity Rate", - Constant::Units::W, - thisDXCoil.CrankcaseHeaterPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Heating Coil Crankcase Heater Electricity Energy", - Constant::Units::J, - thisDXCoil.CrankcaseHeaterConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Runtime Fraction", - Constant::Units::None, - thisDXCoil.HeatingCoilRuntimeFraction, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); + setupDXHeatingCrankcaseAndRuntimeOutputVars(state, thisDXCoil); if (thisDXCoil.IsSecondaryDXCoilInZone) { SetupOutputVariable(state, @@ -6496,190 +5177,47 @@ void GetDXCoils(EnergyPlusData &state) "[]", thisDXCoil.FrostHeatingInputPowerMultiplierEMSOverrideOn, thisDXCoil.FrostHeatingInputPowerMultiplierEMSOverrideValue); - } - } - - // VRF cooling coil report variables - else if (thisDXCoil.DXCoilType_Num == HVAC::CoilVRF_Cooling) { - // Setup Report Variables for Cooling Equipment: - // CurrentModuleObject='Coil:Cooling:DX:VariableRefrigerantFlow - SetupOutputVariable(state, - "Cooling Coil Total Cooling Rate", - Constant::Units::W, - thisDXCoil.TotalCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Total Cooling Energy", - Constant::Units::J, - thisDXCoil.TotalCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::CoolingCoils); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Rate", - Constant::Units::W, - thisDXCoil.SensCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Energy", - Constant::Units::J, - thisDXCoil.SensCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Rate", - Constant::Units::W, - thisDXCoil.LatCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Energy", - Constant::Units::J, - thisDXCoil.LatCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Runtime Fraction", - Constant::Units::None, - thisDXCoil.CoolingCoilRuntimeFraction, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - if (thisDXCoil.CondensateCollectMode == CondensateCollectAction::ToTank) { - SetupOutputVariable(state, - "Cooling Coil Condensate Volume Flow Rate", - Constant::Units::m3_s, - thisDXCoil.CondensateVdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Condensate Volume", - Constant::Units::m3, - thisDXCoil.CondensateVol, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::OnSiteWater, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Condensate); - } - } - - // VRF heating coil report variables - else if (thisDXCoil.DXCoilType_Num == HVAC::CoilVRF_Heating) { - // Setup Report Variables for Heating Equipment: - // CurrentModuleObject='Coil:Heating:DX:VariableRefrigerantFlow - SetupOutputVariable(state, - "Heating Coil Heating Rate", - Constant::Units::W, - thisDXCoil.TotalHeatingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Heating Coil Heating Energy", - Constant::Units::J, - thisDXCoil.TotalHeatingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::HeatingCoils); - SetupOutputVariable(state, - "Heating Coil Runtime Fraction", - Constant::Units::None, - thisDXCoil.HeatingCoilRuntimeFraction, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - - if (state.dataGlobal->AnyEnergyManagementSystemInModel) { - SetupEMSActuator(state, - thisDXCoil.DXCoilType, - thisDXCoil.Name, - "Frost Heating Capacity Multiplier", - "[]", - thisDXCoil.FrostHeatingCapacityMultiplierEMSOverrideOn, - thisDXCoil.FrostHeatingCapacityMultiplierEMSOverrideValue); - - SetupEMSActuator(state, - thisDXCoil.DXCoilType, - thisDXCoil.Name, - "Frost Heating Input Power Multiplier", - "[]", - thisDXCoil.FrostHeatingInputPowerMultiplierEMSOverrideOn, - thisDXCoil.FrostHeatingInputPowerMultiplierEMSOverrideValue); - } - } - - // VRF cooling coil for FluidTCtrl, report variables - else if (thisDXCoil.DXCoilType_Num == HVAC::CoilVRF_FluidTCtrl_Cooling) { - // Setup Report Variables for Cooling Equipment: - // CurrentModuleObject='Coil:Cooling:DX:VariableRefrigerantFlow:FluidTemperatureControl - SetupOutputVariable(state, - "Cooling Coil Total Cooling Rate", - Constant::Units::W, - thisDXCoil.TotalCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Total Cooling Energy", - Constant::Units::J, - thisDXCoil.TotalCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::CoolingCoils); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Rate", - Constant::Units::W, - thisDXCoil.SensCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Energy", - Constant::Units::J, - thisDXCoil.SensCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Rate", - Constant::Units::W, - thisDXCoil.LatCoolingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Energy", - Constant::Units::J, - thisDXCoil.LatCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Runtime Fraction", - Constant::Units::None, - thisDXCoil.CoolingCoilRuntimeFraction, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); + } + } + + // VRF cooling coil report variables + else if (thisDXCoil.DXCoilType_Num == HVAC::CoilVRF_Cooling) { + // Setup Report Variables for Cooling Equipment: + // CurrentModuleObject='Coil:Cooling:DX:VariableRefrigerantFlow + setupVRFCoolingOutputVars(state, thisDXCoil); + setupCondensateTankOutputVars(state, thisDXCoil); + } + + // VRF heating coil report variables + else if (thisDXCoil.DXCoilType_Num == HVAC::CoilVRF_Heating) { + // Setup Report Variables for Heating Equipment: + // CurrentModuleObject='Coil:Heating:DX:VariableRefrigerantFlow + setupVRFHeatingOutputVars(state, thisDXCoil); + + if (state.dataGlobal->AnyEnergyManagementSystemInModel) { + SetupEMSActuator(state, + thisDXCoil.DXCoilType, + thisDXCoil.Name, + "Frost Heating Capacity Multiplier", + "[]", + thisDXCoil.FrostHeatingCapacityMultiplierEMSOverrideOn, + thisDXCoil.FrostHeatingCapacityMultiplierEMSOverrideValue); + + SetupEMSActuator(state, + thisDXCoil.DXCoilType, + thisDXCoil.Name, + "Frost Heating Input Power Multiplier", + "[]", + thisDXCoil.FrostHeatingInputPowerMultiplierEMSOverrideOn, + thisDXCoil.FrostHeatingInputPowerMultiplierEMSOverrideValue); + } + } + + // VRF cooling coil for FluidTCtrl, report variables + else if (thisDXCoil.DXCoilType_Num == HVAC::CoilVRF_FluidTCtrl_Cooling) { + // Setup Report Variables for Cooling Equipment: + // CurrentModuleObject='Coil:Cooling:DX:VariableRefrigerantFlow:FluidTemperatureControl + setupVRFCoolingOutputVars(state, thisDXCoil); // Following for VRF_FluidTCtrl Only SetupOutputVariable(state, "Cooling Coil VRF Evaporating Temperature", @@ -6696,55 +5234,14 @@ void GetDXCoils(EnergyPlusData &state) OutputProcessor::StoreType::Average, thisDXCoil.Name); - if (thisDXCoil.CondensateCollectMode == CondensateCollectAction::ToTank) { - SetupOutputVariable(state, - "Cooling Coil Condensate Volume Flow Rate", - Constant::Units::m3_s, - thisDXCoil.CondensateVdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Condensate Volume", - Constant::Units::m3, - thisDXCoil.CondensateVol, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::OnSiteWater, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Condensate); - } + setupCondensateTankOutputVars(state, thisDXCoil); } // VRF heating coil for FluidTCtrl, report variables else if (thisDXCoil.DXCoilType_Num == HVAC::CoilVRF_FluidTCtrl_Heating) { // Setup Report Variables for Heating Equipment: // CurrentModuleObject='Coil:Heating:DX:VariableRefrigerantFlow:FluidTemperatureControl - SetupOutputVariable(state, - "Heating Coil Heating Rate", - Constant::Units::W, - thisDXCoil.TotalHeatingEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); - SetupOutputVariable(state, - "Heating Coil Heating Energy", - Constant::Units::J, - thisDXCoil.TotalHeatingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisDXCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::HeatingCoils); - SetupOutputVariable(state, - "Heating Coil Runtime Fraction", - Constant::Units::None, - thisDXCoil.HeatingCoilRuntimeFraction, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisDXCoil.Name); + setupVRFHeatingOutputVars(state, thisDXCoil); // Following for VRF_FluidTCtrl Only SetupOutputVariable(state, "Heating Coil VRF Condensing Temperature", @@ -7443,6 +5940,156 @@ void InitDXCoil(EnergyPlusData &state, int const DXCoilNum) // number of the cur } } +// Run AutoCalculateSizer with isEpJSON-aware string override. +static Real64 runAutoCalcSizer(EnergyPlusData &state, + std::string_view compType, + std::string_view compName, + bool printFlag, + std::string_view routineName, + Real64 tempSize, + bool &errorsFound, + std::string_view normalLabel, + std::string_view epjsonLabel) +{ + AutoCalculateSizer sizer; + std::string label(state.dataGlobal->isEpJSON ? epjsonLabel : normalLabel); + sizer.overrideSizingString(label); + sizer.initializeWithinEP(state, compType, compName, printFlag, routineName); + return sizer.size(state, tempSize, errorsFound); +} + +// Apply autosize result or compare user-specified vs design-size value with mismatch warning. +// If isAutoSize, assigns designValue to actualValue and reports. Otherwise, reports both values +// and warns if they differ by more than the hard-sizing threshold. +// The warningUserMsg and warningDesMsg are pre-formatted strings for the ShowContinueError calls. +static void applySizeResultOrReport(EnergyPlusData &state, + std::string_view coilType, + std::string_view coilName, + bool isAutoSize, + bool hardSizeNoDesRun, + Real64 designValue, + Real64 &actualValue, + std::string const &designSizeDesc, + std::string const &userSpecDesc, + std::string const &warningUserMsg, + std::string const &warningDesMsg) +{ + if (isAutoSize) { + actualValue = designValue; + BaseSizer::reportSizerOutput(state, coilType, coilName, designSizeDesc, designValue); + } else { + if (actualValue > 0.0 && designValue > 0.0 && !hardSizeNoDesRun) { + Real64 userValue = actualValue; + BaseSizer::reportSizerOutput(state, coilType, coilName, designSizeDesc, designValue, userSpecDesc, userValue); + if (state.dataGlobal->DisplayExtraWarnings) { + if ((std::abs(designValue - userValue) / userValue) > state.dataSize->AutoVsHardSizingThreshold) { + ShowMessage(state, EnergyPlus::format("SizeDxCoil: Potential issue with equipment sizing for {} {}", coilType, coilName)); + ShowContinueError(state, warningUserMsg); + ShowContinueError(state, warningDesMsg); + ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); + ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); + } + } + } + } +} + +// Validate that multispeed values are monotonically non-decreasing with speed. +// Issues a warning + fatal if value at any speed exceeds the next higher speed. +static void validateMultispeedMonotonicity(EnergyPlusData &state, + std::string_view coilType, + std::string_view coilName, + int numSpeeds, + const Array1D &values, + std::string_view fieldDescription) +{ + for (int Mode = 1; Mode <= numSpeeds - 1; ++Mode) { + if (values(Mode) > values(Mode + 1)) { + ShowWarningError(state, + EnergyPlus::format("SizeDXCoil: {} {}, Speed {} {} must be less than or equal to Speed {} {}.", + coilType, + coilName, + Mode, + fieldDescription, + Mode + 1, + fieldDescription)); + ShowContinueError(state, EnergyPlus::format("Instead, {:.2R} > {:.2R}", values(Mode), values(Mode + 1))); + ShowFatalError(state, "Preceding conditions cause termination."); + } + } +} + +// Reset all sizing state variables used by SizeDXCoil back to defaults. +// Called after each sizing sub-step to avoid stale state leaking into the next step. +static void resetDXCoilSizingState(EnergyPlusData &state) +{ + auto &ds = *state.dataSize; + ds.DataIsDXCoil = false; + ds.DataEMSOverrideON = false; + ds.DataEMSOverride = 0.0; + ds.DataBypassFrac = 0.0; + ds.DataFlowUsedForSizing = 0.0; + ds.DataCoolCoilCap = 0.0; + ds.DataTotCapCurveIndex = 0; + ds.DataConstantUsedForSizing = 0.0; + ds.DataFractionUsedForSizing = 0.0; + ds.DataTotCapCurveValue = 0.0; + ds.DataCapacityUsedForSizing = 0.0; + ds.DataDXSpeedNum = 0; +} + +// Size a multispeed evaporative condenser quantity (air flow or pump power) for all speeds. +// Computes design values based on a per-unit-capacity factor, then reports/validates via applySizeResultOrReport. +static void sizeMultispeedEvapCondField(EnergyPlusData &state, + DXCoilData const &coil, + bool HardSizeNoDesRun, + Real64 MSRatedTotCapDesAtMaxSpeed, + Array1D &fieldValues, + Real64 perCapFactor, + std::string_view designLabel, + std::string_view userLabel, + std::string_view userDiffFmt, + std::string_view desDiffFmt, + std::string_view validationLabel) +{ + for (int Mode = 1; Mode <= coil.NumOfSpeeds; ++Mode) { + bool IsAutoSize = (fieldValues(Mode) == DataSizing::AutoSize); + + Real64 desSizeValue; + if (IsAutoSize || !HardSizeNoDesRun) { + desSizeValue = ((float)Mode / coil.NumOfSpeeds) * MSRatedTotCapDesAtMaxSpeed * perCapFactor; + } else { + desSizeValue = coil.MSRatedTotCap(Mode) * perCapFactor; + } + applySizeResultOrReport(state, + coil.DXCoilType, + coil.Name, + IsAutoSize, + HardSizeNoDesRun, + desSizeValue, + fieldValues(Mode), + EnergyPlus::format(designLabel, Mode), + EnergyPlus::format(userLabel, Mode), + EnergyPlus::format(userDiffFmt, fieldValues(Mode)), + EnergyPlus::format(desDiffFmt, desSizeValue)); + } + + validateMultispeedMonotonicity(state, coil.DXCoilType, coil.Name, coil.NumOfSpeeds, fieldValues, validationLabel); +} + +// Validate that a low-speed value does not exceed the corresponding high-speed value for a two-speed coil. +// Issues a severe error + fatal if the low-speed value is greater than the high-speed value. +static void validateTwoSpeedLowVsHigh( + EnergyPlusData &state, std::string_view coilType, std::string_view coilName, Real64 lowSpeedVal, Real64 highSpeedVal, std::string_view fieldDesc) +{ + if (lowSpeedVal > highSpeedVal) { + ShowSevereError( + state, EnergyPlus::format("SizeDXCoil: {} {}, {} low speed must be less than or equal to high speed.", coilType, coilName, fieldDesc)); + ShowContinueError(state, EnergyPlus::format("Instead, {:.2R} > {:.2R}", lowSpeedVal, highSpeedVal)); + ShowFatalError(state, "Preceding conditions cause termination."); + } +} + void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) { @@ -7560,14 +6207,15 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) state.dataSize->DataConstantUsedForSizing = thisDXCoil.RatedTotCap2; state.dataSize->DataFractionUsedForSizing = 0.00005035; TempSize = AutoSize; - AutoCalculateSizer sizerHPRatedAirVolFlow; - std::string stringOverride = "Rated Evaporator Air Flow Rate [m3/s]"; - if (state.dataGlobal->isEpJSON) { - stringOverride = "rated_evaporator_air_flow_rate [m3/s]"; - } - sizerHPRatedAirVolFlow.overrideSizingString(stringOverride); - sizerHPRatedAirVolFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - thisDXCoil.RatedAirVolFlowRate(1) = sizerHPRatedAirVolFlow.size(state, TempSize, ErrorsFound); + thisDXCoil.RatedAirVolFlowRate(1) = runAutoCalcSizer(state, + CompType, + CompName, + PrintFlag, + RoutineName, + TempSize, + ErrorsFound, + "Rated Evaporator Air Flow Rate [m3/s]", + "rated_evaporator_air_flow_rate [m3/s]"); PrintFlag = false; } @@ -7580,14 +6228,15 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) state.dataSize->DataConstantUsedForSizing = thisDXCoil.RatedTotCap2; state.dataSize->DataFractionUsedForSizing = 0.00000004487; TempSize = AutoSize; - AutoCalculateSizer sizerHPWHCondWaterFlow; - std::string stringOverride = "Rated Condenser Water Flow Rate [m3/s]"; - if (state.dataGlobal->isEpJSON) { - stringOverride = "rated_condenser_water_flow_rate [m3/s]"; - } - sizerHPWHCondWaterFlow.overrideSizingString(stringOverride); - sizerHPWHCondWaterFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - thisDXCoil.RatedHPWHCondWaterFlow = sizerHPWHCondWaterFlow.size(state, TempSize, ErrorsFound); + thisDXCoil.RatedHPWHCondWaterFlow = runAutoCalcSizer(state, + CompType, + CompName, + PrintFlag, + RoutineName, + TempSize, + ErrorsFound, + "Rated Condenser Water Flow Rate [m3/s]", + "rated_condenser_water_flow_rate [m3/s]"); PrintFlag = false; } } else { @@ -7657,10 +6306,7 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); thisDXCoil.RatedAirVolFlowRate(Mode) = sizingCoolingAirFlow.size(state, TempSize, errorsFound); } - state.dataSize->DataIsDXCoil = false; - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataEMSOverride = 0.0; - state.dataSize->DataBypassFrac = 0.0; + resetDXCoilSizingState(state); } state.dataSize->DataFlowUsedForSizing = thisDXCoil.RatedAirVolFlowRate(Mode); @@ -7776,15 +6422,7 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); thisDXCoil.RatedTotCap(Mode) = sizerCoolingCapacity.size(state, TempSize, ErrorsFound); } - state.dataSize->DataIsDXCoil = false; - state.dataSize->DataFlowUsedForSizing = 0.0; - state.dataSize->DataCoolCoilCap = 0.0; - state.dataSize->DataTotCapCurveIndex = 0; - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataEMSOverride = 0.0; - state.dataSize->DataConstantUsedForSizing = 0.0; - state.dataSize->DataFractionUsedForSizing = 0.0; - state.dataSize->DataTotCapCurveValue = 0.0; + resetDXCoilSizingState(state); // Cooling coil capacity if (thisDXCoil.DXCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed || thisDXCoil.DXCoilType_Num == HVAC::CoilDX_CoolingTwoSpeed || @@ -7812,11 +6450,7 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) state.dataSize->DataEMSOverride = thisDXCoil.RatedSHREMSOverrideValue(Mode); sizerCoolingSHR.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); thisDXCoil.RatedSHR(Mode) = sizerCoolingSHR.size(state, TempSize, ErrorsFound); - state.dataSize->DataDXSpeedNum = 0; - state.dataSize->DataFlowUsedForSizing = 0.0; - state.dataSize->DataCapacityUsedForSizing = 0.0; - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataEMSOverride = 0.0; + resetDXCoilSizingState(state); } // End of Rated SHR @@ -7863,37 +6497,18 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) } // Autosize Primary Coil Air Flow * Secondary Coil Scaling Factor SecCoilAirFlowDes = thisDXCoil.RatedAirVolFlowRate(1) * thisDXCoil.SecCoilAirFlowScalingFactor; - if (IsAutoSize) { - thisDXCoil.SecCoilAirFlow = SecCoilAirFlowDes; - BaseSizer::reportSizerOutput( - state, thisDXCoil.DXCoilType, thisDXCoil.Name, "Design Size Secondary Coil Air Flow Rate [m3/s]", SecCoilAirFlowDes); - } else { - if (thisDXCoil.SecCoilAirFlow > 0.0 && SecCoilAirFlowDes > 0.0 && !HardSizeNoDesRun) { - SecCoilAirFlowUser = thisDXCoil.SecCoilAirFlow; - BaseSizer::reportSizerOutput(state, - thisDXCoil.DXCoilType, - thisDXCoil.Name, - "Design Size Secondary Coil Air Flow Rate [m3/s]", - SecCoilAirFlowDes, - "User-Specified Secondary Coil Air Flow Rate [m3/s]", - SecCoilAirFlowUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(SecCoilAirFlowDes - SecCoilAirFlowUser) / SecCoilAirFlowUser) > state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeDxCoil: Potential issue with equipment sizing for {} {}", - thisDXCoil.DXCoilType, - thisDXCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("User-Specified Secondary Coil Air Flow Rate of {:.5R} [m3/s]", SecCoilAirFlowUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Secondary Coil Air Flow Rate of {:.5R} [m3/s]", SecCoilAirFlowDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } + applySizeResultOrReport( + state, + thisDXCoil.DXCoilType, + thisDXCoil.Name, + IsAutoSize, + HardSizeNoDesRun, + SecCoilAirFlowDes, + thisDXCoil.SecCoilAirFlow, + "Design Size Secondary Coil Air Flow Rate [m3/s]", + "User-Specified Secondary Coil Air Flow Rate [m3/s]", + EnergyPlus::format("User-Specified Secondary Coil Air Flow Rate of {:.5R} [m3/s]", thisDXCoil.SecCoilAirFlow), + EnergyPlus::format("differs from Design Size Secondary Coil Air Flow Rate of {:.5R} [m3/s]", SecCoilAirFlowDes)); } // Sizing evaporative condenser air flow 2 @@ -7908,14 +6523,15 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) state.dataSize->DataConstantUsedForSizing = thisDXCoil.RatedTotCap(Mode); state.dataSize->DataFractionUsedForSizing = 0.000114 * 0.3333; TempSize = thisDXCoil.EvapCondAirFlow2; - AutoCalculateSizer sizerEvapCondAirFlow2; - std::string stringOverride = "Low Speed Evaporative Condenser Air Flow Rate [m3/s]"; - if (state.dataGlobal->isEpJSON) { - stringOverride = "low_speed_evaporative_condenser_air_flow_rate [m3/s]"; - } - sizerEvapCondAirFlow2.overrideSizingString(stringOverride); - sizerEvapCondAirFlow2.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - thisDXCoil.EvapCondAirFlow2 = sizerEvapCondAirFlow2.size(state, TempSize, ErrorsFound); + thisDXCoil.EvapCondAirFlow2 = runAutoCalcSizer(state, + CompType, + CompName, + PrintFlag, + RoutineName, + TempSize, + ErrorsFound, + "Low Speed Evaporative Condenser Air Flow Rate [m3/s]", + "low_speed_evaporative_condenser_air_flow_rate [m3/s]"); } // Sizing evaporative condenser pump electric nominal power @@ -7963,14 +6579,15 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) state.dataSize->DataConstantUsedForSizing = thisDXCoil.RatedTotCap(Mode); state.dataSize->DataFractionUsedForSizing = 0.004266 * 0.3333; TempSize = thisDXCoil.EvapCondPumpElecNomPower2; - AutoCalculateSizer sizerEvapCondPumpPower2; - std::string stringOverride = "Low Speed Evaporative Condenser Pump Rated Power Consumption [W]"; - if (state.dataGlobal->isEpJSON) { - stringOverride = "low_speed_evaporative_condenser_pump_rated_power_consumption [W]"; - } - sizerEvapCondPumpPower2.overrideSizingString(stringOverride); - sizerEvapCondPumpPower2.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - thisDXCoil.EvapCondPumpElecNomPower2 = sizerEvapCondPumpPower2.size(state, TempSize, ErrorsFound); + thisDXCoil.EvapCondPumpElecNomPower2 = runAutoCalcSizer(state, + CompType, + CompName, + PrintFlag, + RoutineName, + TempSize, + ErrorsFound, + "Low Speed Evaporative Condenser Pump Rated Power Consumption [W]", + "low_speed_evaporative_condenser_pump_rated_power_consumption [W]"); } // // Sizing rated low speed air flow rate @@ -7981,14 +6598,15 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) state.dataSize->DataConstantUsedForSizing = thisDXCoil.RatedAirVolFlowRate(Mode); state.dataSize->DataFractionUsedForSizing = 0.3333; TempSize = thisDXCoil.RatedAirVolFlowRate2; - AutoCalculateSizer sizerLowSpdAirFlow; - std::string stringOverride = "Low Speed Rated Air Flow Rate [m3/s]"; - if (state.dataGlobal->isEpJSON) { - stringOverride = "low_speed_rated_air_flow_rate [m3/s]"; - } - sizerLowSpdAirFlow.overrideSizingString(stringOverride); - sizerLowSpdAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - thisDXCoil.RatedAirVolFlowRate2 = sizerLowSpdAirFlow.size(state, TempSize, ErrorsFound); + thisDXCoil.RatedAirVolFlowRate2 = runAutoCalcSizer(state, + CompType, + CompName, + PrintFlag, + RoutineName, + TempSize, + ErrorsFound, + "Low Speed Rated Air Flow Rate [m3/s]", + "low_speed_rated_air_flow_rate [m3/s]"); } // // Sizing rated low speed total cooling capacity @@ -7999,65 +6617,42 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) state.dataSize->DataConstantUsedForSizing = thisDXCoil.RatedTotCap(Mode); state.dataSize->DataFractionUsedForSizing = 0.3333; TempSize = thisDXCoil.RatedTotCap2; - AutoCalculateSizer sizerLowSpdCap; - std::string stringOverride = "Low Speed Gross Rated Total Cooling Capacity [W]"; - if (state.dataGlobal->isEpJSON) { - stringOverride = "low_speed_gross_rated_total_cooling_capacity [W]"; - } - sizerLowSpdCap.overrideSizingString(stringOverride); - sizerLowSpdCap.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - thisDXCoil.RatedTotCap2 = sizerLowSpdCap.size(state, TempSize, ErrorsFound); + thisDXCoil.RatedTotCap2 = runAutoCalcSizer(state, + CompType, + CompName, + PrintFlag, + RoutineName, + TempSize, + ErrorsFound, + "Low Speed Gross Rated Total Cooling Capacity [W]", + "low_speed_gross_rated_total_cooling_capacity [W]"); } if (thisDXCoil.DXCoilType_Num == HVAC::CoilDX_CoolingTwoSpeed) { - if (thisDXCoil.EvapCondAirFlow2 > thisDXCoil.EvapCondAirFlow(Mode)) { - ShowSevereError( - state, - EnergyPlus::format( - "SizeDXCoil: {} {}, Evaporative Condenser low speed air flow must be less than or equal to high speed air flow.", - thisDXCoil.DXCoilType, - thisDXCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("Instead, {:.2R} > {:.2R}", thisDXCoil.EvapCondAirFlow2, thisDXCoil.EvapCondAirFlow(Mode))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - - if (thisDXCoil.EvapCondPumpElecNomPower2 > thisDXCoil.EvapCondPumpElecNomPower(Mode)) { - ShowSevereError( - state, - EnergyPlus::format( - "SizeDXCoil: {} {}, Evaporative Condenser low speed pump power must be less than or equal to high speed pump power.", - thisDXCoil.DXCoilType, - thisDXCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("Instead, {:.2R} > {:.2R}", - thisDXCoil.EvapCondPumpElecNomPower2, - thisDXCoil.EvapCondPumpElecNomPower(Mode))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - - if (thisDXCoil.RatedTotCap2 > thisDXCoil.RatedTotCap(Mode)) { - ShowSevereError( - state, - EnergyPlus::format("SizeDXCoil: {} {}, Rated Total Cooling Capacity, Low Speed must be less than or equal to Rated Total " - "Cooling Capacity, High Speed.", - thisDXCoil.DXCoilType, - thisDXCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Instead, {:.2R} > {:.2R}", thisDXCoil.RatedTotCap2, thisDXCoil.RatedTotCap(Mode))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - - if (thisDXCoil.RatedAirVolFlowRate2 > thisDXCoil.RatedAirVolFlowRate(Mode)) { - ShowFatalError( - state, - EnergyPlus::format("SizeDXCoil: {} {}, Rated Air Volume Flow Rate, low speed must be less than or equal to Rated Air Volume " - "Flow Rate, high speed.", - thisDXCoil.DXCoilType, - thisDXCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("Instead, {:.2R} > {:.2R}", thisDXCoil.RatedAirVolFlowRate2, thisDXCoil.RatedAirVolFlowRate(Mode))); - ShowFatalError(state, "Preceding conditions cause termination."); - } + validateTwoSpeedLowVsHigh(state, + thisDXCoil.DXCoilType, + thisDXCoil.Name, + thisDXCoil.EvapCondAirFlow2, + thisDXCoil.EvapCondAirFlow(Mode), + "Evaporative Condenser Air Flow Rate,"); + validateTwoSpeedLowVsHigh(state, + thisDXCoil.DXCoilType, + thisDXCoil.Name, + thisDXCoil.EvapCondPumpElecNomPower2, + thisDXCoil.EvapCondPumpElecNomPower(Mode), + "Evaporative Condenser Pump Power,"); + validateTwoSpeedLowVsHigh(state, + thisDXCoil.DXCoilType, + thisDXCoil.Name, + thisDXCoil.RatedTotCap2, + thisDXCoil.RatedTotCap(Mode), + "Rated Total Cooling Capacity,"); + validateTwoSpeedLowVsHigh(state, + thisDXCoil.DXCoilType, + thisDXCoil.Name, + thisDXCoil.RatedAirVolFlowRate2, + thisDXCoil.RatedAirVolFlowRate(Mode), + "Rated Air Volume Flow Rate,"); } // // Sizing rated low speed SHR2 @@ -8073,9 +6668,7 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) TempSize = thisDXCoil.RatedSHR2; sizerCoolingSHR.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); thisDXCoil.RatedSHR2 = sizerCoolingSHR.size(state, TempSize, ErrorsFound); - state.dataSize->DataConstantUsedForSizing = 0.0; - state.dataSize->DataFractionUsedForSizing = 0.0; - state.dataSize->DataDXSpeedNum = 0; + resetDXCoilSizingState(state); } // // Sizing resistive defrost heater capacity @@ -8090,14 +6683,15 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) state.dataSize->DataConstantUsedForSizing = state.dataSize->DXCoolCap; state.dataSize->DataFractionUsedForSizing = 1.0; TempSize = thisDXCoil.DefrostCapacity; - AutoCalculateSizer sizerResDefCap; - std::string stringOverride = "Resistive Defrost Heater Capacity [W]"; - if (state.dataGlobal->isEpJSON) { - stringOverride = "resistive_defrost_heater_capacity [W]"; - } - sizerResDefCap.overrideSizingString(stringOverride); - sizerResDefCap.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - thisDXCoil.DefrostCapacity = sizerResDefCap.size(state, TempSize, ErrorsFound); + thisDXCoil.DefrostCapacity = runAutoCalcSizer(state, + CompType, + CompName, + PrintFlag, + RoutineName, + TempSize, + ErrorsFound, + "Resistive Defrost Heater Capacity [W]", + "resistive_defrost_heater_capacity [W]"); } else { thisDXCoil.DefrostCapacity = 0.0; } @@ -8163,31 +6757,12 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName); thisDXCoil.MSRatedAirVolFlowRate(Mode) = sizingCoolingAirFlow.size(state, TempSize, errorsFound); } - state.dataSize->DataEMSOverride = 0.0; - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataIsDXCoil = false; - state.dataSize->DataTotCapCurveIndex = 0; - state.dataSize->DataConstantUsedForSizing = 0.0; - state.dataSize->DataFractionUsedForSizing = 0.0; + resetDXCoilSizingState(state); } // Ensure flow rate at lower speed must be lower or equal to the flow rate at higher speed. Otherwise, a severe error is issued. - for (Mode = 1; Mode <= thisDXCoil.NumOfSpeeds - 1; ++Mode) { - if (thisDXCoil.MSRatedAirVolFlowRate(Mode) > thisDXCoil.MSRatedAirVolFlowRate(Mode + 1)) { - ShowWarningError( - state, - EnergyPlus::format("SizeDXCoil: {} {}, Speed {} Rated Air Flow Rate must be less than or equal to Speed {} Rated Air Flow Rate.", - thisDXCoil.DXCoilType, - thisDXCoil.Name, - Mode, - Mode + 1)); - ShowContinueError(state, - EnergyPlus::format("Instead, {:.2R} > {:.2R}", - thisDXCoil.MSRatedAirVolFlowRate(Mode), - thisDXCoil.MSRatedAirVolFlowRate(Mode + 1))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - } + validateMultispeedMonotonicity( + state, thisDXCoil.DXCoilType, thisDXCoil.Name, thisDXCoil.NumOfSpeeds, thisDXCoil.MSRatedAirVolFlowRate, "Rated Air Flow Rate"); // Sizing multispeed rated total cooling capacity for (Mode = thisDXCoil.NumOfSpeeds; Mode >= 1; --Mode) { @@ -8254,31 +6829,12 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); thisDXCoil.MSRatedTotCap(Mode) = sizerCoolingCapacity.size(state, TempSize, ErrorsFound); } - state.dataSize->DataEMSOverride = 0.0; - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataIsDXCoil = false; - state.dataSize->DataCoolCoilCap = 0.0; - state.dataSize->DataTotCapCurveIndex = 0; - state.dataSize->DataConstantUsedForSizing = 0.0; - state.dataSize->DataFractionUsedForSizing = 0.0; + resetDXCoilSizingState(state); } // Ensure capacity at lower speed must be lower or equal to the capacity at higher speed. - for (Mode = 1; Mode <= thisDXCoil.NumOfSpeeds - 1; ++Mode) { - if (thisDXCoil.MSRatedTotCap(Mode) > thisDXCoil.MSRatedTotCap(Mode + 1)) { - ShowWarningError( - state, - EnergyPlus::format("SizeDXCoil: {} {}, Speed {} Rated Total Cooling Capacity must be less than or equal to Speed {} Rated " - "Total Cooling Capacity.", - thisDXCoil.DXCoilType, - thisDXCoil.Name, - Mode, - Mode + 1)); - ShowContinueError(state, - EnergyPlus::format("Instead, {:.2R} > {:.2R}", thisDXCoil.MSRatedTotCap(Mode), thisDXCoil.MSRatedTotCap(Mode + 1))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - } + validateMultispeedMonotonicity( + state, thisDXCoil.DXCoilType, thisDXCoil.Name, thisDXCoil.NumOfSpeeds, thisDXCoil.MSRatedTotCap, "Rated Total Cooling Capacity"); // Rated SHR for (Mode = thisDXCoil.NumOfSpeeds; Mode >= 1; --Mode) { @@ -8312,154 +6868,33 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) thisDXCoil.MSRatedSHR(Mode) = sizerCoolingSHR.size(state, TempSize, ErrorsFound); } } - state.dataSize->DataFlowUsedForSizing = 0.0; - state.dataSize->DataCapacityUsedForSizing = 0.0; - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataEMSOverride = 0.0; - state.dataSize->DataDXSpeedNum = 0; - state.dataSize->DataFractionUsedForSizing = 0.0; - state.dataSize->DataConstantUsedForSizing = 0.0; + resetDXCoilSizingState(state); // Rated Evaporative condenser airflow rates - for (Mode = 1; Mode <= thisDXCoil.NumOfSpeeds; ++Mode) { - IsAutoSize = false; - if (thisDXCoil.MSEvapCondAirFlow(Mode) == AutoSize) { - IsAutoSize = true; - } - if (IsAutoSize || !HardSizeNoDesRun) { - // Autosize condenser air flow to Total Capacity * 0.000114 m3/s/w (850 cfm/ton) - MSEvapCondAirFlowDes = ((float)Mode / thisDXCoil.NumOfSpeeds) * MSRatedTotCapDesAtMaxSpeed * 0.000114; - } else { - // this is done to duplicate any existing calc method - MSEvapCondAirFlowDes = thisDXCoil.MSRatedTotCap(Mode) * 0.000114; - } - if (IsAutoSize) { - thisDXCoil.MSEvapCondAirFlow(Mode) = MSEvapCondAirFlowDes; - BaseSizer::reportSizerOutput(state, - thisDXCoil.DXCoilType, - thisDXCoil.Name, - EnergyPlus::format("Design Size Speed {} Evaporative Condenser Air Flow Rate [m3/s]", Mode), - MSEvapCondAirFlowDes); - } else { - if (thisDXCoil.MSEvapCondAirFlow(Mode) > 0.0 && MSEvapCondAirFlowDes > 0.0 && !HardSizeNoDesRun) { - MSEvapCondAirFlowUser = thisDXCoil.MSEvapCondAirFlow(Mode); - BaseSizer::reportSizerOutput(state, - thisDXCoil.DXCoilType, - thisDXCoil.Name, - EnergyPlus::format("Design Size Speed {} Evaporative Condenser Air Flow Rate [m3/s]", Mode), - MSEvapCondAirFlowDes, - EnergyPlus::format("User-Specified Speed {} Evaporative Condenser Air Flow Rate [m3/s]", Mode), - MSEvapCondAirFlowUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(MSEvapCondAirFlowDes - MSEvapCondAirFlowUser) / MSEvapCondAirFlowUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format( - "SizeDxCoil: Potential issue with equipment sizing for {} {}", thisDXCoil.DXCoilType, thisDXCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("User-Specified Evaporative Condenser Air Flow Rate of {:.5R} [m3/s]", MSEvapCondAirFlowUser)); - ShowContinueError(state, - EnergyPlus::format("differs from Design Size Evaporative Condenser Air Flow Rate of {:.5R} [m3/s]", - MSEvapCondAirFlowDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } - } - - // Ensure evaporative condenser airflow rate at lower speed must be lower or equal to one at higher speed. - for (Mode = 1; Mode <= thisDXCoil.NumOfSpeeds - 1; ++Mode) { - if (thisDXCoil.MSEvapCondAirFlow(Mode) > thisDXCoil.MSEvapCondAirFlow(Mode + 1)) { - ShowWarningError( - state, - EnergyPlus::format("SizeDXCoil: {} {}, Speed {} Evaporative Condenser Air Flow Rate must be less than or equal to Speed {} " - "Evaporative Condenser Air Flow Rate.", - thisDXCoil.DXCoilType, - thisDXCoil.Name, - Mode, - Mode + 1)); - ShowContinueError( - state, - EnergyPlus::format("Instead, {:.2R} > {:.2R}", thisDXCoil.MSEvapCondAirFlow(Mode), thisDXCoil.MSEvapCondAirFlow(Mode + 1))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - } + sizeMultispeedEvapCondField(state, + thisDXCoil, + HardSizeNoDesRun, + MSRatedTotCapDesAtMaxSpeed, + thisDXCoil.MSEvapCondAirFlow, + 0.000114, + "Design Size Speed {} Evaporative Condenser Air Flow Rate [m3/s]", + "User-Specified Speed {} Evaporative Condenser Air Flow Rate [m3/s]", + "User-Specified Evaporative Condenser Air Flow Rate of {:.5R} [m3/s]", + "differs from Design Size Evaporative Condenser Air Flow Rate of {:.5R} [m3/s]", + "Evaporative Condenser Air Flow Rate"); // Sizing multispeed rated evaporative condenser pump power - for (Mode = 1; Mode <= thisDXCoil.NumOfSpeeds; ++Mode) { - IsAutoSize = false; - if (thisDXCoil.MSEvapCondPumpElecNomPower(Mode) == AutoSize) { - IsAutoSize = true; - } - - if (IsAutoSize || !HardSizeNoDesRun) { - // Autosize low speed evap condenser pump power to 1/3 Total Capacity * 0.004266 w/w (15 w/ton) - MSEvapCondPumpElecNomPowerDes = ((float)Mode / thisDXCoil.NumOfSpeeds) * MSRatedTotCapDesAtMaxSpeed * 0.004266; - } else { - // this is done to duplicate any existing calc method - MSEvapCondPumpElecNomPowerDes = thisDXCoil.MSRatedTotCap(Mode) * 0.004266; - } - // Design Size data is always available - if (IsAutoSize) { - thisDXCoil.MSEvapCondPumpElecNomPower(Mode) = MSEvapCondPumpElecNomPowerDes; - BaseSizer::reportSizerOutput(state, - thisDXCoil.DXCoilType, - thisDXCoil.Name, - EnergyPlus::format("Design Size Speed {} Rated Evaporative Condenser Pump Power Consumption [W]", Mode), - MSEvapCondPumpElecNomPowerDes); - } else { - if (thisDXCoil.MSEvapCondPumpElecNomPower(Mode) > 0.0 && MSEvapCondPumpElecNomPowerDes > 0.0 && !HardSizeNoDesRun) { - MSEvapCondPumpElecNomPowerUser = thisDXCoil.MSEvapCondPumpElecNomPower(Mode); - BaseSizer::reportSizerOutput( - state, - thisDXCoil.DXCoilType, - thisDXCoil.Name, - EnergyPlus::format("Design Size Speed {} Rated Evaporative Condenser Pump Power Consumption [W]", Mode), - MSEvapCondPumpElecNomPowerDes, - EnergyPlus::format("User-Specified Speed {} Rated Evaporative Condenser Pump Power Consumption [W]", Mode), - MSEvapCondPumpElecNomPowerUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(MSEvapCondPumpElecNomPowerDes - MSEvapCondPumpElecNomPowerUser) / MSEvapCondPumpElecNomPowerUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format( - "SizeDxCoil: Potential issue with equipment sizing for {} {}", thisDXCoil.DXCoilType, thisDXCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Evaporative Condenser Pump Rated Power Consumption of {:.2R} [W]", - MSEvapCondPumpElecNomPowerUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Evaporative Condenser Pump Rated Power Consumption of {:.2R} [W]", - MSEvapCondPumpElecNomPowerDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } - } - - // Ensure evaporative condenser pump power at lower speed must be lower or equal to one at higher speed. - for (Mode = 1; Mode <= thisDXCoil.NumOfSpeeds - 1; ++Mode) { - if (thisDXCoil.MSEvapCondPumpElecNomPower(Mode) > thisDXCoil.MSEvapCondPumpElecNomPower(Mode + 1)) { - ShowWarningError( - state, - EnergyPlus::format("SizeDXCoil: {} {}, Speed {} Rated Evaporative Condenser Pump Power Consumption must be less than or " - "equal to Speed {} Rated Evaporative Condenser Pump Power Consumption.", - thisDXCoil.DXCoilType, - thisDXCoil.Name, - Mode, - Mode + 1)); - ShowContinueError(state, - EnergyPlus::format("Instead, {:.2R} > {:.2R}", - thisDXCoil.MSEvapCondPumpElecNomPower(Mode), - thisDXCoil.MSEvapCondPumpElecNomPower(Mode + 1))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - } + sizeMultispeedEvapCondField(state, + thisDXCoil, + HardSizeNoDesRun, + MSRatedTotCapDesAtMaxSpeed, + thisDXCoil.MSEvapCondPumpElecNomPower, + 0.004266, + "Design Size Speed {} Rated Evaporative Condenser Pump Power Consumption [W]", + "User-Specified Speed {} Rated Evaporative Condenser Pump Power Consumption [W]", + "User-Specified Evaporative Condenser Pump Rated Power Consumption of {:.2R} [W]", + "differs from Design Size Evaporative Condenser Pump Rated Power Consumption of {:.2R} [W]", + "Rated Evaporative Condenser Pump Power Consumption"); } // Autosizing for multispeed heating coil @@ -8516,31 +6951,12 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName); thisDXCoil.MSRatedAirVolFlowRate(Mode) = sizingHeatingAirFlow.size(state, TempSize, errorsFound); } - state.dataSize->DataEMSOverride = 0.0; - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataIsDXCoil = false; - state.dataSize->DataTotCapCurveIndex = 0; - state.dataSize->DataConstantUsedForSizing = 0.0; - state.dataSize->DataFractionUsedForSizing = 0.0; + resetDXCoilSizingState(state); } // Ensure flow rate at lower speed must be lower or equal to the flow rate at higher speed. Otherwise, a severe error is issued. - for (Mode = 1; Mode <= thisDXCoil.NumOfSpeeds - 1; ++Mode) { - if (thisDXCoil.MSRatedAirVolFlowRate(Mode) > thisDXCoil.MSRatedAirVolFlowRate(Mode + 1)) { - ShowWarningError( - state, - EnergyPlus::format("SizeDXCoil: {} {}, Speed {} Rated Air Flow Rate must be less than or equal to Speed {} Rated Air Flow Rate.", - thisDXCoil.DXCoilType, - thisDXCoil.Name, - Mode, - Mode + 1)); - ShowContinueError(state, - EnergyPlus::format("Instead, {:.2R} > {:.2R}", - thisDXCoil.MSRatedAirVolFlowRate(Mode), - thisDXCoil.MSRatedAirVolFlowRate(Mode + 1))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - } + validateMultispeedMonotonicity( + state, thisDXCoil.DXCoilType, thisDXCoil.Name, thisDXCoil.NumOfSpeeds, thisDXCoil.MSRatedAirVolFlowRate, "Rated Air Flow Rate"); // Rated Secondary Coil Airflow Rates for AirCooled condenser type if (thisDXCoil.IsSecondaryDXCoilInZone) { for (Mode = thisDXCoil.NumOfSpeeds; Mode >= 1; --Mode) { @@ -8550,40 +6966,18 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) } // Autosize Primary Coil air flow * Secondary Coil Scaling Factor SecCoilAirFlowDes = thisDXCoil.MSRatedAirVolFlowRate(Mode) * thisDXCoil.MSSecCoilAirFlowScalingFactor(Mode); - if (IsAutoSize) { - thisDXCoil.MSSecCoilAirFlow(Mode) = SecCoilAirFlowDes; - BaseSizer::reportSizerOutput(state, - thisDXCoil.DXCoilType, - thisDXCoil.Name, - EnergyPlus::format("Design Size Speed {} Secondary Coil Air Flow Rate [m3/s]", Mode), - SecCoilAirFlowDes); - } else { - if (thisDXCoil.MSSecCoilAirFlow(Mode) > 0.0 && SecCoilAirFlowDes > 0.0 && !HardSizeNoDesRun) { - SecCoilAirFlowUser = thisDXCoil.MSSecCoilAirFlow(Mode); - BaseSizer::reportSizerOutput(state, - thisDXCoil.DXCoilType, - thisDXCoil.Name, - EnergyPlus::format("Design Size Speed {} Secondary Coil Air Flow Rate [m3/s]", Mode), - SecCoilAirFlowDes, - EnergyPlus::format("User-Specified Speed {} Secondary Coil Air Flow Rate [m3/s]", Mode), - SecCoilAirFlowUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(SecCoilAirFlowDes - SecCoilAirFlowUser) / SecCoilAirFlowUser) > state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeDxCoil: Potential issue with equipment sizing for {} {}", - thisDXCoil.DXCoilType, - thisDXCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("User-Specified Secondary Coil Air Flow Rate of {:.5R} [m3/s]", SecCoilAirFlowUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Secondary Coil Air Flow Rate of {:.5R} [m3/s]", SecCoilAirFlowDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } + applySizeResultOrReport( + state, + thisDXCoil.DXCoilType, + thisDXCoil.Name, + IsAutoSize, + HardSizeNoDesRun, + SecCoilAirFlowDes, + thisDXCoil.MSSecCoilAirFlow(Mode), + EnergyPlus::format("Design Size Speed {} Secondary Coil Air Flow Rate [m3/s]", Mode), + EnergyPlus::format("User-Specified Speed {} Secondary Coil Air Flow Rate [m3/s]", Mode), + EnergyPlus::format("User-Specified Secondary Coil Air Flow Rate of {:.5R} [m3/s]", thisDXCoil.MSSecCoilAirFlow(Mode)), + EnergyPlus::format("differs from Design Size Secondary Coil Air Flow Rate of {:.5R} [m3/s]", SecCoilAirFlowDes)); } } @@ -8658,31 +7052,11 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) thisDXCoil.MSRatedTotCap(Mode) = TempSize; } PrintFlag = false; - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataEMSOverride = 0.0; - state.dataSize->DataIsDXCoil = false; - state.dataSize->DataFlowUsedForSizing = 0.0; - state.dataSize->DataCoolCoilCap = 0.0; - state.dataSize->DataTotCapCurveIndex = 0; - state.dataSize->DataConstantUsedForSizing = 0.0; - state.dataSize->DataFractionUsedForSizing = 0.0; + resetDXCoilSizingState(state); } // Ensure capacity at lower speed must be lower or equal to the capacity at higher speed. - for (Mode = 1; Mode <= thisDXCoil.NumOfSpeeds - 1; ++Mode) { - if (thisDXCoil.MSRatedTotCap(Mode) > thisDXCoil.MSRatedTotCap(Mode + 1)) { - ShowWarningError( - state, - EnergyPlus::format("SizeDXCoil: {} {}, Speed {} Rated Total Heating Capacity must be less than or equal to Speed {} Rated " - "Total Heating Capacity.", - thisDXCoil.DXCoilType, - thisDXCoil.Name, - Mode, - Mode + 1)); - ShowContinueError(state, - EnergyPlus::format("Instead, {:.2R} > {:.2R}", thisDXCoil.MSRatedTotCap(Mode), thisDXCoil.MSRatedTotCap(Mode + 1))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - } + validateMultispeedMonotonicity( + state, thisDXCoil.DXCoilType, thisDXCoil.Name, thisDXCoil.NumOfSpeeds, thisDXCoil.MSRatedTotCap, "Rated Total Heating Capacity"); // Resistive Defrost Heater Capacity = capacity at the first stage // Sizing defrost heater capacity @@ -8815,27 +7189,16 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) case HVAC::CoilDX_MultiSpeedCooling: { PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilType, equipName, thisDXCoil.DXCoilType); if (thisDXCoil.NumOfSpeeds == 0) { - if (thisDXCoil.NumCapacityStages == 1) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilTotCap, equipName, thisDXCoil.RatedTotCap(1)); - PreDefTableEntry( - state, state.dataOutRptPredefined->pdchCoolCoilSensCap, equipName, thisDXCoil.RatedTotCap(1) * thisDXCoil.RatedSHR(1)); - PreDefTableEntry(state, - state.dataOutRptPredefined->pdchCoolCoilLatCap, - equipName, - thisDXCoil.RatedTotCap(1) - thisDXCoil.RatedTotCap(1) * thisDXCoil.RatedSHR(1)); - PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilSHR, equipName, thisDXCoil.RatedSHR(1)); - PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilNomEff, equipName, thisDXCoil.RatedCOP(1)); - } else { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilTotCap, equipName, thisDXCoil.RatedTotCap(2)); - PreDefTableEntry( - state, state.dataOutRptPredefined->pdchCoolCoilSensCap, equipName, thisDXCoil.RatedTotCap(2) * thisDXCoil.RatedSHR(2)); - PreDefTableEntry(state, - state.dataOutRptPredefined->pdchCoolCoilLatCap, - equipName, - thisDXCoil.RatedTotCap(2) - thisDXCoil.RatedTotCap(2) * thisDXCoil.RatedSHR(2)); - PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilSHR, equipName, thisDXCoil.RatedSHR(2)); - PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilNomEff, equipName, thisDXCoil.RatedCOP(2)); - } + int const idx = (thisDXCoil.NumCapacityStages == 1) ? 1 : 2; + PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilTotCap, equipName, thisDXCoil.RatedTotCap(idx)); + PreDefTableEntry( + state, state.dataOutRptPredefined->pdchCoolCoilSensCap, equipName, thisDXCoil.RatedTotCap(idx) * thisDXCoil.RatedSHR(idx)); + PreDefTableEntry(state, + state.dataOutRptPredefined->pdchCoolCoilLatCap, + equipName, + thisDXCoil.RatedTotCap(idx) - thisDXCoil.RatedTotCap(idx) * thisDXCoil.RatedSHR(idx)); + PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilSHR, equipName, thisDXCoil.RatedSHR(idx)); + PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilNomEff, equipName, thisDXCoil.RatedCOP(idx)); } else { for (Mode = 1; Mode <= thisDXCoil.NumOfSpeeds; ++Mode) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilTotCap, equipName, thisDXCoil.MSRatedTotCap(Mode)); @@ -8859,13 +7222,9 @@ void SizeDXCoil(EnergyPlusData &state, int const DXCoilNum) case HVAC::CoilDX_HeatPumpWaterHeaterWrapped: { PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilType, equipName, thisDXCoil.DXCoilType); if (thisDXCoil.NumOfSpeeds == 0) { - if (thisDXCoil.NumCapacityStages == 1) { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomCap, equipName, thisDXCoil.RatedTotCap(1)); - PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, equipName, thisDXCoil.RatedCOP(1)); - } else { - PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomCap, equipName, thisDXCoil.RatedTotCap(2)); - PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, equipName, thisDXCoil.RatedCOP(2)); - } + int const idx = (thisDXCoil.NumCapacityStages == 1) ? 1 : 2; + PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomCap, equipName, thisDXCoil.RatedTotCap(idx)); + PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, equipName, thisDXCoil.RatedCOP(idx)); } else { for (Mode = 1; Mode <= thisDXCoil.NumOfSpeeds; ++Mode) { PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomCap, equipName, thisDXCoil.MSRatedTotCap(Mode)); diff --git a/src/EnergyPlus/DesiccantDehumidifiers.cc b/src/EnergyPlus/DesiccantDehumidifiers.cc index 9fd5f774f71..440fedaf631 100644 --- a/src/EnergyPlus/DesiccantDehumidifiers.cc +++ b/src/EnergyPlus/DesiccantDehumidifiers.cc @@ -197,6 +197,106 @@ namespace DesiccantDehumidifiers { ReportDesiccantDehumidifier(state, DesicDehumNum); } + // Mine water heating coil data: index, control node, max flow, air inlet/outlet nodes. + // Sets desicDehum fields and returns true if any errors were found. + static bool mineWaterHeatingCoilData(EnergyPlusData &state, + DesiccantDehumidifierData &desicDehum, + std::string_view currentModuleObject, + std::string_view regenCoilName, + std::string_view alphaFieldName, + std::string_view routineNamePrefix = "") + { + bool anyError = false; + bool errFlag = false; + + desicDehum.RegenCoilIndex = WaterCoils::GetWaterCoilIndex(state, "COIL:HEATING:WATER", std::string(regenCoilName), errFlag); + if (desicDehum.RegenCoilIndex == 0) { + ShowSevereError(state, EnergyPlus::format("{}{} illegal {} = {}", routineNamePrefix, currentModuleObject, alphaFieldName, regenCoilName)); + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", currentModuleObject, desicDehum.Name)); + anyError = true; + } + + errFlag = false; + desicDehum.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", std::string(regenCoilName), errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", currentModuleObject, desicDehum.Name)); + anyError = true; + } + + errFlag = false; + desicDehum.MaxCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", std::string(regenCoilName), errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", currentModuleObject, desicDehum.Name)); + anyError = true; + } + + errFlag = false; + desicDehum.RegenCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", std::string(regenCoilName), errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", currentModuleObject, desicDehum.Name)); + anyError = true; + } + + errFlag = false; + desicDehum.RegenCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", std::string(regenCoilName), errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", currentModuleObject, desicDehum.Name)); + anyError = true; + } + + return anyError; + } + + // Mine steam heating coil data: index, control node, max flow (with density conversion), air inlet/outlet nodes. + // Sets desicDehum fields and returns true if any errors were found. + static bool mineSteamHeatingCoilData(EnergyPlusData &state, + DesiccantDehumidifierData &desicDehum, + std::string_view currentModuleObject, + std::string_view regenCoilName, + std::string_view alphaFieldName, + std::string_view callerName, + std::string_view routineNamePrefix = "") + { + bool anyError = false; + bool errFlag = false; + + desicDehum.RegenCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", std::string(regenCoilName), errFlag); + if (desicDehum.RegenCoilIndex == 0) { + ShowSevereError(state, EnergyPlus::format("{}{} illegal {} = {}", routineNamePrefix, currentModuleObject, alphaFieldName, regenCoilName)); + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", currentModuleObject, desicDehum.Name)); + anyError = true; + } + + errFlag = false; + desicDehum.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", std::string(regenCoilName), errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", currentModuleObject, desicDehum.Name)); + anyError = true; + } + + desicDehum.MaxCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, desicDehum.RegenCoilIndex, errFlag); + if (desicDehum.MaxCoilFluidFlow > 0.0) { + Real64 SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, TempSteamIn, 1.0, callerName); + desicDehum.MaxCoilFluidFlow *= SteamDensity; + } + + errFlag = false; + desicDehum.RegenCoilInletNode = SteamCoils::GetCoilAirInletNode(state, desicDehum.RegenCoilIndex, std::string(regenCoilName), errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", currentModuleObject, desicDehum.Name)); + anyError = true; + } + + errFlag = false; + desicDehum.RegenCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, desicDehum.RegenCoilIndex, std::string(regenCoilName), errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", currentModuleObject, desicDehum.Name)); + anyError = true; + } + + return anyError; + } + void GetDesiccantDehumidifierInput(EnergyPlusData &state) { @@ -244,7 +344,6 @@ namespace DesiccantDehumidifiers { Array1D Numbers; // Numeric input items for object Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE. Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE. - bool errFlag; // local error flag std::string RegenCoilType; // Regen heating coil type std::string RegenCoilName; // Regen heating coil name bool RegairHeatingCoilFlag; // local error flag @@ -407,46 +506,7 @@ namespace DesiccantDehumidifiers { ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; } else { // mine data from heating coil object - errFlag = false; - desicDehum.RegenCoilIndex = WaterCoils::GetWaterCoilIndex(state, "COIL:HEATING:WATER", RegenCoilName, errFlag); - if (desicDehum.RegenCoilIndex == 0) { - ShowSevereError(state, - EnergyPlus::format("{}{} illegal {} = {}", RoutineName, CurrentModuleObject, cAlphaFields(9), RegenCoilName)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil Hot water Inlet or control Node number - errFlag = false; - desicDehum.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", RegenCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the Regeneration Heating Coil hot water max volume flow rate - errFlag = false; - desicDehum.MaxCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", RegenCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the Regeneration Heating Coil Inlet Node - errFlag = false; - int RegenCoilAirInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", RegenCoilName, errFlag); - desicDehum.RegenCoilInletNode = RegenCoilAirInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the Regeneration Heating Coil Outlet Node - errFlag = false; - int RegenCoilAirOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", RegenCoilName, errFlag); - desicDehum.RegenCoilOutletNode = RegenCoilAirOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); + if (mineWaterHeatingCoilData(state, desicDehum, CurrentModuleObject, RegenCoilName, cAlphaFields(9), RoutineName)) { ErrorsFound = true; } } @@ -457,46 +517,8 @@ namespace DesiccantDehumidifiers { ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; } else { // mine data from the regeneration heating coil object - - errFlag = false; - desicDehum.RegenCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", RegenCoilName, errFlag); - if (desicDehum.RegenCoilIndex == 0) { - ShowSevereError(state, - EnergyPlus::format("{}{} illegal {} = {}", RoutineName, CurrentModuleObject, cAlphaFields(9), RegenCoilName)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the regeneration Heating Coil steam inlet node number - errFlag = false; - desicDehum.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", RegenCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the regeneration heating Coil steam max volume flow rate - desicDehum.MaxCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, desicDehum.RegenCoilIndex, errFlag); - if (desicDehum.MaxCoilFluidFlow > 0.0) { - Real64 SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, TempSteamIn, 1.0, dehumidifierDesiccantNoFans); - desicDehum.MaxCoilFluidFlow *= SteamDensity; - } - - // Get the regeneration heating Coil Inlet Node - errFlag = false; - int RegenCoilAirInletNode = SteamCoils::GetCoilAirInletNode(state, desicDehum.RegenCoilIndex, RegenCoilName, errFlag); - desicDehum.RegenCoilInletNode = RegenCoilAirInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the regeneration heating Coil Outlet Node - errFlag = false; - int RegenCoilAirOutletNode = SteamCoils::GetCoilAirOutletNode(state, desicDehum.RegenCoilIndex, RegenCoilName, errFlag); - desicDehum.RegenCoilOutletNode = RegenCoilAirOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); + if (mineSteamHeatingCoilData( + state, desicDehum, CurrentModuleObject, RegenCoilName, cAlphaFields(9), dehumidifierDesiccantNoFans, RoutineName)) { ErrorsFound = true; } } @@ -519,46 +541,22 @@ namespace DesiccantDehumidifiers { if (Util::SameString(Alphas(12), "UserCurves")) { desicDehum.PerformanceModel_Num = PerformanceModel::UserCurves; - desicDehum.ProcDryBulbCurvefTW = Curve::GetCurveIndex(state, Alphas(13)); - if (desicDehum.ProcDryBulbCurvefTW == 0) { - ShowSevereError(state, EnergyPlus::format("{}Curve object={} not found.", RoutineName, Alphas(13))); - ErrorsFound2 = true; - } - desicDehum.ProcDryBulbCurvefV = Curve::GetCurveIndex(state, Alphas(14)); - if (desicDehum.ProcDryBulbCurvefV == 0) { - ShowSevereError(state, EnergyPlus::format("{}Curve object={} not found.", RoutineName, Alphas(14))); - ErrorsFound2 = true; - } - desicDehum.ProcHumRatCurvefTW = Curve::GetCurveIndex(state, Alphas(15)); - if (desicDehum.ProcHumRatCurvefTW == 0) { - ShowSevereError(state, EnergyPlus::format("{}Curve object={} not found.", RoutineName, Alphas(15))); - ErrorsFound2 = true; - } - desicDehum.ProcHumRatCurvefV = Curve::GetCurveIndex(state, Alphas(16)); - if (desicDehum.ProcHumRatCurvefV == 0) { - ShowSevereError(state, EnergyPlus::format("{}Curve object={} not found.", RoutineName, Alphas(16))); - ErrorsFound2 = true; - } - desicDehum.RegenEnergyCurvefTW = Curve::GetCurveIndex(state, Alphas(17)); - if (desicDehum.RegenEnergyCurvefTW == 0) { - ShowSevereError(state, EnergyPlus::format("{}Curve object={} not found.", RoutineName, Alphas(17))); - ErrorsFound2 = true; - } - desicDehum.RegenEnergyCurvefV = Curve::GetCurveIndex(state, Alphas(18)); - if (desicDehum.RegenEnergyCurvefV == 0) { - ShowSevereError(state, EnergyPlus::format("{}Curve object={} not found.", RoutineName, Alphas(18))); - ErrorsFound2 = true; - } - desicDehum.RegenVelCurvefTW = Curve::GetCurveIndex(state, Alphas(19)); - if (desicDehum.RegenVelCurvefTW == 0) { - ShowSevereError(state, EnergyPlus::format("{}Curve object={} not found.", RoutineName, Alphas(19))); - ErrorsFound2 = true; - } - desicDehum.RegenVelCurvefV = Curve::GetCurveIndex(state, Alphas(20)); - if (desicDehum.RegenVelCurvefV == 0) { - ShowSevereError(state, EnergyPlus::format("{}Curve object={} not found.", RoutineName, Alphas(20))); - ErrorsFound2 = true; - } + // Look up a required performance curve; set ErrorsFound2 if not found. + auto lookupCurve = [&](int &curveIndex, int alphaIdx) { + curveIndex = Curve::GetCurveIndex(state, Alphas(alphaIdx)); + if (curveIndex == 0) { + ShowSevereError(state, EnergyPlus::format("{}Curve object={} not found.", RoutineName, Alphas(alphaIdx))); + ErrorsFound2 = true; + } + }; + lookupCurve(desicDehum.ProcDryBulbCurvefTW, 13); + lookupCurve(desicDehum.ProcDryBulbCurvefV, 14); + lookupCurve(desicDehum.ProcHumRatCurvefTW, 15); + lookupCurve(desicDehum.ProcHumRatCurvefV, 16); + lookupCurve(desicDehum.RegenEnergyCurvefTW, 17); + lookupCurve(desicDehum.RegenEnergyCurvefV, 18); + lookupCurve(desicDehum.RegenVelCurvefTW, 19); + lookupCurve(desicDehum.RegenVelCurvefV, 20); if (ErrorsFound2) { ShowSevereError(state, EnergyPlus::format("{}{} = {}", RoutineName, CurrentModuleObject, Alphas(1))); ShowContinueError(state, "Errors found in getting performance curves."); @@ -816,6 +814,22 @@ namespace DesiccantDehumidifiers { RegenCoilName = Alphas(10); desicDehum.RegenSetPointTemp = Numbers(1); + // Warn if a regen heating coil has a temperature setpoint node (should be blank). + auto warnIfCoilHasSetpointNode = [&](int controlNodeNum) { + if (controlNodeNum > 0) { + ShowSevereError(state, EnergyPlus::format("{} \"{}\"", desicDehum.DehumType, desicDehum.Name)); + ShowContinueError( + state, EnergyPlus::format("{} is specified as {:.3R} C in this object.", cNumericFields(1), desicDehum.RegenSetPointTemp)); + ShowContinueError(state, " Do not specify a coil temperature setpoint node name in the regeneration air heater object."); + ShowContinueError(state, EnergyPlus::format("...{} = {}", cAlphaFields(9), desicDehum.RegenCoilType)); + ShowContinueError(state, EnergyPlus::format("...{} = {}", cAlphaFields(10), desicDehum.RegenCoilName)); + ShowContinueError( + state, EnergyPlus::format("...heating coil temperature setpoint node = {}", state.dataLoopNodes->NodeID(controlNodeNum))); + ShowContinueError(state, "...leave the heating coil temperature setpoint node name blank in the regen heater object."); + ErrorsFoundGeneric = true; + } + }; + if (!lAlphaBlanks(10)) { if (Util::SameString(desicDehum.RegenCoilType, "Coil:Heating:Electric") || Util::SameString(desicDehum.RegenCoilType, "Coil:Heating:Fuel")) { @@ -865,20 +879,7 @@ namespace DesiccantDehumidifiers { ErrorsFoundGeneric = true; } - if (RegenCoilControlNodeNum > 0) { - ShowSevereError(state, EnergyPlus::format("{} \"{}\"", desicDehum.DehumType, desicDehum.Name)); - ShowContinueError( - state, - EnergyPlus::format("{} is specified as {:.3R} C in this object.", cNumericFields(1), desicDehum.RegenSetPointTemp)); - ShowContinueError(state, " Do not specify a coil temperature setpoint node name in the regeneration air heater object."); - ShowContinueError(state, EnergyPlus::format("...{} = {}", cAlphaFields(9), desicDehum.RegenCoilType)); - ShowContinueError(state, EnergyPlus::format("...{} = {}", cAlphaFields(10), desicDehum.RegenCoilName)); - ShowContinueError(state, - EnergyPlus::format("...heating coil temperature setpoint node = {}", - state.dataLoopNodes->NodeID(RegenCoilControlNodeNum))); - ShowContinueError(state, "...leave the heating coil temperature setpoint node name blank in the regen heater object."); - ErrorsFoundGeneric = true; - } + warnIfCoilHasSetpointNode(RegenCoilControlNodeNum); RegairHeatingCoilFlag = true; HeatingCoils::SetHeatingCoilData(state, desicDehum.RegenCoilIndex, ErrorsFound2, RegairHeatingCoilFlag, DesicDehumNum); @@ -894,11 +895,7 @@ namespace DesiccantDehumidifiers { ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; } else { // mine data from heating coil object - errFlag = false; - desicDehum.RegenCoilIndex = WaterCoils::GetWaterCoilIndex(state, "COIL:HEATING:WATER", RegenCoilName, errFlag); - if (desicDehum.RegenCoilIndex == 0) { - ShowSevereError(state, EnergyPlus::format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(9), RegenCoilName)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); + if (mineWaterHeatingCoilData(state, desicDehum, CurrentModuleObject, RegenCoilName, cAlphaFields(9))) { ErrorsFound = true; } @@ -908,40 +905,6 @@ namespace DesiccantDehumidifiers { ErrorsFoundGeneric = true; } - // Get the Heating Coil Hot water Inlet or control Node number - errFlag = false; - desicDehum.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", RegenCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the Regeneration Heating Coil hot water max volume flow rate - errFlag = false; - desicDehum.MaxCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", RegenCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the Regeneration Heating Coil Inlet Node - errFlag = false; - int RegenCoilAirInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", RegenCoilName, errFlag); - desicDehum.RegenCoilInletNode = RegenCoilAirInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the Regeneration Heating Coil Outlet Node - errFlag = false; - int RegenCoilAirOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", RegenCoilName, errFlag); - desicDehum.RegenCoilOutletNode = RegenCoilAirOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - RegairHeatingCoilFlag = true; WaterCoils::SetWaterCoilData(state, desicDehum.RegenCoilIndex, ErrorsFound2, RegairHeatingCoilFlag, DesicDehumNum); if (ErrorsFound2) { @@ -962,44 +925,8 @@ namespace DesiccantDehumidifiers { ErrorsFoundGeneric = true; } - errFlag = false; - desicDehum.RegenCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", RegenCoilName, errFlag); - if (desicDehum.RegenCoilIndex == 0) { - ShowSevereError(state, EnergyPlus::format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(9), RegenCoilName)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the regeneration Heating Coil steam inlet node number - errFlag = false; - desicDehum.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", RegenCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the regeneration heating Coil steam max volume flow rate - desicDehum.MaxCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, desicDehum.RegenCoilIndex, errFlag); - if (desicDehum.MaxCoilFluidFlow > 0.0) { - Real64 SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, TempSteamIn, 1.0, dehumidifierDesiccantNoFans); - desicDehum.MaxCoilFluidFlow *= SteamDensity; - } - - // Get the regeneration heating Coil Inlet Node - errFlag = false; - int RegenCoilAirInletNode = SteamCoils::GetCoilAirInletNode(state, desicDehum.RegenCoilIndex, RegenCoilName, errFlag); - desicDehum.RegenCoilInletNode = RegenCoilAirInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); - ErrorsFound = true; - } - - // Get the regeneration heating Coil Outlet Node - errFlag = false; - int RegenCoilAirOutletNode = SteamCoils::GetCoilAirOutletNode(state, desicDehum.RegenCoilIndex, RegenCoilName, errFlag); - desicDehum.RegenCoilOutletNode = RegenCoilAirOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, desicDehum.Name)); + if (mineSteamHeatingCoilData( + state, desicDehum, CurrentModuleObject, RegenCoilName, cAlphaFields(9), dehumidifierDesiccantNoFans)) { ErrorsFound = true; } } @@ -1012,20 +939,7 @@ namespace DesiccantDehumidifiers { ErrorsFoundGeneric = true; } - if (RegenCoilControlNodeNum > 0) { - ShowSevereError(state, EnergyPlus::format("{} \"{}\"", desicDehum.DehumType, desicDehum.Name)); - ShowContinueError( - state, - EnergyPlus::format("{} is specified as {:.3R} C in this object.", cNumericFields(1), desicDehum.RegenSetPointTemp)); - ShowContinueError(state, " Do not specify a coil temperature setpoint node name in the regeneration air heater object."); - ShowContinueError(state, EnergyPlus::format("...{} = {}", cAlphaFields(9), desicDehum.RegenCoilType)); - ShowContinueError(state, EnergyPlus::format("...{} = {}", cAlphaFields(10), desicDehum.RegenCoilName)); - ShowContinueError(state, - EnergyPlus::format("...heating coil temperature setpoint node = {}", - state.dataLoopNodes->NodeID(RegenCoilControlNodeNum))); - ShowContinueError(state, "...leave the heating coil temperature setpoint node name blank in the regen heater object."); - ErrorsFoundGeneric = true; - } + warnIfCoilHasSetpointNode(RegenCoilControlNodeNum); RegairHeatingCoilFlag = true; SteamCoils::SetSteamCoilData(state, desicDehum.RegenCoilIndex, ErrorsFound2, RegairHeatingCoilFlag, DesicDehumNum); diff --git a/src/EnergyPlus/EvaporativeFluidCoolers.cc b/src/EnergyPlus/EvaporativeFluidCoolers.cc index 66b836eb9cf..051aee6491f 100644 --- a/src/EnergyPlus/EvaporativeFluidCoolers.cc +++ b/src/EnergyPlus/EvaporativeFluidCoolers.cc @@ -1338,6 +1338,129 @@ namespace EvaporativeFluidCoolers { PlantUtilities::SetComponentFlowRate(state, this->WaterMassFlowRate, this->WaterInletNodeNum, this->WaterOutletNodeNum, this->plantLoc); } + // Helper: emit both final and initial sizer output for a given description. + // The "Initial " prefix is automatically prepended for the first-sizes report. + static void reportSizerPair(EnergyPlusData &state, std::string_view type, std::string const &name, std::string_view desc, Real64 value) + { + if (state.dataPlnt->PlantFinalSizesOkayToReport) { + BaseSizer::reportSizerOutput(state, type, name, desc, value); + } + if (state.dataPlnt->PlantFirstSizesOkayToReport) { + BaseSizer::reportSizerOutput(state, type, name, EnergyPlus::format("Initial {}", desc), value); + } + } + + // Helper: emit sizer output choosing the correct type string and description + // depending on whether the equipment is single-speed or two-speed. + static void reportSizerByType(EnergyPlusData &state, + DataPlant::PlantEquipmentType eqType, + std::string const &name, + std::string_view singleDesc, + std::string_view twoDesc, + Real64 value) + { + if (eqType == DataPlant::PlantEquipmentType::EvapFluidCooler_SingleSpd) { + reportSizerPair(state, cEvapFluidCooler_SingleSpeed, name, singleDesc, value); + } else if (eqType == DataPlant::PlantEquipmentType::EvapFluidCooler_TwoSpd) { + reportSizerPair(state, cEvapFluidCooler_TwoSpeed, name, twoDesc, value); + } + } + + // Helper: emit detailed diagnostic output when the UA solver fails to converge (SolFla == -2). + // Reports the design inputs and calculated outlet water temperatures at the UA bounds. + static void reportUASolverFailure(EnergyPlusData &state, + std::string const &name, + Real64 desLoad, + Real64 desWaterFlowRate, + Real64 airFlowRate, + Real64 airWetBulb, + Real64 waterInletTemp, + Real64 exitWaterTemp, + Real64 UA0, + Real64 UA1, + Real64 outWaterTempAtUA0, + Real64 outWaterTempAtUA1, + int PltSizCondNum, + EnergyPlusData const &stateForPlantSiz) + { + std::string const CalledFrom("SizeEvapFluidCooler"); + ShowSevereError(state, EnergyPlus::format("{}: The combination of design input values did not allow the calculation of a ", CalledFrom)); + ShowContinueError(state, "reasonable UA value. Review and revise design input values as appropriate. Specifying hard"); + ShowContinueError(state, + "sizes for some \"autosizable\" fields while autosizing other \"autosizable\" fields may be contributing " + "to this problem."); + ShowContinueError(state, "This model iterates on UA to find the heat transfer required to provide the design outlet "); + ShowContinueError(state, "water temperature. Initially, the outlet water temperatures at high and low UA values are "); + ShowContinueError(state, "calculated. The Design Exit Water Temperature should be between the outlet water "); + ShowContinueError(state, "temperatures calculated at high and low UA values. If the Design Exit Water Temperature is "); + ShowContinueError(state, "out of this range, the solution will not converge and UA will not be calculated. "); + ShowContinueError(state, "The possible solutions could be to manually input adjusted water and/or air flow rates "); + ShowContinueError(state, + "based on the autosized values shown below or to adjust design evaporative fluid cooler air inlet wet-bulb temperature."); + ShowContinueError(state, "Plant:Sizing object inputs also influence these results (e.g. DeltaT and ExitTemp)."); + ShowContinueError(state, "Inputs to the evaporative fluid cooler object:"); + ShowContinueError(state, EnergyPlus::format("Design Evaporative Fluid Cooler Load [W] = {:.2R}", desLoad)); + ShowContinueError(state, EnergyPlus::format("Design Evaporative Fluid Cooler Water Volume Flow Rate [m3/s] = {:.6R}", desWaterFlowRate)); + ShowContinueError(state, EnergyPlus::format("Design Evaporative Fluid Cooler Air Volume Flow Rate [m3/s] = {:.2R}", airFlowRate)); + ShowContinueError(state, EnergyPlus::format("Design Evaporative Fluid Cooler Air Inlet Wet-bulb Temp [C] = {:.2R}", airWetBulb)); + ShowContinueError(state, EnergyPlus::format("Design Evaporative Fluid Cooler Water Inlet Temp [C] = {:.2R}", waterInletTemp)); + ShowContinueError(state, "Inputs to the plant sizing object:"); + ShowContinueError(state, EnergyPlus::format("Design Exit Water Temp [C] = {:.2R}", exitWaterTemp)); + if (PltSizCondNum > 0) { + ShowContinueError(state, + EnergyPlus::format("Loop Design Temperature Difference [C] = {:.2R}", + stateForPlantSiz.dataSize->PlantSizData(PltSizCondNum).DeltaT)); + } + ShowContinueError(state, EnergyPlus::format("Design Evaporative Fluid Cooler Water Inlet Temp [C] = {:.2R}", waterInletTemp)); + ShowContinueError(state, + EnergyPlus::format("Calculated water outlet temperature at low UA [C](UA = {:.2R} W/C) = {:.2R}", UA0, outWaterTempAtUA0)); + ShowContinueError( + state, EnergyPlus::format("Calculated water outlet temperature at high UA [C](UA = {:.2R} W/C) = {:.2R}", UA1, outWaterTempAtUA1)); + ShowFatalError(state, EnergyPlus::format("Autosizing of Evaporative Fluid Cooler UA failed for Evaporative Fluid Cooler = {}", name)); + } + + // Helper: solve for UA given design load and flow parameters. + // Caller must set cooler->inletConds (WaterTemp, AirTemp, AirWetBulb) before calling. + // Sets inletConds.AirPress and AirHumRat, computes UA0/UA1, creates the solver lambda, + // and calls SolveRoot. SolFla == -1 is handled with a warning. + // Returns the solver flag; on -2, caller handles the bracket-failure error reporting. + static int solveForUA(EnergyPlusData &state, + EvapFluidCoolerSpecs *cooler, + Real64 desLoad, + Real64 waterMassFlowRate, + Real64 airFlowRate, + Real64 Cp, + Real64 &UA, + Real64 &UA0out, + Real64 &UA1out) + { + int constexpr MaxIte(500); + Real64 constexpr Acc(0.0001); + + cooler->inletConds.AirPress = state.dataEnvrn->StdBaroPress; + cooler->inletConds.AirHumRat = + Psychrometrics::PsyWFnTdbTwbPb(state, cooler->inletConds.AirTemp, cooler->inletConds.AirWetBulb, cooler->inletConds.AirPress); + + UA0out = 0.0001 * desLoad; // Lower bound: assume deltaT = 10000K + UA1out = desLoad; // Upper bound: assume deltaT = 1K + + auto f = [&state, cooler, desLoad, waterMassFlowRate, airFlowRate, Cp](Real64 UAval) { + cooler->SimSimpleEvapFluidCooler(state, waterMassFlowRate, airFlowRate, UAval, cooler->DesignExitWaterTemp); + Real64 const CoolingOutput = Cp * waterMassFlowRate * (cooler->inletConds.WaterTemp - cooler->DesignExitWaterTemp); + return (desLoad - CoolingOutput) / desLoad; + }; + + int SolFla = 0; + General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0out, UA1out); + + if (SolFla == -1) { + ShowWarningError(state, "Iteration limit exceeded in calculating evaporative fluid cooler UA."); + ShowContinueError(state, EnergyPlus::format("Autosizing of fluid cooler UA failed for evaporative fluid cooler = {}", cooler->Name)); + ShowContinueError(state, EnergyPlus::format("The final UA value = {:.2R}W/C, and the simulation continues...", UA)); + } + return SolFla; + } + void EvapFluidCoolerSpecs::SizeEvapFluidCooler(EnergyPlusData &state) { @@ -1359,8 +1482,6 @@ namespace EvaporativeFluidCoolers { // REFERENCES: // Based on SizeTower by Don Shirey, Sept/Oct 2002; Richard Raustad, Feb 2005 - int constexpr MaxIte(500); // Maximum number of iterations - Real64 constexpr Acc(0.0001); // Accuracy of result std::string const CalledFrom("SizeEvapFluidCooler"); int SolFla = 0; // Flag of solver @@ -1460,14 +1581,7 @@ namespace EvaporativeFluidCoolers { } } if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, this->EvapFluidCoolerType, this->Name, "Design Water Flow Rate [m3/s]", this->DesignWaterFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, this->EvapFluidCoolerType, this->Name, "Initial Design Water Flow Rate [m3/s]", this->DesignWaterFlowRate); - } + reportSizerPair(state, this->EvapFluidCoolerType, this->Name, "Design Water Flow Rate [m3/s]", this->DesignWaterFlowRate); } } else { if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { @@ -1493,40 +1607,12 @@ namespace EvaporativeFluidCoolers { tmpDesignWaterFlowRate = 5.382e-8 * this->HighSpeedStandardDesignCapacity; if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->DesignWaterFlowRate = tmpDesignWaterFlowRate; - if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_SingleSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_SingleSpeed, - this->Name, - "Design Water Flow Rate based on evaporative fluid cooler Standard Design Capacity [m3/s]", - this->DesignWaterFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, - cEvapFluidCooler_SingleSpeed, - this->Name, - "Initial Design Water Flow Rate based on evaporative fluid cooler Standard Design Capacity [m3/s]", - this->DesignWaterFlowRate); - } - } else if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_TwoSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, - cEvapFluidCooler_TwoSpeed, - this->Name, - "Design Water Flow Rate based on evaporative fluid cooler high-speed Standard Design Capacity [m3/s]", - this->DesignWaterFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, - cEvapFluidCooler_TwoSpeed, - this->Name, - "Initial Design Water Flow Rate based on evaporative fluid cooler high-speed Standard Design Capacity [m3/s]", - this->DesignWaterFlowRate); - } - } + reportSizerByType(state, + this->Type, + this->Name, + "Design Water Flow Rate based on evaporative fluid cooler Standard Design Capacity [m3/s]", + "Design Water Flow Rate based on evaporative fluid cooler high-speed Standard Design Capacity [m3/s]", + this->DesignWaterFlowRate); } } @@ -1573,28 +1659,12 @@ namespace EvaporativeFluidCoolers { } } if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { - if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_SingleSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, cEvapFluidCooler_SingleSpeed, this->Name, "Fan Power at Design Air Flow Rate [W]", this->HighSpeedFanPower); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_SingleSpeed, - this->Name, - "Initial Fan Power at Design Air Flow Rate [W]", - this->HighSpeedFanPower); - } - } else if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_TwoSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, cEvapFluidCooler_TwoSpeed, this->Name, "Fan Power at High Fan Speed [W]", this->HighSpeedFanPower); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, cEvapFluidCooler_TwoSpeed, this->Name, "Initial Fan Power at High Fan Speed [W]", this->HighSpeedFanPower); - } - } + reportSizerByType(state, + this->Type, + this->Name, + "Fan Power at Design Air Flow Rate [W]", + "Fan Power at High Fan Speed [W]", + this->HighSpeedFanPower); } } @@ -1605,28 +1675,12 @@ namespace EvaporativeFluidCoolers { if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->HighSpeedAirFlowRate = tmpHighSpeedAirFlowRate; - if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_SingleSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, cEvapFluidCooler_SingleSpeed, this->Name, "Design Air Flow Rate [m3/s]", this->HighSpeedAirFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, cEvapFluidCooler_SingleSpeed, this->Name, "Initial Design Air Flow Rate [m3/s]", this->HighSpeedAirFlowRate); - } - } else if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_TwoSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, cEvapFluidCooler_TwoSpeed, this->Name, "Air Flow Rate at High Fan Speed [m3/s]", this->HighSpeedAirFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_TwoSpeed, - this->Name, - "Initial Air Flow Rate at High Fan Speed [m3/s]", - this->HighSpeedAirFlowRate); - } - } + reportSizerByType(state, + this->Type, + this->Name, + "Design Air Flow Rate [m3/s]", + "Air Flow Rate at High Fan Speed [m3/s]", + this->HighSpeedAirFlowRate); } } @@ -1660,80 +1714,29 @@ namespace EvaporativeFluidCoolers { DesEvapFluidCoolerLoad = rho * Cp * tmpDesignWaterFlowRate * state.dataSize->PlantSizData(PltSizCondNum).DeltaT; Real64 const par1 = rho * tmpDesignWaterFlowRate; // Design water mass flow rate Real64 const par2 = tmpHighSpeedAirFlowRate; // Design air volume flow rate - // Lower bound for UA [W/C] - Real64 UA0 = 0.0001 * DesEvapFluidCoolerLoad; // Assume deltaT = 10000K (limit) - Real64 UA1 = DesEvapFluidCoolerLoad; // Assume deltaT = 1K this->inletConds.WaterTemp = this->DesignExitWaterTemp + state.dataSize->PlantSizData(PltSizCondNum).DeltaT; this->inletConds.AirTemp = 35.0; this->inletConds.AirWetBulb = 25.6; - this->inletConds.AirPress = state.dataEnvrn->StdBaroPress; - this->inletConds.AirHumRat = - Psychrometrics::PsyWFnTdbTwbPb(state, this->inletConds.AirTemp, this->inletConds.AirWetBulb, this->inletConds.AirPress); - auto f = [&state, this, DesEvapFluidCoolerLoad, par1, par2, Cp](Real64 UA) { - this->SimSimpleEvapFluidCooler(state, par1, par2, UA, this->DesignExitWaterTemp); - Real64 const CoolingOutput = Cp * par1 * (this->inletConds.WaterTemp - this->DesignExitWaterTemp); - return (DesEvapFluidCoolerLoad - CoolingOutput) / DesEvapFluidCoolerLoad; - }; - General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1); - if (SolFla == -1) { - ShowWarningError(state, "Iteration limit exceeded in calculating evaporative fluid cooler UA."); - ShowContinueError(state, - EnergyPlus::format("Autosizing of fluid cooler UA failed for evaporative fluid cooler = {}", this->Name)); - ShowContinueError(state, EnergyPlus::format("The final UA value = {:.2R}W/C, and the simulation continues...", UA)); - } else if (SolFla == -2) { + Real64 UA0 = 0.0; + Real64 UA1 = 0.0; + SolFla = solveForUA(state, this, DesEvapFluidCoolerLoad, par1, par2, Cp, UA, UA0, UA1); + if (SolFla == -2) { this->SimSimpleEvapFluidCooler(state, par1, par2, UA0, OutWaterTempAtUA0); this->SimSimpleEvapFluidCooler(state, par1, par2, UA1, OutWaterTempAtUA1); - ShowSevereError( - state, EnergyPlus::format("{}: The combination of design input values did not allow the calculation of a ", CalledFrom)); - ShowContinueError(state, "reasonable UA value. Review and revise design input values as appropriate. Specifying hard"); - ShowContinueError(state, - "sizes for some \"autosizable\" fields while autosizing other \"autosizable\" fields may be contributing " - "to this problem."); - ShowContinueError(state, "This model iterates on UA to find the heat transfer required to provide the design outlet "); - ShowContinueError(state, "water temperature. Initially, the outlet water temperatures at high and low UA values are "); - ShowContinueError(state, "calculated. The Design Exit Water Temperature should be between the outlet water "); - ShowContinueError(state, "temperatures calculated at high and low UA values. If the Design Exit Water Temperature is "); - ShowContinueError(state, "out of this range, the solution will not converge and UA will not be calculated. "); - ShowContinueError(state, "The possible solutions could be to manually input adjusted water and/or air flow rates "); - ShowContinueError( - state, - "based on the autosized values shown below or to adjust design evaporative fluid cooler air inlet wet-bulb temperature."); - ShowContinueError(state, "Plant:Sizing object inputs also influence these results (e.g. DeltaT and ExitTemp)."); - ShowContinueError(state, "Inputs to the evaporative fluid cooler object:"); - ShowContinueError( - state, - EnergyPlus::format("Design Evaporative Fluid Cooler Load [W] = {:.2R}", DesEvapFluidCoolerLoad)); - ShowContinueError( - state, - EnergyPlus::format("Design Evaporative Fluid Cooler Water Volume Flow Rate [m3/s] = {:.6R}", this->DesignWaterFlowRate)); - ShowContinueError(state, EnergyPlus::format("Design Evaporative Fluid Cooler Air Volume Flow Rate [m3/s] = {:.2R}", par2)); - ShowContinueError(state, - EnergyPlus::format("Design Evaporative Fluid Cooler Air Inlet Wet-bulb Temp [C] = {:.2R}", - this->inletConds.AirWetBulb)); - ShowContinueError( - state, - EnergyPlus::format("Design Evaporative Fluid Cooler Water Inlet Temp [C] = {:.2R}", this->inletConds.WaterTemp)); - ShowContinueError(state, "Inputs to the plant sizing object:"); - ShowContinueError( - state, - EnergyPlus::format("Design Exit Water Temp [C] = {:.2R}", this->DesignExitWaterTemp)); - ShowContinueError(state, - EnergyPlus::format("Loop Design Temperature Difference [C] = {:.2R}", - state.dataSize->PlantSizData(PltSizCondNum).DeltaT)); - ShowContinueError( - state, - EnergyPlus::format("Design Evaporative Fluid Cooler Water Inlet Temp [C] = {:.2R}", this->inletConds.WaterTemp)); - ShowContinueError(state, - EnergyPlus::format("Calculated water outlet temperature at low UA [C](UA = {:.2R} W/C) = {:.2R}", - UA0, - OutWaterTempAtUA0)); - ShowContinueError(state, - EnergyPlus::format("Calculated water outlet temperature at high UA [C](UA = {:.2R} W/C) = {:.2R}", - UA1, - OutWaterTempAtUA1)); - ShowFatalError( - state, - EnergyPlus::format("Autosizing of Evaporative Fluid Cooler UA failed for Evaporative Fluid Cooler = {}", this->Name)); + reportUASolverFailure(state, + this->Name, + DesEvapFluidCoolerLoad, + this->DesignWaterFlowRate, + par2, + this->inletConds.AirWetBulb, + this->inletConds.WaterTemp, + this->DesignExitWaterTemp, + UA0, + UA1, + OutWaterTempAtUA0, + OutWaterTempAtUA1, + PltSizCondNum, + state); } if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->HighSpeedEvapFluidCoolerUA = UA; @@ -1745,37 +1748,12 @@ namespace EvaporativeFluidCoolers { } } if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { - if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_SingleSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_SingleSpeed, - this->Name, - "U-Factor Times Area Value at Design Air Flow Rate [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_SingleSpeed, - this->Name, - "Initial U-Factor Times Area Value at Design Air Flow Rate [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - } else if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_TwoSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_TwoSpeed, - this->Name, - "U-Factor Times Area Value at High Fan Speed [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_TwoSpeed, - this->Name, - "Initial U-Factor Times Area Value at High Fan Speed [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - } + reportSizerByType(state, + this->Type, + this->Name, + "U-Factor Times Area Value at Design Air Flow Rate [W/C]", + "U-Factor Times Area Value at High Fan Speed [W/C]", + this->HighSpeedEvapFluidCoolerUA); } } else { if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { @@ -1794,28 +1772,15 @@ namespace EvaporativeFluidCoolers { DesEvapFluidCoolerLoad = this->HighSpeedStandardDesignCapacity * this->HeatRejectCapNomCapSizingRatio; Real64 const par1 = rho * this->DesignWaterFlowRate; // Design water mass flow rate Real64 const par2 = this->HighSpeedAirFlowRate; // Design air volume flow rate - Real64 UA0 = 0.0001 * DesEvapFluidCoolerLoad; // Assume deltaT = 10000K (limit) - Real64 UA1 = DesEvapFluidCoolerLoad; // Assume deltaT = 1K this->inletConds.WaterTemp = 35.0; // 95F design inlet water temperature this->DesignEnteringWaterTemp = this->inletConds.WaterTemp; this->inletConds.AirTemp = 35.0; // 95F design inlet air dry-bulb temp this->inletConds.AirWetBulb = 25.6; // 78F design inlet air wet-bulb temp this->DesignEnteringAirWetBulbTemp = this->inletConds.AirWetBulb; - this->inletConds.AirPress = state.dataEnvrn->StdBaroPress; - this->inletConds.AirHumRat = - Psychrometrics::PsyWFnTdbTwbPb(state, this->inletConds.AirTemp, this->inletConds.AirWetBulb, this->inletConds.AirPress); - auto f = [&state, this, DesEvapFluidCoolerLoad, par1, par2, Cp](Real64 UA) { - this->SimSimpleEvapFluidCooler(state, par1, par2, UA, this->DesignExitWaterTemp); - Real64 const CoolingOutput = Cp * par1 * (this->inletConds.WaterTemp - this->DesignExitWaterTemp); - return (DesEvapFluidCoolerLoad - CoolingOutput) / DesEvapFluidCoolerLoad; - }; - General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1); - if (SolFla == -1) { - ShowWarningError(state, "Iteration limit exceeded in calculating evaporative fluid cooler UA."); - ShowContinueError(state, - EnergyPlus::format("Autosizing of fluid cooler UA failed for evaporative fluid cooler = {}", this->Name)); - ShowContinueError(state, EnergyPlus::format("The final UA value = {:.2R}W/C, and the simulation continues...", UA)); - } else if (SolFla == -2) { + Real64 UA0 = 0.0; + Real64 UA1 = 0.0; + SolFla = solveForUA(state, this, DesEvapFluidCoolerLoad, par1, par2, Cp, UA, UA0, UA1); + if (SolFla == -2) { ShowSevereError(state, EnergyPlus::format("{}: The combination of design input values did not allow the calculation of a ", CalledFrom)); ShowContinueError(state, "reasonable UA value. Review and revise design input values as appropriate. "); @@ -1827,37 +1792,12 @@ namespace EvaporativeFluidCoolers { this->HighSpeedEvapFluidCoolerUA = 0.0; } if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { - if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_SingleSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_SingleSpeed, - this->Name, - "U-Factor Times Area Value at Design Air Flow Rate [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_SingleSpeed, - this->Name, - "Initial U-Factor Times Area Value at Design Air Flow Rate [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - } else if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_TwoSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_TwoSpeed, - this->Name, - "U-Factor Times Area Value at High Fan Speed [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_TwoSpeed, - this->Name, - "Initial U-Factor Times Area Value at High Fan Speed [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - } + reportSizerByType(state, + this->Type, + this->Name, + "U-Factor Times Area Value at Design Air Flow Rate [W/C]", + "U-Factor Times Area Value at High Fan Speed [W/C]", + this->HighSpeedEvapFluidCoolerUA); } } @@ -1868,157 +1808,58 @@ namespace EvaporativeFluidCoolers { DesEvapFluidCoolerLoad = this->HighSpeedUserSpecifiedDesignCapacity; Real64 const par1 = rho * tmpDesignWaterFlowRate; // Design water mass flow rate Real64 const par2 = tmpHighSpeedAirFlowRate; // Design air volume flow rate - Real64 UA0 = 0.0001 * DesEvapFluidCoolerLoad; // Assume deltaT = 10000K (limit) - Real64 UA1 = DesEvapFluidCoolerLoad; // Assume deltaT = 1K - this->inletConds.WaterTemp = this->DesignEnteringWaterTemp; this->inletConds.AirTemp = this->DesignEnteringAirTemp; this->inletConds.AirWetBulb = this->DesignEnteringAirWetBulbTemp; - this->inletConds.AirPress = state.dataEnvrn->StdBaroPress; - this->inletConds.AirHumRat = - Psychrometrics::PsyWFnTdbTwbPb(state, this->inletConds.AirTemp, this->inletConds.AirWetBulb, this->inletConds.AirPress); - auto f = [&state, this, DesEvapFluidCoolerLoad, par1, par2, Cp](Real64 UA) { - this->SimSimpleEvapFluidCooler(state, par1, par2, UA, this->DesignExitWaterTemp); - Real64 const CoolingOutput = Cp * par1 * (this->inletConds.WaterTemp - this->DesignExitWaterTemp); - return (DesEvapFluidCoolerLoad - CoolingOutput) / DesEvapFluidCoolerLoad; - }; - General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1); - if (SolFla == -1) { - ShowWarningError(state, "Iteration limit exceeded in calculating evaporative fluid cooler UA."); - ShowContinueError(state, - EnergyPlus::format("Autosizing of fluid cooler UA failed for evaporative fluid cooler = {}", this->Name)); - ShowContinueError(state, EnergyPlus::format("The final UA value = {:.2R}W/C, and the simulation continues...", UA)); - } else if (SolFla == -2) { + Real64 UA0 = 0.0; + Real64 UA1 = 0.0; + SolFla = solveForUA(state, this, DesEvapFluidCoolerLoad, par1, par2, Cp, UA, UA0, UA1); + if (SolFla == -2) { this->SimSimpleEvapFluidCooler(state, par1, par2, UA0, OutWaterTempAtUA0); this->SimSimpleEvapFluidCooler(state, par1, par2, UA1, OutWaterTempAtUA1); - ShowSevereError(state, - EnergyPlus::format("{}: The combination of design input values did not allow the calculation of a ", CalledFrom)); - ShowContinueError(state, "reasonable UA value. Review and revise design input values as appropriate. Specifying hard"); - ShowContinueError( - state, - R"(sizes for some "autosizable" fields while autosizing other "autosizable" fields may be contributing to this problem.)"); - ShowContinueError(state, "This model iterates on UA to find the heat transfer required to provide the design outlet "); - ShowContinueError(state, "water temperature. Initially, the outlet water temperatures at high and low UA values are "); - ShowContinueError(state, "calculated. The Design Exit Water Temperature should be between the outlet water "); - ShowContinueError(state, "temperatures calculated at high and low UA values. If the Design Exit Water Temperature is "); - ShowContinueError(state, "out of this range, the solution will not converge and UA will not be calculated. "); - ShowContinueError(state, "The possible solutions could be to manually input adjusted water and/or air flow rates "); - ShowContinueError( - state, - "based on the autosized values shown below or to adjust design evaporative fluid cooler air inlet wet-bulb temperature."); - ShowContinueError(state, "Plant:Sizing object inputs also influence these results (e.g. DeltaT and ExitTemp)."); - ShowContinueError(state, "Inputs to the evaporative fluid cooler object:"); - ShowContinueError( - state, EnergyPlus::format("Design Evaporative Fluid Cooler Load [W] = {:.2R}", DesEvapFluidCoolerLoad)); - ShowContinueError( - state, - EnergyPlus::format("Design Evaporative Fluid Cooler Water Volume Flow Rate [m3/s] = {:.6R}", this->DesignWaterFlowRate)); - ShowContinueError(state, EnergyPlus::format("Design Evaporative Fluid Cooler Air Volume Flow Rate [m3/s] = {:.2R}", par2)); - ShowContinueError( - state, - EnergyPlus::format("Design Evaporative Fluid Cooler Air Inlet Wet-bulb Temp [C] = {:.2R}", this->inletConds.AirWetBulb)); - ShowContinueError( - state, - EnergyPlus::format("Design Evaporative Fluid Cooler Water Inlet Temp [C] = {:.2R}", this->inletConds.WaterTemp)); - ShowContinueError(state, "Inputs to the plant sizing object:"); - ShowContinueError( - state, - EnergyPlus::format("Design Exit Water Temp [C] = {:.2R}", this->DesignExitWaterTemp)); - if (PltSizCondNum > 0) { - ShowContinueError(state, - EnergyPlus::format("Loop Design Temperature Difference [C] = {:.2R}", - state.dataSize->PlantSizData(PltSizCondNum).DeltaT)); - } - ShowContinueError( - state, - EnergyPlus::format("Design Evaporative Fluid Cooler Water Inlet Temp [C] = {:.2R}", this->inletConds.WaterTemp)); - ShowContinueError( - state, - EnergyPlus::format("Calculated water outlet temperature at low UA [C](UA = {:.2R} W/C) = {:.2R}", UA0, OutWaterTempAtUA0)); - ShowContinueError( - state, - EnergyPlus::format("Calculated water outlet temperature at high UA [C](UA = {:.2R} W/C) = {:.2R}", UA1, OutWaterTempAtUA1)); - ShowFatalError( - state, EnergyPlus::format("Autosizing of Evaporative Fluid Cooler UA failed for Evaporative Fluid Cooler = {}", this->Name)); + reportUASolverFailure(state, + this->Name, + DesEvapFluidCoolerLoad, + this->DesignWaterFlowRate, + par2, + this->inletConds.AirWetBulb, + this->inletConds.WaterTemp, + this->DesignExitWaterTemp, + UA0, + UA1, + OutWaterTempAtUA0, + OutWaterTempAtUA1, + PltSizCondNum, + state); } this->HighSpeedEvapFluidCoolerUA = UA; } else { this->HighSpeedEvapFluidCoolerUA = 0.0; } if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { - if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_SingleSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_SingleSpeed, - this->Name, - "U-Factor Times Area Value at Design Air Flow Rate [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_SingleSpeed, - this->Name, - "Initial U-Factor Times Area Value at Design Air Flow Rate [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - } else if (this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_TwoSpd) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_TwoSpeed, - this->Name, - "U-Factor Times Area Value at High Fan Speed [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - cEvapFluidCooler_TwoSpeed, - this->Name, - "Initial U-Factor Times Area Value at High Fan Speed [W/C]", - this->HighSpeedEvapFluidCoolerUA); - } - } + reportSizerByType(state, + this->Type, + this->Name, + "U-Factor Times Area Value at Design Air Flow Rate [W/C]", + "U-Factor Times Area Value at High Fan Speed [W/C]", + this->HighSpeedEvapFluidCoolerUA); } } if (this->LowSpeedAirFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->LowSpeedAirFlowRate = this->LowSpeedAirFlowRateSizingFactor * this->HighSpeedAirFlowRate; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, this->EvapFluidCoolerType, this->Name, "Air Flow Rate at Low Fan Speed [m3/s]", this->LowSpeedAirFlowRate); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, this->EvapFluidCoolerType, this->Name, "Initial Air Flow Rate at Low Fan Speed [m3/s]", this->LowSpeedAirFlowRate); - } + reportSizerPair(state, this->EvapFluidCoolerType, this->Name, "Air Flow Rate at Low Fan Speed [m3/s]", this->LowSpeedAirFlowRate); } if (this->LowSpeedFanPowerWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->LowSpeedFanPower = this->LowSpeedFanPowerSizingFactor * this->HighSpeedFanPower; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, this->EvapFluidCoolerType, this->Name, "Fan Power at Low Fan Speed [W]", this->LowSpeedFanPower); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput( - state, this->EvapFluidCoolerType, this->Name, "Initial Fan Power at Low Fan Speed [W]", this->LowSpeedFanPower); - } + reportSizerPair(state, this->EvapFluidCoolerType, this->Name, "Fan Power at Low Fan Speed [W]", this->LowSpeedFanPower); } if (this->LowSpeedEvapFluidCoolerUAWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->LowSpeedEvapFluidCoolerUA = this->LowSpeedEvapFluidCoolerUASizingFactor * this->HighSpeedEvapFluidCoolerUA; - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - this->EvapFluidCoolerType, - this->Name, - "U-Factor Times Area Value at Low Fan Speed [W/C]", - this->LowSpeedEvapFluidCoolerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - this->EvapFluidCoolerType, - this->Name, - "Initial U-Factor Times Area Value at Low Fan Speed [W/C]", - this->LowSpeedEvapFluidCoolerUA); - } + reportSizerPair( + state, this->EvapFluidCoolerType, this->Name, "U-Factor Times Area Value at Low Fan Speed [W/C]", this->LowSpeedEvapFluidCoolerUA); } if (this->PerformanceInputMethod_Num == PIM::StandardDesignCapacity && this->Type == DataPlant::PlantEquipmentType::EvapFluidCooler_TwoSpd) { @@ -2030,26 +1871,13 @@ namespace EvaporativeFluidCoolers { DesEvapFluidCoolerLoad = this->LowSpeedStandardDesignCapacity * this->HeatRejectCapNomCapSizingRatio; Real64 const par1 = rho * tmpDesignWaterFlowRate; // Design water mass flow rate Real64 const par2 = this->LowSpeedAirFlowRate; // Air volume flow rate at low fan speed - Real64 UA0 = 0.0001 * DesEvapFluidCoolerLoad; // Assume deltaT = 10000K (limit) - Real64 UA1 = DesEvapFluidCoolerLoad; // Assume deltaT = 1K this->inletConds.WaterTemp = 35.0; // 95F design inlet water temperature this->inletConds.AirTemp = 35.0; // 95F design inlet air dry-bulb temp this->inletConds.AirWetBulb = 25.6; // 78F design inlet air wet-bulb temp - this->inletConds.AirPress = state.dataEnvrn->StdBaroPress; - this->inletConds.AirHumRat = - Psychrometrics::PsyWFnTdbTwbPb(state, this->inletConds.AirTemp, this->inletConds.AirWetBulb, this->inletConds.AirPress); - auto f = [&state, this, DesEvapFluidCoolerLoad, par1, par2, Cp](Real64 UA) { - this->SimSimpleEvapFluidCooler(state, par1, par2, UA, this->DesignExitWaterTemp); - Real64 const CoolingOutput = Cp * par1 * (this->inletConds.WaterTemp - this->DesignExitWaterTemp); - return (DesEvapFluidCoolerLoad - CoolingOutput) / DesEvapFluidCoolerLoad; - }; - General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1); - if (SolFla == -1) { - ShowWarningError(state, "Iteration limit exceeded in calculating evaporative fluid cooler UA."); - ShowContinueError(state, - EnergyPlus::format("Autosizing of fluid cooler UA failed for evaporative fluid cooler = {}", this->Name)); - ShowContinueError(state, EnergyPlus::format("The final UA value = {:.2R}W/C, and the simulation continues...", UA)); - } else if (SolFla == -2) { + Real64 UA0 = 0.0; + Real64 UA1 = 0.0; + SolFla = solveForUA(state, this, DesEvapFluidCoolerLoad, par1, par2, Cp, UA, UA0, UA1); + if (SolFla == -2) { ShowSevereError(state, EnergyPlus::format("{}: The combination of design input values did not allow the calculation of a ", CalledFrom)); ShowContinueError(state, "reasonable low-speed UA value. Review and revise design input values as appropriate. "); @@ -2061,20 +1889,11 @@ namespace EvaporativeFluidCoolers { this->LowSpeedEvapFluidCoolerUA = 0.0; } if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - this->EvapFluidCoolerType, - this->Name, - "U-Factor Times Area Value at Low Fan Speed [W/C]", - this->LowSpeedEvapFluidCoolerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - this->EvapFluidCoolerType, - this->Name, - "Initial U-Factor Times Area Value at Low Fan Speed [W/C]", - this->LowSpeedEvapFluidCoolerUA); - } + reportSizerPair(state, + this->EvapFluidCoolerType, + this->Name, + "U-Factor Times Area Value at Low Fan Speed [W/C]", + this->LowSpeedEvapFluidCoolerUA); } } @@ -2086,77 +1905,45 @@ namespace EvaporativeFluidCoolers { DesEvapFluidCoolerLoad = this->LowSpeedUserSpecifiedDesignCapacity; Real64 const par1 = rho * tmpDesignWaterFlowRate; // Design water mass flow rate Real64 const par2 = this->LowSpeedAirFlowRate; // Air volume flow rate at low fan speed - Real64 UA0 = 0.0001 * DesEvapFluidCoolerLoad; // Assume deltaT = 10000K (limit) - Real64 UA1 = DesEvapFluidCoolerLoad; // Assume deltaT = 1K this->inletConds.WaterTemp = this->DesignEnteringWaterTemp; this->inletConds.AirTemp = this->DesignEnteringAirTemp; this->inletConds.AirWetBulb = this->DesignEnteringAirWetBulbTemp; - this->inletConds.AirPress = state.dataEnvrn->StdBaroPress; - this->inletConds.AirHumRat = - Psychrometrics::PsyWFnTdbTwbPb(state, this->inletConds.AirTemp, this->inletConds.AirWetBulb, this->inletConds.AirPress); - auto f = [&state, this, DesEvapFluidCoolerLoad, par1, par2, Cp](Real64 UA) { - this->SimSimpleEvapFluidCooler(state, par1, par2, UA, this->DesignExitWaterTemp); - Real64 const CoolingOutput = Cp * par1 * (this->inletConds.WaterTemp - this->DesignExitWaterTemp); - return (DesEvapFluidCoolerLoad - CoolingOutput) / DesEvapFluidCoolerLoad; - }; - General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1); + Real64 UA0 = 0.0; + Real64 UA1 = 0.0; + SolFla = solveForUA(state, this, DesEvapFluidCoolerLoad, par1, par2, Cp, UA, UA0, UA1); if (SolFla == -1) { + // Override the warning from solveForUA with a fatal error for this case ShowSevereError(state, "Iteration limit exceeded in calculating EvaporativeFluidCooler UA"); ShowFatalError(state, EnergyPlus::format("Autosizing of EvaporativeFluidCooler UA failed for EvaporativeFluidCooler {}", this->Name)); } else if (SolFla == -2) { this->SimSimpleEvapFluidCooler(state, par1, par2, UA0, OutWaterTempAtUA0); this->SimSimpleEvapFluidCooler(state, par1, par2, UA1, OutWaterTempAtUA1); - ShowSevereError(state, - EnergyPlus::format("{}: The combination of design input values did not allow the calculation of a ", CalledFrom)); - ShowContinueError(state, "reasonable UA value. Review and revise design input values as appropriate. Specifying hard"); - ShowContinueError( - state, - R"(sizes for some "autosizable" fields while autosizing other "autosizable" fields may be contributing to this problem.)"); - ShowContinueError(state, "This model iterates on UA to find the heat transfer required to provide the design outlet "); - ShowContinueError(state, "water temperature. Initially, the outlet water temperatures at high and low UA values are "); - ShowContinueError(state, "calculated. The Design Exit Water Temperature should be between the outlet water "); - ShowContinueError(state, "temperatures calculated at high and low UA values. If the Design Exit Water Temperature is "); - ShowContinueError(state, "out of this range, the solution will not converge and UA will not be calculated. "); - ShowContinueError(state, "Inputs to the Evaporative Fluid Cooler model are:"); - ShowContinueError(state, - EnergyPlus::format("Design Evaporative Fluid Cooler Load = {:.2R}", DesEvapFluidCoolerLoad)); - ShowContinueError(state, EnergyPlus::format("Design Evaporative Fluid Cooler Water Volume Flow Rate = {:.2R}", par1)); - ShowContinueError(state, EnergyPlus::format("Design Evaporative Fluid Cooler Air Volume Flow Rate = {:.2R}", par2)); - ShowContinueError( - state, EnergyPlus::format("Design Evaporative Fluid Cooler Air Inlet Wet-bulb Temp = {:.2R}", this->inletConds.AirWetBulb)); - ShowContinueError( - state, EnergyPlus::format("Design Evaporative Fluid Cooler Water Inlet Temp = {:.2R}", this->inletConds.WaterTemp)); - ShowContinueError( - state, EnergyPlus::format("Design Exit Water Temp = {:.2R}", this->DesignExitWaterTemp)); - ShowContinueError( - state, EnergyPlus::format("Design Evaporative Fluid Cooler Water Inlet Temp [C] = {:.2R}", this->inletConds.WaterTemp)); - ShowContinueError(state, - EnergyPlus::format("Calculated water outlet temperature at low UA({:.2R}) = {:.2R}", UA0, OutWaterTempAtUA0)); - ShowContinueError(state, - EnergyPlus::format("Calculated water outlet temperature at high UA({:.2R}) = {:.2R}", UA1, OutWaterTempAtUA1)); - ShowFatalError( - state, EnergyPlus::format("Autosizing of Evaporative Fluid Cooler UA failed for Evaporative Fluid Cooler = {}", this->Name)); + reportUASolverFailure(state, + this->Name, + DesEvapFluidCoolerLoad, + this->DesignWaterFlowRate, + par2, + this->inletConds.AirWetBulb, + this->inletConds.WaterTemp, + this->DesignExitWaterTemp, + UA0, + UA1, + OutWaterTempAtUA0, + OutWaterTempAtUA1, + PltSizCondNum, + state); } this->LowSpeedEvapFluidCoolerUA = UA; } else { this->LowSpeedEvapFluidCoolerUA = 0.0; } if (state.dataPlnt->PlantFirstSizesOkayToFinalize) { - if (state.dataPlnt->PlantFinalSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - this->EvapFluidCoolerType, - this->Name, - "U-Factor Times Area Value at Low Fan Speed [W/C]", - this->LowSpeedEvapFluidCoolerUA); - } - if (state.dataPlnt->PlantFirstSizesOkayToReport) { - BaseSizer::reportSizerOutput(state, - this->EvapFluidCoolerType, - this->Name, - "Initial U-Factor Times Area Value at Low Fan Speed [W/C]", - this->LowSpeedEvapFluidCoolerUA); - } + reportSizerPair(state, + this->EvapFluidCoolerType, + this->Name, + "U-Factor Times Area Value at Low Fan Speed [W/C]", + this->LowSpeedEvapFluidCoolerUA); } } diff --git a/src/EnergyPlus/FanCoilUnits.cc b/src/EnergyPlus/FanCoilUnits.cc index f6880a4bfaa..bc0057fa732 100644 --- a/src/EnergyPlus/FanCoilUnits.cc +++ b/src/EnergyPlus/FanCoilUnits.cc @@ -1948,6 +1948,196 @@ namespace FanCoilUnits { } } + // Report SolveRoot convergence / limit errors for ConsFanVarFlow water-flow control. + // Called for both hot-water and cold-water branches; the string and counter + // references distinguish the two cases. + static void reportWaterFlowSolveRootErrors(EnergyPlusData &state, + int const SolFlag, + std::string const &fluidLabel, // "Cold Water" or "Hot Water" + std::string const &fcuName, + int const FanCoilNum, + int const ControlledZoneNum, + bool const FirstHVACIteration, + int const fluidInletNode, + Real64 const waterFlow, + Real64 const QZnReq, + Real64 const MinWaterFlow, + Real64 const MaxWaterFlow, + int &convgErrCount, + int &limitErrCount, + int &maxIterIndex, + int &badMassFlowLimIndex) + { + if (SolFlag == -1) { + ++convgErrCount; + if (convgErrCount < 2) { + ShowWarningError(state, EnergyPlus::format("{} control failed in fan coil unit {}", fluidLabel, fcuName)); + ShowContinueError(state, " Iteration limit exceeded in calculating water flow rate "); + state.dataLoopNodes->Node(fluidInletNode).MassFlowRate = waterFlow; + Real64 QUnitOut; + Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); + ShowContinueErrorTimeStamp(state, EnergyPlus::format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut)); + ShowContinueErrorTimeStamp( + state, + EnergyPlus::format( + "Min water flow used during iterations = {}, Max water flow used during iterations = {}", MinWaterFlow, MaxWaterFlow)); + ShowContinueErrorTimeStamp(state, EnergyPlus::format("Water flow rate on last iteration = {}", waterFlow)); + ShowContinueErrorTimeStamp(state, "..Water flow rate set to last iteration value "); + } else { + ShowRecurringWarningErrorAtEnd(state, fluidLabel + " flow Iteration limit exceeded in fan coil unit " + fcuName, maxIterIndex); + } + } else if (SolFlag == -2) { + ++limitErrCount; + if (limitErrCount < 2) { + ShowWarningError(state, EnergyPlus::format("{} control failed in fan coil unit {}", fluidLabel, fcuName)); + ShowContinueError(state, EnergyPlus::format(" Bad {} mass flow limits", fluidLabel)); + ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit "); + } else { + ShowRecurringWarningErrorAtEnd(state, fluidLabel + " control failed in fan coil unit " + fcuName, badMassFlowLimIndex); + } + } + } + + // Report SolveRoot convergence / limit errors for CycFan/VarFanVarFlow PLR control. + // Called for both cooling and heating branches. + static void reportPLRSolveRootErrors(EnergyPlusData &state, + int const SolFlag, + std::string const &modeLabel, // "cooling" or "heating" + std::string const &fcuName, + int const FanCoilNum, + int const ControlledZoneNum, + bool const FirstHVACIteration, + int const fluidInletNode, + Real64 const PLR, + Real64 const maxCoilFluidFlow, + Real64 const QZnReq, + Real64 const PLRMin, + Real64 const PLRMax, + int &convgErrCount, + int &limitErrCount, + int &maxIterIndex, + int &badMassFlowLimIndex) + { + if (SolFlag == -1) { + ++convgErrCount; + if (convgErrCount < 2) { + ShowWarningError(state, EnergyPlus::format("Part-load ratio {} control failed in fan coil unit {}", modeLabel, fcuName)); + ShowContinueError(state, " Iteration limit exceeded in calculating FCU part-load ratio "); + state.dataLoopNodes->Node(fluidInletNode).MassFlowRate = PLR * maxCoilFluidFlow; + Real64 QUnitOut; + Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR); + ShowContinueErrorTimeStamp(state, EnergyPlus::format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut)); + ShowContinueErrorTimeStamp( + state, + EnergyPlus::format("Min part-load used during iterations = {}, Max part-load used during iterations = {}", PLRMin, PLRMax)); + ShowContinueErrorTimeStamp(state, EnergyPlus::format("Part-load ratio on last iteration = {}", PLR)); + ShowContinueErrorTimeStamp(state, "..Part-load ratio set to last iteration value "); + } else { + ShowRecurringWarningErrorAtEnd( + state, "Part-load ratio " + modeLabel + " iteration limit exceeded in fan coil unit " + fcuName, maxIterIndex); + } + } else if (SolFlag == -2) { + ++limitErrCount; + if (limitErrCount < 2) { + ShowWarningError(state, EnergyPlus::format("Part-load ratio {} control failed in fan coil unit {}", modeLabel, fcuName)); + ShowContinueError(state, " Bad part-load ratio limits"); + ShowContinueErrorTimeStamp(state, EnergyPlus::format("..Part-load ratio set to {}", PLRMin)); + } else { + ShowRecurringWarningErrorAtEnd( + state, "Part-load ratio " + modeLabel + " control failed in fan coil unit " + fcuName, badMassFlowLimIndex); + } + } + } + + // Iteratively adjust PLR until the fan coil output matches the zone load. + // Used by the VarFanConsFlow control method for both cooling and heating. + static void iterateFanCoilPLR(EnergyPlusData &state, + int const FanCoilNum, + int const ControlledZoneNum, + bool const FirstHVACIteration, + Real64 const QZnReq, + Real64 const QUnitOutMax, + Real64 const ControlOffset, + int const MaxIterCycl, + Real64 &PLR, + Real64 &QUnitOut, + std::string const &modeLabel, // "cooling" or "heating" + std::string const &fcuName, + int &maxIterIndex) + { + Real64 Error = 1.0; + Real64 AbsError = 2.0 * HVAC::SmallLoad; + Real64 Relax = 1.0; + int Iter = 0; + + while (std::abs(Error) > ControlOffset && std::abs(AbsError) > HVAC::SmallLoad && Iter < MaxIterCycl && PLR != 1.0) { + Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR); + Error = (QZnReq - QUnitOut) / QZnReq; + AbsError = QZnReq - QUnitOut; + Real64 DelPLR = (QZnReq - QUnitOut) / QUnitOutMax; + PLR += Relax * DelPLR; + PLR = max(0.0, min(1.0, PLR)); + ++Iter; + if (Iter == 32) { + Relax = 0.5; + } + if (Iter == 65) { + Relax = 0.25; + } + } + + // warning if not converged + if (Iter > (MaxIterCycl - 1)) { + if (maxIterIndex == 0) { + ShowWarningMessage( + state, + EnergyPlus::format("ZoneHVAC:FourPipeFanCoil=\"{}\" -- Exceeded max iterations while adjusting cycling fan sensible " + "runtime to meet the zone load within the {} convergence tolerance.", + fcuName, + modeLabel)); + if (modeLabel == "heating") { + ShowContinueError(state, EnergyPlus::format("...Requested zone load = {:.3T} [W]", QZnReq)); + ShowContinueError(state, EnergyPlus::format("...Fan coil capacity = {:.3T} [W]", QUnitOut)); + } + ShowContinueErrorTimeStamp(state, EnergyPlus::format("Iterations={}", MaxIterCycl)); + } + ShowRecurringWarningErrorAtEnd(state, + "ZoneHVAC:FourPipeFanCoil=\"" + fcuName + + "\" -- Exceeded max iterations error (sensible runtime) continues...", + maxIterIndex); + } + } + + // Handle flow-locked bypass logic for ConsFanVarFlow water coil control. + // When the plant flow is locked at a higher rate than needed, compute + // the coil output at the needed rate and then blend the bypass flow + // with the coil outlet to correct temperature and enthalpy. + static void calcFlowLockedBypass(EnergyPlusData &state, + int const FanCoilNum, + int const ControlledZoneNum, + bool const FirstHVACIteration, + int const inletNode, + int const outletNode, + Real64 const mdotLock, + Real64 const waterFlow, + Real64 &QUnitOut) + { + if (mdotLock > waterFlow) { + Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); + state.dataLoopNodes->Node(inletNode).MassFlowRate = mdotLock; + state.dataLoopNodes->Node(outletNode).MassFlowRate = mdotLock; + Real64 const bypassFlow = mdotLock - waterFlow; + state.dataLoopNodes->Node(outletNode).Temp = + (bypassFlow * state.dataLoopNodes->Node(inletNode).Temp + waterFlow * state.dataLoopNodes->Node(outletNode).Temp) / mdotLock; + state.dataLoopNodes->Node(outletNode).Enthalpy = + (bypassFlow * state.dataLoopNodes->Node(inletNode).Enthalpy + waterFlow * state.dataLoopNodes->Node(outletNode).Enthalpy) / mdotLock; + } else { + state.dataLoopNodes->Node(inletNode).MassFlowRate = mdotLock; + state.dataLoopNodes->Node(outletNode).MassFlowRate = mdotLock; + Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); + } + } + void Sim4PipeFanCoil(EnergyPlusData &state, int &FanCoilNum, // number of the current fan coil unit being simulated int const ControlledZoneNum, // index into ZoneEqupConfig @@ -1987,7 +2177,6 @@ namespace FanCoilUnits { Real64 QUnitOutMaxH; // unit output with full active heating [W] Real64 SpecHumOut; // Specific humidity ratio of outlet air (kg moisture / kg moist air) Real64 SpecHumIn; // Specific humidity ratio of inlet air (kg moisture / kg moist air) - Real64 DelPLR; Real64 mdot; // Real64 Low_mdot; Real64 QSensUnitOutNoATM; // unit output not including air added by supply side air terminal mixer @@ -1998,8 +2187,7 @@ namespace FanCoilUnits { Real64 MinSAMassFlowRate; // minimum supply air mass flow rate [kg/s] Real64 MaxSAMassFlowRate; // maximum supply air mass flow rate [kg/s] // Real64 FCOutletTempOn; // ASHRAE outlet air temperature when coil is on [C] - Real64 CWFlow; // cold water mass flow rate solution [kg/s] - Real64 CWFlowBypass; // cold water bypassed mass flow rate [kg/s] + Real64 CWFlow; // cold water mass flow rate solution [kg/s] auto &fanCoil = state.dataFanCoilUnits->FanCoil(FanCoilNum); @@ -2019,15 +2207,11 @@ namespace FanCoilUnits { int OutletNode = fanCoil.AirOutNode; int InletNode = fanCoil.AirInNode; Real64 AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate; // air mass flow rate [kg/sec] - Real64 Error = 1.0; // Error between QZnReq and QUnitOut - Real64 AbsError = 2.0 * HVAC::SmallLoad; // Absolute error between QZnReq and QUnitOut [W] !FB - Real64 Relax = 1.0; - Real64 HWFlow = 0.0; // hot water mass flow rate solution [kg/s] - Real64 HWFlowBypass = 0.0; // hot water bypassed mass flow rate [kg/s] - Real64 MdotLockH = 0.0; // saved value of locked chilled water mass flow rate [kg/s] - Real64 MdotLockC = 0.0; // saved value of locked hot water mass flow rate [kg/s] - bool ColdFlowLocked = false; // if true cold water flow is locked - bool HotFlowLocked = false; // if true Hot water flow is locked + Real64 HWFlow = 0.0; // hot water mass flow rate solution [kg/s] + Real64 MdotLockH = 0.0; // saved value of locked chilled water mass flow rate [kg/s] + Real64 MdotLockC = 0.0; // saved value of locked hot water mass flow rate [kg/s] + bool ColdFlowLocked = false; // if true cold water flow is locked + bool HotFlowLocked = false; // if true Hot water flow is locked // select capacity control method switch (fanCoil.CapCtrlMeth_Num) { @@ -2113,46 +2297,39 @@ namespace FanCoilUnits { MinWaterFlow, MaxWaterFlow); General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, CWFlow, f, MinWaterFlow, MaxWaterFlow); - if (SolFlag == -1) { - ++fanCoil.ConvgErrCountC; - if (fanCoil.ConvgErrCountC < 2) { - ShowWarningError(state, EnergyPlus::format("Cold Water control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Iteration limit exceeded in calculating water flow rate "); - state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate = CWFlow; - Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut)); - ShowContinueErrorTimeStamp( - state, - EnergyPlus::format("Min water flow used during iterations = {}, Max water flow used during iterations = {}", + reportWaterFlowSolveRootErrors(state, + SolFlag, + "Cold Water", + fanCoil.Name, + FanCoilNum, + ControlledZoneNum, + FirstHVACIteration, + fanCoil.CoolCoilFluidInletNode, + CWFlow, + QZnReq, MinWaterFlow, - MaxWaterFlow)); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Water flow rate on last iteration = {}", CWFlow)); - ShowContinueErrorTimeStamp(state, "..Water flow rate set to last iteration value "); - } else { - ShowRecurringWarningErrorAtEnd( - state, "Cold water flow Iteration limit exceeded in fan coil unit " + fanCoil.Name, fanCoil.MaxIterIndexC); - } - } else if (SolFlag == -2) { - ++fanCoil.LimitErrCountC; - if (fanCoil.LimitErrCountC < 2) { - ShowWarningError(state, EnergyPlus::format("Cold Water control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Bad cold water mass flow limits"); - ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit "); - } else { - ShowRecurringWarningErrorAtEnd( - state, "Cold Water control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexC); - } - } + MaxWaterFlow, + fanCoil.ConvgErrCountC, + fanCoil.LimitErrCountC, + fanCoil.MaxIterIndexC, + fanCoil.BadMassFlowLimIndexC); } else if (SolFlag == -2) { - ++fanCoil.LimitErrCountC; - if (fanCoil.LimitErrCountC < 2) { - ShowWarningError(state, EnergyPlus::format("Cold Water control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Bad cold water mass flow limits"); - ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit "); - } else { - ShowRecurringWarningErrorAtEnd( - state, "Cold Water control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexC); - } + reportWaterFlowSolveRootErrors(state, + SolFlag, + "Cold Water", + fanCoil.Name, + FanCoilNum, + ControlledZoneNum, + FirstHVACIteration, + fanCoil.CoolCoilFluidInletNode, + CWFlow, + QZnReq, + MinWaterFlow, + MaxWaterFlow, + fanCoil.ConvgErrCountC, + fanCoil.LimitErrCountC, + fanCoil.MaxIterIndexC, + fanCoil.BadMassFlowLimIndexC); } } else { // demand greater than capacity @@ -2164,34 +2341,15 @@ namespace FanCoilUnits { state, mdot, fanCoil.CoolCoilFluidInletNode, fanCoil.CoolCoilFluidOutletNodeNum, fanCoil.CoolCoilPlantLoc); Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); // get QUnitOut } else { - // flow lock on - if (MdotLockC > CWFlow) { // if mdot > CWFlow, bypass extra flow - Calc4PipeFanCoil(state, + calcFlowLockedBypass(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, - QUnitOut); // get QUnitOut with CWFlow; rest will be bypassed - state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate = - MdotLockC; // reset flow to locked value. Since lock is on, must do this by hand - state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).MassFlowRate = MdotLockC; - // Keep soln flow rate but reset outlet water temperature - i.e. bypass extra water - CWFlowBypass = MdotLockC - CWFlow; - // change water outlet temperature and enthalpy - state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Temp = - (CWFlowBypass * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).Temp + - CWFlow * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Temp) / - MdotLockC; - state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Enthalpy = - (CWFlowBypass * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).Enthalpy + - CWFlow * state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).Enthalpy) / - MdotLockC; - } else { - // if MdotLockC <= CWFlow use MdotLockC as is - state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate = - MdotLockC; // reset flow to locked value. Since lock is on, must do this by hand - state.dataLoopNodes->Node(fanCoil.CoolCoilFluidOutletNodeNum).MassFlowRate = MdotLockC; - Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); - } + fanCoil.CoolCoilFluidInletNode, + fanCoil.CoolCoilFluidOutletNodeNum, + MdotLockC, + CWFlow, + QUnitOut); } QUnitOut = calcZoneSensibleOutput(AirMassFlow, state.dataLoopNodes->Node(OutletNode).Temp, @@ -2259,46 +2417,39 @@ namespace FanCoilUnits { MinWaterFlow, MaxWaterFlow); General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, HWFlow, f, MinWaterFlow, MaxWaterFlow); - if (SolFlag == -1) { - ++fanCoil.ConvgErrCountH; - if (fanCoil.ConvgErrCountH < 2) { - ShowWarningError(state, EnergyPlus::format("Hot Water control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Iteration limit exceeded in calculating water flow rate "); - state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate = HWFlow; - Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut)); - ShowContinueErrorTimeStamp( - state, - EnergyPlus::format("Min water flow used during iterations = {}, Max water flow used during iterations = {}", + reportWaterFlowSolveRootErrors(state, + SolFlag, + "Hot Water", + fanCoil.Name, + FanCoilNum, + ControlledZoneNum, + FirstHVACIteration, + fanCoil.HeatCoilFluidInletNode, + HWFlow, + QZnReq, MinWaterFlow, - MaxWaterFlow)); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Water flow rate on last iteration = {}", HWFlow)); - ShowContinueErrorTimeStamp(state, "..Water flow rate set to last iteration value "); - } else { - ShowRecurringWarningErrorAtEnd( - state, "Hot water flow Iteration limit exceeded in fan coil unit " + fanCoil.Name, fanCoil.MaxIterIndexH); - } - } else if (SolFlag == -2) { - ++fanCoil.LimitErrCountH; - if (fanCoil.LimitErrCountH < 2) { - ShowWarningError(state, EnergyPlus::format("Hot Water control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Bad hot water mass flow limits"); - ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit "); - } else { - ShowRecurringWarningErrorAtEnd( - state, "Hot Water control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexH); - } - } + MaxWaterFlow, + fanCoil.ConvgErrCountH, + fanCoil.LimitErrCountH, + fanCoil.MaxIterIndexH, + fanCoil.BadMassFlowLimIndexH); } else if (SolFlag == -2) { - ++fanCoil.LimitErrCountH; - if (fanCoil.LimitErrCountH < 2) { - ShowWarningError(state, EnergyPlus::format("Hot Water control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Bad hot water mass flow limits"); - ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit "); - } else { - ShowRecurringWarningErrorAtEnd( - state, "Hot Water control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexH); - } + reportWaterFlowSolveRootErrors(state, + SolFlag, + "Hot Water", + fanCoil.Name, + FanCoilNum, + ControlledZoneNum, + FirstHVACIteration, + fanCoil.HeatCoilFluidInletNode, + HWFlow, + QZnReq, + MinWaterFlow, + MaxWaterFlow, + fanCoil.ConvgErrCountH, + fanCoil.LimitErrCountH, + fanCoil.MaxIterIndexH, + fanCoil.BadMassFlowLimIndexH); } } else { auto f = [&state, FirstHVACIteration, FanCoilNum, ControlledZoneNum, QZnReq](Real64 const PartLoadRatio) { @@ -2321,34 +2472,15 @@ namespace FanCoilUnits { state, mdot, fanCoil.HeatCoilFluidInletNode, fanCoil.HeatCoilFluidOutletNodeNum, fanCoil.HeatCoilPlantLoc); Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); // get QUnitOut } else { - // flow lock on - if (MdotLockH > HWFlow) { // if mdot > HWFlow, bypass extra flow - Calc4PipeFanCoil(state, + calcFlowLockedBypass(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, - QUnitOut); // get QUnitOut with HWFlow; rest will be bypassed - state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate = - MdotLockH; // reset flow to locked value. Since lock is on, must do this by hand - state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).MassFlowRate = MdotLockH; - // Keep soln flow rate but reset outlet water temperature - i.e. bypass extra water - HWFlowBypass = MdotLockH - HWFlow; - // change outlet water temperature and enthalpy - state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Temp = - (HWFlowBypass * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).Temp + - HWFlow * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Temp) / - MdotLockH; - state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Enthalpy = - (HWFlowBypass * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).Enthalpy + - HWFlow * state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).Enthalpy) / - MdotLockH; - } else { - // if MdotLockH <= HWFlow use MdotLockH as is - state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate = - MdotLockH; // reset flow to locked value. Since lock is on, must do this by hand - state.dataLoopNodes->Node(fanCoil.HeatCoilFluidOutletNodeNum).MassFlowRate = MdotLockH; - Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); - } + fanCoil.HeatCoilFluidInletNode, + fanCoil.HeatCoilFluidOutletNodeNum, + MdotLockH, + HWFlow, + QUnitOut); } } QUnitOut = calcZoneSensibleOutput(AirMassFlow, @@ -2478,48 +2610,41 @@ namespace FanCoilUnits { PLRMin, PLRMax); General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, PLRMin, PLRMax); - if (SolFlag == -1) { - ++fanCoil.ConvgErrCountC; - if (fanCoil.ConvgErrCountC < 2) { - ShowWarningError(state, - EnergyPlus::format("Part-load ratio cooling control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Iteration limit exceeded in calculating FCU part-load ratio "); - state.dataLoopNodes->Node(fanCoil.CoolCoilFluidInletNode).MassFlowRate = PLR * fanCoil.MaxCoolCoilFluidFlow; - Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut)); - ShowContinueErrorTimeStamp( - state, - EnergyPlus::format( - "Min part-load used during iterations = {}, Max part-load used during iterations = {}", PLRMin, PLRMax)); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Part-load ratio on last iteration = {}", PLR)); - ShowContinueErrorTimeStamp(state, "..Part-load ratio set to last iteration value "); - } else { - ShowRecurringWarningErrorAtEnd(state, - "Part-load ratio cooling iteration limit exceeded in fan coil unit " + fanCoil.Name, - fanCoil.MaxIterIndexC); - } - } else if (SolFlag == -2) { - ++fanCoil.LimitErrCountC; - if (fanCoil.LimitErrCountC < 2) { - ShowWarningError(state, - EnergyPlus::format("Part-load ratio cooling control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Bad part-load ratio limits"); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("..Part-load ratio set to {}", PLRMin)); - } else { - ShowRecurringWarningErrorAtEnd( - state, "Part-load ratio cooling control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexC); - } - } + reportPLRSolveRootErrors(state, + SolFlag, + "cooling", + fanCoil.Name, + FanCoilNum, + ControlledZoneNum, + FirstHVACIteration, + fanCoil.CoolCoilFluidInletNode, + PLR, + fanCoil.MaxCoolCoilFluidFlow, + QZnReq, + PLRMin, + PLRMax, + fanCoil.ConvgErrCountC, + fanCoil.LimitErrCountC, + fanCoil.MaxIterIndexC, + fanCoil.BadMassFlowLimIndexC); } else if (SolFlag == -2) { - ++fanCoil.LimitErrCountC; - if (fanCoil.LimitErrCountC < 2) { - ShowWarningError(state, EnergyPlus::format("Part-load ratio control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Bad part-load ratio limits"); - ShowContinueErrorTimeStamp(state, "..Part-load ratio set to 0"); - } else { - ShowRecurringWarningErrorAtEnd( - state, "Part-load ratio control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexC); - } + reportPLRSolveRootErrors(state, + SolFlag, + "cooling", + fanCoil.Name, + FanCoilNum, + ControlledZoneNum, + FirstHVACIteration, + fanCoil.CoolCoilFluidInletNode, + PLR, + fanCoil.MaxCoolCoilFluidFlow, + QZnReq, + PLRMin, + PLRMax, + fanCoil.ConvgErrCountC, + fanCoil.LimitErrCountC, + fanCoil.MaxIterIndexC, + fanCoil.BadMassFlowLimIndexC); } mdot = PLR * fanCoil.MaxCoolCoilFluidFlow; PlantUtilities::SetComponentFlowRate( @@ -2579,53 +2704,41 @@ namespace FanCoilUnits { PLRMin, PLRMax); General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, PLRMin, PLRMax); - if (SolFlag == -1) { - ++fanCoil.ConvgErrCountH; - if (fanCoil.ConvgErrCountH < 2) { - ShowWarningError(state, - EnergyPlus::format("Part-load ratio heating control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Iteration limit exceeded in calculating FCU part-load ratio "); - state.dataLoopNodes->Node(fanCoil.HeatCoilFluidInletNode).MassFlowRate = PLR * fanCoil.MaxHeatCoilFluidFlow; - Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut)); - ShowContinueErrorTimeStamp( - state, - EnergyPlus::format( - "Min part-load ratio used during iterations = {}, Max part-load used during iterations = {}", - PLRMin, - PLRMax)); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Part-load ratio on last iteration = {}", PLR)); - ShowContinueErrorTimeStamp(state, "..Part-load ratio set to last iteration value "); - } else { - ShowRecurringWarningErrorAtEnd(state, - "Part-load ratio heating iteration limit exceeded in fan coil unit " + - fanCoil.Name, - fanCoil.MaxIterIndexH); - } - } else if (SolFlag == -2) { - ++fanCoil.LimitErrCountH; - if (fanCoil.LimitErrCountH < 2) { - ShowWarningError(state, - EnergyPlus::format("Part-load ratio heating control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Bad hot part-load ratio limits"); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("..Part-load ratio set to {}", PLRMin)); - } else { - ShowRecurringWarningErrorAtEnd(state, - "Part-load ratio heating control failed in fan coil unit " + fanCoil.Name, - fanCoil.BadMassFlowLimIndexH); - } - } + reportPLRSolveRootErrors(state, + SolFlag, + "heating", + fanCoil.Name, + FanCoilNum, + ControlledZoneNum, + FirstHVACIteration, + fanCoil.HeatCoilFluidInletNode, + PLR, + fanCoil.MaxHeatCoilFluidFlow, + QZnReq, + PLRMin, + PLRMax, + fanCoil.ConvgErrCountH, + fanCoil.LimitErrCountH, + fanCoil.MaxIterIndexH, + fanCoil.BadMassFlowLimIndexH); } else if (SolFlag == -2) { - ++fanCoil.LimitErrCountH; - if (fanCoil.LimitErrCountH < 2) { - ShowWarningError(state, - EnergyPlus::format("Part-load ratio heating control failed in fan coil unit {}", fanCoil.Name)); - ShowContinueError(state, " Bad part-load ratio limits"); - ShowContinueErrorTimeStamp(state, "..Part-load ratio set to 0"); - } else { - ShowRecurringWarningErrorAtEnd( - state, "Part-load ratio heating control failed in fan coil unit " + fanCoil.Name, fanCoil.BadMassFlowLimIndexH); - } + reportPLRSolveRootErrors(state, + SolFlag, + "heating", + fanCoil.Name, + FanCoilNum, + ControlledZoneNum, + FirstHVACIteration, + fanCoil.HeatCoilFluidInletNode, + PLR, + fanCoil.MaxHeatCoilFluidFlow, + QZnReq, + PLRMin, + PLRMax, + fanCoil.ConvgErrCountH, + fanCoil.LimitErrCountH, + fanCoil.MaxIterIndexH, + fanCoil.BadMassFlowLimIndexH); } HWFlow = PLR * fanCoil.MaxHeatCoilFluidFlow; PlantUtilities::SetComponentFlowRate( @@ -2845,7 +2958,6 @@ namespace FanCoilUnits { QUnitOutNoHC, 0.0); // needs PLR=0 for electric heating coil, otherwise will run at full capacity - int Iter = 0; if (UnitOn && state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP < (-1.0 * HVAC::SmallLoad) && state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::SetptType::SingleHeat) { // cooling coil action, maximum cold water flow @@ -2865,38 +2977,19 @@ namespace FanCoilUnits { PLR = 1.0; } - // adjust the PLR to meet the cooling load calling Calc4PipeFanCoil repeatedly with the PLR adjusted - while (std::abs(Error) > ControlOffset && std::abs(AbsError) > HVAC::SmallLoad && Iter < MaxIterCycl && PLR != 1.0) { - Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR); - Error = (QZnReq - QUnitOut) / QZnReq; - AbsError = QZnReq - QUnitOut; - DelPLR = (QZnReq - QUnitOut) / QUnitOutMax; - PLR += Relax * DelPLR; - PLR = max(0.0, min(1.0, PLR)); - ++Iter; - if (Iter == 32) { - Relax = 0.5; - } - if (Iter == 65) { - Relax = 0.25; - } - } - - // warning if not converged - if (Iter > (MaxIterCycl - 1)) { - if (fanCoil.MaxIterIndexC == 0) { - ShowWarningMessage( - state, - EnergyPlus::format("ZoneHVAC:FourPipeFanCoil=\"{}\" -- Exceeded max iterations while adjusting cycling fan sensible " - "runtime to meet the zone load within the cooling convergence tolerance.", - fanCoil.Name)); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Iterations={}", MaxIterCycl)); - } - ShowRecurringWarningErrorAtEnd(state, - "ZoneHVAC:FourPipeFanCoil=\"" + fanCoil.Name + - "\" -- Exceeded max iterations error (sensible runtime) continues...", - fanCoil.MaxIterIndexC); - } + iterateFanCoilPLR(state, + FanCoilNum, + ControlledZoneNum, + FirstHVACIteration, + QZnReq, + QUnitOutMax, + ControlOffset, + MaxIterCycl, + PLR, + QUnitOut, + "cooling", + fanCoil.Name, + fanCoil.MaxIterIndexC); // at the end calculate output with adjusted PLR Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR); @@ -2922,40 +3015,19 @@ namespace FanCoilUnits { PLR = 1.0; } - // adjust the PLR to meet the heating load calling Calc4PipeFanCoil repeatedly with the PLR adjusted - while (std::abs(Error) > ControlOffset && std::abs(AbsError) > HVAC::SmallLoad && Iter < MaxIterCycl && PLR != 1.0) { - Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR); - Error = (QZnReq - QUnitOut) / QZnReq; - AbsError = QZnReq - QUnitOut; - DelPLR = (QZnReq - QUnitOut) / QUnitOutMax; - PLR += Relax * DelPLR; - PLR = max(0.0, min(1.0, PLR)); - ++Iter; - if (Iter == 32) { - Relax = 0.5; - } - if (Iter == 65) { - Relax = 0.25; - } - } - - // warning if not converged - if (Iter > (MaxIterCycl - 1)) { - if (fanCoil.MaxIterIndexH == 0) { - ShowWarningMessage( - state, - EnergyPlus::format("ZoneHVAC:FourPipeFanCoil=\"{}\" -- Exceeded max iterations while adjusting cycling fan sensible " - "runtime to meet the zone load within the heating convergence tolerance.", - fanCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...Requested zone load = {:.3T} [W]", QZnReq)); - ShowContinueError(state, EnergyPlus::format("...Fan coil capacity = {:.3T} [W]", QUnitOut)); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Iterations={}", MaxIterCycl)); - } - ShowRecurringWarningErrorAtEnd(state, - "ZoneHVAC:FourPipeFanCoil=\"" + fanCoil.Name + - "\" -- Exceeded max iterations error (sensible runtime) continues...", - fanCoil.MaxIterIndexH); - } + iterateFanCoilPLR(state, + FanCoilNum, + ControlledZoneNum, + FirstHVACIteration, + QZnReq, + QUnitOutMax, + ControlOffset, + MaxIterCycl, + PLR, + QUnitOut, + "heating", + fanCoil.Name, + fanCoil.MaxIterIndexH); // at the end calculate output with adjusted PLR Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR); diff --git a/src/EnergyPlus/FaultsManager.cc b/src/EnergyPlus/FaultsManager.cc index a2c709be890..fb525719b9e 100644 --- a/src/EnergyPlus/FaultsManager.cc +++ b/src/EnergyPlus/FaultsManager.cc @@ -200,6 +200,82 @@ namespace FaultsManager { constexpr std::array(FouledCoil::Num)> FouledCoilNamesUC{"FOULEDUARATED", "FOULINGFACTOR"}; + // Helper: emit a warning that a chiller is not water-cooled and the fault model won't apply. + static void showChillerNotWaterCooledWarning(EnergyPlusData &state, + std::string const &faultObjType, + std::string const &faultName, + std::string const &fieldName, + std::string const &fieldValue) + { + ShowWarningError(state, + EnergyPlus::format("{} = \"{}\" invalid {} = \"{}\". The specified chiller is not water cooled. The chiller fouling " + "fault model will not be applied.", + faultObjType, + faultName, + fieldName, + fieldValue)); + } + + // Helper: emit a "not found" severe error for a fault equipment lookup failure. + static void showFaultEquipNotFoundError(EnergyPlusData &state, + std::string const &faultObjType, + std::string const &faultName, + std::string const &fieldName, + std::string const &fieldValue, + bool &errorsFound) + { + ShowSevereError(state, EnergyPlus::format("{} = \"{}\" invalid {} = \"{}\" not found.", faultObjType, faultName, fieldName, fieldValue)); + errorsFound = true; + } + + // Helper: validate that a required alpha field is not blank; if blank, emit a severe error. + static void validateRequiredAlphaField(EnergyPlusData &state, + std::string const &faultObjType, + std::string const &faultName, + Array1D_string const &alphaFieldNames, + Array1D_string const &alphaArgs, + Array1D_bool const &alphaFieldBlanks, + int fieldIdx, + bool &errorsFound) + { + if (alphaFieldBlanks(fieldIdx)) { + ShowSevereError(state, + EnergyPlus::format( + "{} = \"{}\" invalid {} = \"{}\" blank.", faultObjType, faultName, alphaFieldNames(fieldIdx), alphaArgs(fieldIdx))); + errorsFound = true; + } + } + + // Helper: read the availability and severity schedule fields that are common to most fault objects. + // alphaFieldBlanks / alphaArgs / alphaFieldNames are 1-based arrays; availIdx and severityIdx + // give the positions of the two schedule fields within them. + static void readFaultSchedules(EnergyPlusData &state, + FaultProperties &fault, + ErrorObjectHeader const &eoh, + Array1D_string const &alphaArgs, + Array1D_bool const &alphaFieldBlanks, + Array1D_string const &alphaFieldNames, + int availIdx, + int severityIdx, + bool &errorsFound) + { + // Availability schedule + if (alphaFieldBlanks(availIdx)) { + fault.availSched = Sched::GetScheduleAlwaysOn(state); + } else if ((fault.availSched = Sched::GetSchedule(state, alphaArgs(availIdx))) == nullptr) { + ShowSevereItemNotFound(state, eoh, alphaFieldNames(availIdx), alphaArgs(availIdx)); + errorsFound = true; + } + + // Severity schedule + if (alphaFieldBlanks(severityIdx)) { + fault.severitySched = Sched::GetScheduleAlwaysOn(state); + } else if ((fault.severitySched = Sched::GetSchedule(state, alphaArgs(severityIdx))) == nullptr) { + ShowSevereItemNotFound(state, eoh, alphaFieldNames(severityIdx), alphaArgs(severityIdx)); + errorsFound = true; + } + } + void CheckAndReadFaults(EnergyPlusData &state) { @@ -357,44 +433,20 @@ namespace FaultsManager { faultsECFouling.type = FaultType::Fouling_EvapCooler; faultsECFouling.Name = cAlphaArgs(1); - // Fault availability schedule - if (lAlphaFieldBlanks(2)) { - faultsECFouling.availSched = Sched::GetScheduleAlwaysOn(state); // returns schedule value of 1 - } else if ((faultsECFouling.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2)); - state.dataFaultsMgr->ErrorsFound = true; - } - - // Fault severity schedule - if (lAlphaFieldBlanks(3)) { - faultsECFouling.severitySched = Sched::GetScheduleAlwaysOn(state); // not an availability schedule, but defaults to constant-1.0 - } else if ((faultsECFouling.severitySched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - state.dataFaultsMgr->ErrorsFound = true; - } + readFaultSchedules(state, faultsECFouling, eoh, cAlphaArgs, lAlphaFieldBlanks, cAlphaFieldNames, 2, 3, state.dataFaultsMgr->ErrorsFound); // CapReductionFactor - degree of fault faultsECFouling.FoulingFactor = rNumericArgs(1); // Evaporative cooler type faultsECFouling.EvapCoolerType = cAlphaArgs(4); - if (lAlphaFieldBlanks(4)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 4, state.dataFaultsMgr->ErrorsFound); // Evaporative cooler name faultsECFouling.EvapCoolerName = cAlphaArgs(5); - if (lAlphaFieldBlanks(5)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 5, state.dataFaultsMgr->ErrorsFound); // Evaporative cooler check if (Util::SameString(faultsECFouling.EvapCoolerType, "EvaporativeCooler:Indirect:WetCoil")) { @@ -408,11 +460,8 @@ namespace FaultsManager { int EvapCoolerNum = Util::FindItemInList(faultsECFouling.EvapCoolerName, state.dataEvapCoolers->EvapCond, &EvaporativeCoolers::EvapConditions::Name); if (EvapCoolerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the boiler with the fault model state.dataEvapCoolers->EvapCond(EvapCoolerNum).FaultyEvapCoolerFoulingFlag = true; @@ -443,44 +492,21 @@ namespace FaultsManager { faultsChillerFouling.type = FaultType::Fouling_Chiller; faultsChillerFouling.Name = cAlphaArgs(1); - // Fault availability schedule - if (lAlphaFieldBlanks(2)) { - faultsChillerFouling.availSched = Sched::GetScheduleAlwaysOn(state); // returns schedule value of 1 - } else if ((faultsChillerFouling.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2)); - state.dataFaultsMgr->ErrorsFound = true; - } - - // Fault severity schedule - if (lAlphaFieldBlanks(3)) { - faultsChillerFouling.severitySched = Sched::GetScheduleAlwaysOn(state); // not an availability schedule, but defaults to constant-1.0 - } else if ((faultsChillerFouling.severitySched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - state.dataFaultsMgr->ErrorsFound = true; - } + readFaultSchedules( + state, faultsChillerFouling, eoh, cAlphaArgs, lAlphaFieldBlanks, cAlphaFieldNames, 2, 3, state.dataFaultsMgr->ErrorsFound); // CapReductionFactor - degree of fault faultsChillerFouling.FoulingFactor = rNumericArgs(1); // Chiller type faultsChillerFouling.ChillerType = cAlphaArgs(4); - if (lAlphaFieldBlanks(4)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 4, state.dataFaultsMgr->ErrorsFound); // Chiller name faultsChillerFouling.ChillerName = cAlphaArgs(5); - if (lAlphaFieldBlanks(5)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 5, state.dataFaultsMgr->ErrorsFound); // Chiller check int ChillerNum; @@ -498,23 +524,13 @@ namespace FaultsManager { } } if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { if (state.dataPlantChillers->ElectricChiller(ChillerNum).CondenserType != DataPlant::CondenserType::WaterCooled) { // The fault model is only applicable to the chillers with water based condensers - ShowWarningError( - state, - EnergyPlus::format("{} = \"{}\" invalid {} = \"{}\". The specified chiller is not water cooled. The chiller fouling " - "fault model will not be applied.", - cFaultCurrentObject, - cAlphaArgs(1), - cAlphaFieldNames(5), - cAlphaArgs(5))); + showChillerNotWaterCooledWarning(state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)); } else { // Link the chiller with the fault model @@ -533,23 +549,13 @@ namespace FaultsManager { // Check whether the chiller name and chiller type match each other ChillerNum = Util::FindItemInList(faultsChillerFouling.ChillerName, state.dataChillerElectricEIR->ElectricEIRChiller); if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { if (state.dataChillerElectricEIR->ElectricEIRChiller(ChillerNum).CondenserType != DataPlant::CondenserType::WaterCooled) { // The fault model is only applicable to the chillers with water based condensers - ShowWarningError( - state, - EnergyPlus::format("{} = \"{}\" invalid {} = \"{}\". The specified chiller is not water cooled. The chiller fouling " - "fault model will not be applied.", - cFaultCurrentObject, - cAlphaArgs(1), - cAlphaFieldNames(5), - cAlphaArgs(5))); + showChillerNotWaterCooledWarning(state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)); } else { // Link the chiller with the fault model @@ -568,23 +574,13 @@ namespace FaultsManager { // Check whether the chiller name and chiller type match each other ChillerNum = Util::FindItemInList(faultsChillerFouling.ChillerName, state.dataChillerReformulatedEIR->ElecReformEIRChiller); if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { if (state.dataChillerReformulatedEIR->ElecReformEIRChiller(ChillerNum).CondenserType != DataPlant::CondenserType::WaterCooled) { // The fault model is only applicable to the chillers with water based condensers - ShowWarningError( - state, - EnergyPlus::format("{} = \"{}\" invalid {} = \"{}\". The specified chiller is not water cooled. The chiller fouling " - "fault model will not be applied.", - cFaultCurrentObject, - cAlphaArgs(1), - cAlphaFieldNames(5), - cAlphaArgs(5))); + showChillerNotWaterCooledWarning(state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)); } else { // Link the chiller with the fault model @@ -604,23 +600,13 @@ namespace FaultsManager { } } if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { if (state.dataPlantChillers->ConstCOPChiller(ChillerNum).CondenserType != DataPlant::CondenserType::WaterCooled) { // The fault model is only applicable to the chillers with water based condensers - ShowWarningError( - state, - EnergyPlus::format("{} = \"{}\" invalid {} = \"{}\". The specified chiller is not water cooled. The chiller fouling " - "fault model will not be applied.", - cFaultCurrentObject, - cAlphaArgs(1), - cAlphaFieldNames(5), - cAlphaArgs(5))); + showChillerNotWaterCooledWarning(state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)); } else { // Link the chiller with the fault model @@ -640,23 +626,13 @@ namespace FaultsManager { } } if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { if (state.dataPlantChillers->EngineDrivenChiller(ChillerNum).CondenserType != DataPlant::CondenserType::WaterCooled) { // The fault model is only applicable to the chillers with water based condensers - ShowWarningError( - state, - EnergyPlus::format("{} = \"{}\" invalid {} = \"{}\". The specified chiller is not water cooled. The chiller fouling " - "fault model will not be applied.", - cFaultCurrentObject, - cAlphaArgs(1), - cAlphaFieldNames(5), - cAlphaArgs(5))); + showChillerNotWaterCooledWarning(state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)); } else { // Link the fault model with the water cooled chiller @@ -676,22 +652,12 @@ namespace FaultsManager { } } if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { if (state.dataPlantChillers->GTChiller(ChillerNum).CondenserType != DataPlant::CondenserType::WaterCooled) { // The fault model is only applicable to the chillers with water based condensers - ShowWarningError( - state, - EnergyPlus::format("{} = \"{}\" invalid {} = \"{}\". The specified chiller is not water cooled. The chiller fouling " - "fault model will not be applied.", - cFaultCurrentObject, - cAlphaArgs(1), - cAlphaFieldNames(5), - cAlphaArgs(5))); + showChillerNotWaterCooledWarning(state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)); } else { // Link the fault model with the water cooled chiller @@ -727,44 +693,21 @@ namespace FaultsManager { faultsBoilerFouling.type = FaultType::Fouling_Boiler; faultsBoilerFouling.Name = cAlphaArgs(1); - // Fault availability schedule - if (lAlphaFieldBlanks(2)) { - faultsBoilerFouling.availSched = Sched::GetScheduleAlwaysOn(state); // returns schedule value of 1 - } else if ((faultsBoilerFouling.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2)); - state.dataFaultsMgr->ErrorsFound = true; - } - - // Fault severity schedule - if (lAlphaFieldBlanks(3)) { - faultsBoilerFouling.severitySched = Sched::GetScheduleAlwaysOn(state); // not an availability schedule, but defaults to constant-1.0 - } else if ((faultsBoilerFouling.severitySched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - state.dataFaultsMgr->ErrorsFound = true; - } + readFaultSchedules( + state, faultsBoilerFouling, eoh, cAlphaArgs, lAlphaFieldBlanks, cAlphaFieldNames, 2, 3, state.dataFaultsMgr->ErrorsFound); // CapReductionFactor - degree of fault faultsBoilerFouling.FoulingFactor = rNumericArgs(1); // Boiler type faultsBoilerFouling.BoilerType = cAlphaArgs(4); - if (lAlphaFieldBlanks(4)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 4, state.dataFaultsMgr->ErrorsFound); // Boiler name faultsBoilerFouling.BoilerName = cAlphaArgs(5); - if (lAlphaFieldBlanks(5)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 5, state.dataFaultsMgr->ErrorsFound); // Boiler check and link { @@ -777,11 +720,8 @@ namespace FaultsManager { return b.Name == faultsBoilerFouling.BoilerName; }); if (boiler_it == state.dataBoilers->Boiler.end()) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the boiler with the fault model boiler_it->FaultyBoilerFoulingFlag = true; @@ -812,44 +752,21 @@ namespace FaultsManager { faultsCoilSATFouling.type = FaultType::TemperatureSensorOffset_CoilSupplyAir; faultsCoilSATFouling.Name = cAlphaArgs(1); - // Fault availability schedule - if (lAlphaFieldBlanks(2)) { - faultsCoilSATFouling.availSched = Sched::GetScheduleAlwaysOn(state); // returns schedule value of 1 - } else if ((faultsCoilSATFouling.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2)); - state.dataFaultsMgr->ErrorsFound = true; - } - - // Fault severity schedule - if (lAlphaFieldBlanks(3)) { - faultsCoilSATFouling.severitySched = Sched::GetScheduleAlwaysOn(state); // not an availability schedule, but defaults to constant-1.0 - } else if ((faultsCoilSATFouling.severitySched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - state.dataFaultsMgr->ErrorsFound = true; - } + readFaultSchedules( + state, faultsCoilSATFouling, eoh, cAlphaArgs, lAlphaFieldBlanks, cAlphaFieldNames, 2, 3, state.dataFaultsMgr->ErrorsFound); // offset - degree of fault faultsCoilSATFouling.Offset = rNumericArgs(1); // Coil type faultsCoilSATFouling.CoilType = cAlphaArgs(4); - if (lAlphaFieldBlanks(4)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 4, state.dataFaultsMgr->ErrorsFound); // Coil name faultsCoilSATFouling.CoilName = cAlphaArgs(5); - if (lAlphaFieldBlanks(5)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 5, state.dataFaultsMgr->ErrorsFound); // Coil check and link CoilType CoilTypeCheck = static_cast(getEnumValue(CoilTypeNamesUC, Util::makeUPPER(faultsCoilSATFouling.CoilType))); @@ -865,11 +782,8 @@ namespace FaultsManager { // Check the coil name and coil type int CoilNum = Util::FindItemInList(faultsCoilSATFouling.CoilName, state.dataHeatingCoils->HeatingCoil); if (CoilNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the coil with the fault model state.dataHeatingCoils->HeatingCoil(CoilNum).FaultyCoilSATFlag = true; @@ -885,11 +799,8 @@ namespace FaultsManager { // Check the coil name and coil type int CoilNum = Util::FindItemInList(faultsCoilSATFouling.CoilName, state.dataSteamCoils->SteamCoil); if (CoilNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { if (state.dataSteamCoils->SteamCoil(CoilNum).TypeOfCoil != SteamCoils::CoilControlType::TemperatureSetPoint) { @@ -920,22 +831,14 @@ namespace FaultsManager { // Check the coil name and coil type int CoilNum = Util::FindItemInList(faultsCoilSATFouling.CoilName, state.dataWaterCoils->WaterCoil); if (CoilNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } // Read in Water Coil Controller Name faultsCoilSATFouling.WaterCoilControllerName = cAlphaArgs(6); - if (lAlphaFieldBlanks(6)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(6), cAlphaArgs(6))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 6, state.dataFaultsMgr->ErrorsFound); // Read in controller input if not done yet if (state.dataHVACControllers->GetControllerInputFlag) { HVACControllers::GetControllerInput(state); @@ -946,11 +849,8 @@ namespace FaultsManager { state.dataHVACControllers->ControllerProps, &HVACControllers::ControllerPropsType::ControllerName); if (ControlNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(6), cAlphaArgs(6))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(6), cAlphaArgs(6), state.dataFaultsMgr->ErrorsFound); } else { // Link the controller with the fault model state.dataHVACControllers->ControllerProps(ControlNum).FaultyCoilSATFlag = true; @@ -1002,11 +902,8 @@ namespace FaultsManager { // Check the coil name and coil type int CoilSysNum = Util::FindItemInList(faultsCoilSATFouling.CoilName, state.dataHVACDXHeatPumpSys->DXHeatPumpSystem); if (CoilSysNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the coil system with the fault model state.dataHVACDXHeatPumpSys->DXHeatPumpSystem(CoilSysNum).FaultyCoilSATFlag = true; @@ -1043,44 +940,21 @@ namespace FaultsManager { faultsTowerFouling.type = FaultType::Fouling_Tower; faultsTowerFouling.Name = cAlphaArgs(1); - // Fault availability schedule - if (lAlphaFieldBlanks(2)) { - faultsTowerFouling.availSched = Sched::GetScheduleAlwaysOn(state); // returns schedule value of 1 - } else if ((faultsTowerFouling.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2)); - state.dataFaultsMgr->ErrorsFound = true; - } - - // Fault severity schedule - if (lAlphaFieldBlanks(3)) { - faultsTowerFouling.severitySched = Sched::GetScheduleAlwaysOn(state); // not an availability schedule, but defaults to constant-1.0 - } else if ((faultsTowerFouling.severitySched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - state.dataFaultsMgr->ErrorsFound = true; - } + readFaultSchedules( + state, faultsTowerFouling, eoh, cAlphaArgs, lAlphaFieldBlanks, cAlphaFieldNames, 2, 3, state.dataFaultsMgr->ErrorsFound); // UAReductionFactor - degree of fault faultsTowerFouling.UAReductionFactor = rNumericArgs(1); // Cooling tower type faultsTowerFouling.TowerType = cAlphaArgs(4); - if (lAlphaFieldBlanks(4)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 4, state.dataFaultsMgr->ErrorsFound); // Cooling tower name faultsTowerFouling.TowerName = cAlphaArgs(5); - if (lAlphaFieldBlanks(5)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 5, state.dataFaultsMgr->ErrorsFound); // Tower check and link { @@ -1092,11 +966,8 @@ namespace FaultsManager { // Check the tower name and tower type int TowerNum = Util::FindItemInList(faultsTowerFouling.TowerName, state.dataCondenserLoopTowers->towers); if (TowerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the tower with the fault model state.dataCondenserLoopTowers->towers(TowerNum).FaultyTowerFoulingFlag = true; @@ -1157,44 +1028,21 @@ namespace FaultsManager { faultsCondSWTFouling.type = FaultType::TemperatureSensorOffset_CondenserSupplyWater; faultsCondSWTFouling.Name = cAlphaArgs(1); - // Fault availability schedule - if (lAlphaFieldBlanks(2)) { - faultsCondSWTFouling.availSched = Sched::GetScheduleAlwaysOn(state); // returns schedule value of 1 - } else if ((faultsCondSWTFouling.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2)); - state.dataFaultsMgr->ErrorsFound = true; - } - - // Fault severity schedule - if (lAlphaFieldBlanks(3)) { - faultsCondSWTFouling.severitySched = Sched::GetScheduleAlwaysOn(state); // not an availability schedule, but defaults to constant-1.0 - } else if ((faultsCondSWTFouling.severitySched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - state.dataFaultsMgr->ErrorsFound = true; - } + readFaultSchedules( + state, faultsCondSWTFouling, eoh, cAlphaArgs, lAlphaFieldBlanks, cAlphaFieldNames, 2, 3, state.dataFaultsMgr->ErrorsFound); // offset - degree of fault faultsCondSWTFouling.Offset = rNumericArgs(1); // Cooling tower type faultsCondSWTFouling.TowerType = cAlphaArgs(4); - if (lAlphaFieldBlanks(4)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 4, state.dataFaultsMgr->ErrorsFound); // Cooling tower name faultsCondSWTFouling.TowerName = cAlphaArgs(5); - if (lAlphaFieldBlanks(5)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 5, state.dataFaultsMgr->ErrorsFound); // Tower check and link { @@ -1206,11 +1054,8 @@ namespace FaultsManager { // Check the tower name and tower type int TowerNum = Util::FindItemInList(faultsCondSWTFouling.TowerName, state.dataCondenserLoopTowers->towers); if (TowerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the tower with the fault model state.dataCondenserLoopTowers->towers(TowerNum).FaultyCondenserSWTFlag = true; @@ -1255,44 +1100,20 @@ namespace FaultsManager { faultsChillerSWT.type = FaultType::TemperatureSensorOffset_ChillerSupplyWater; faultsChillerSWT.Name = cAlphaArgs(1); - // Fault availability schedule - if (lAlphaFieldBlanks(2)) { - faultsChillerSWT.availSched = Sched::GetScheduleAlwaysOn(state); // returns schedule value of 1 - } else if ((faultsChillerSWT.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2)); - state.dataFaultsMgr->ErrorsFound = true; - } - - // Fault severity schedule - if (lAlphaFieldBlanks(3)) { - faultsChillerSWT.severitySched = Sched::GetScheduleAlwaysOn(state); // not an availability schedule, but defaults to constant-1.0 - } else if ((faultsChillerSWT.severitySched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - state.dataFaultsMgr->ErrorsFound = true; - } + readFaultSchedules(state, faultsChillerSWT, eoh, cAlphaArgs, lAlphaFieldBlanks, cAlphaFieldNames, 2, 3, state.dataFaultsMgr->ErrorsFound); // offset - degree of fault faultsChillerSWT.Offset = rNumericArgs(1); // Chiller type faultsChillerSWT.ChillerType = cAlphaArgs(4); - if (lAlphaFieldBlanks(4)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 4, state.dataFaultsMgr->ErrorsFound); // Chiller name faultsChillerSWT.ChillerName = cAlphaArgs(5); - if (lAlphaFieldBlanks(5)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 5, state.dataFaultsMgr->ErrorsFound); // Chiller check int ChillerNum; @@ -1309,11 +1130,8 @@ namespace FaultsManager { } } if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the chiller with the fault model state.dataPlantChillers->ElectricChiller(ChillerNum).FaultyChillerSWTFlag = true; @@ -1329,11 +1147,8 @@ namespace FaultsManager { // Check whether the chiller name and chiller type match each other ChillerNum = Util::FindItemInList(faultsChillerSWT.ChillerName, state.dataChillerElectricEIR->ElectricEIRChiller); if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the chiller with the fault model state.dataChillerElectricEIR->ElectricEIRChiller(ChillerNum).FaultyChillerSWTFlag = true; @@ -1349,11 +1164,8 @@ namespace FaultsManager { // Check whether the chiller name and chiller type match each other ChillerNum = Util::FindItemInList(faultsChillerSWT.ChillerName, state.dataChillerReformulatedEIR->ElecReformEIRChiller); if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the chiller with the fault model state.dataChillerReformulatedEIR->ElecReformEIRChiller(ChillerNum).FaultyChillerSWTFlag = true; @@ -1371,11 +1183,8 @@ namespace FaultsManager { } } if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the chiller with the fault model state.dataPlantChillers->EngineDrivenChiller(ChillerNum).FaultyChillerSWTFlag = true; @@ -1392,11 +1201,8 @@ namespace FaultsManager { } } if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the chiller with the fault model state.dataPlantChillers->GTChiller(ChillerNum).FaultyChillerSWTFlag = true; @@ -1413,11 +1219,8 @@ namespace FaultsManager { } } if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the chiller with the fault model state.dataPlantChillers->ConstCOPChiller(ChillerNum).FaultyChillerSWTFlag = true; @@ -1433,11 +1236,8 @@ namespace FaultsManager { // Check whether the chiller name and chiller type match each other ChillerNum = Util::FindItemInList(faultsChillerSWT.ChillerName, state.dataChillerAbsorber->absorptionChillers); if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { // Link the chiller with the fault model state.dataChillerAbsorber->absorptionChillers(ChillerNum).FaultyChillerSWTFlag = true; @@ -1453,11 +1253,8 @@ namespace FaultsManager { // Check whether the chiller name and chiller type match each other ChillerNum = Util::FindItemInList(faultsChillerSWT.ChillerName, state.dataChillerIndirectAbsorption->IndirectAbsorber); if (ChillerNum <= 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" not found.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; + showFaultEquipNotFoundError( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5), state.dataFaultsMgr->ErrorsFound); } else { state.dataChillerIndirectAbsorption->IndirectAbsorber(ChillerNum).FaultyChillerSWTFlag = true; state.dataChillerIndirectAbsorption->IndirectAbsorber(ChillerNum).FaultyChillerSWTIndex = jFault_ChillerSWT; @@ -1587,21 +1384,7 @@ namespace FaultsManager { } else { // For Humidistat Offset Type: ThermostatOffsetIndependent - // Availability schedule - if (lAlphaFieldBlanks(4)) { - faultsHStat.availSched = Sched::GetScheduleAlwaysOn(state); // returns schedule value of 1 - } else if ((faultsHStat.availSched = Sched::GetSchedule(state, cAlphaArgs(4))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(4), cAlphaArgs(4)); - state.dataFaultsMgr->ErrorsFound = true; - } - - // Severity schedule - if (lAlphaFieldBlanks(5)) { - faultsHStat.severitySched = Sched::GetScheduleAlwaysOn(state); // not an availability schedule, but defaults to constant-1.0 - } else if ((faultsHStat.severitySched = Sched::GetSchedule(state, cAlphaArgs(5))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(5), cAlphaArgs(5)); - state.dataFaultsMgr->ErrorsFound = true; - } + readFaultSchedules(state, faultsHStat, eoh, cAlphaArgs, lAlphaFieldBlanks, cAlphaFieldNames, 4, 5, state.dataFaultsMgr->ErrorsFound); // Reference offset value is required for Humidistat Offset Type: ThermostatOffsetIndependent if (lAlphaFieldBlanks(1)) { @@ -1641,21 +1424,7 @@ namespace FaultsManager { faultsTStat.Name = cAlphaArgs(1); faultsTStat.FaultyThermostatName = cAlphaArgs(2); - // Availability schedule - if (lAlphaFieldBlanks(3)) { - faultsTStat.availSched = Sched::GetScheduleAlwaysOn(state); // returns schedule value of 1 - } else if ((faultsTStat.availSched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - state.dataFaultsMgr->ErrorsFound = true; - } - - // Severity schedule - if (lAlphaFieldBlanks(4)) { - faultsTStat.severitySched = Sched::GetScheduleAlwaysOn(state); // not an availability schedule, but defaults to constant-1.0 - } else if ((faultsTStat.severitySched = Sched::GetSchedule(state, cAlphaArgs(4))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(4), cAlphaArgs(4)); - state.dataFaultsMgr->ErrorsFound = true; - } + readFaultSchedules(state, faultsTStat, eoh, cAlphaArgs, lAlphaFieldBlanks, cAlphaFieldNames, 3, 4, state.dataFaultsMgr->ErrorsFound); // Reference offset value is required if (lAlphaFieldBlanks(1)) { @@ -1689,21 +1458,7 @@ namespace FaultsManager { faultsFoulCoil.Name = cAlphaArgs(1); faultsFoulCoil.FouledCoilName = cAlphaArgs(2); - // Availability schedule - if (lAlphaFieldBlanks(3)) { - faultsFoulCoil.availSched = Sched::GetScheduleAlwaysOn(state); // returns schedule value of 1 - } else if ((faultsFoulCoil.availSched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - state.dataFaultsMgr->ErrorsFound = true; - } - - // Severity schedule - if (lAlphaFieldBlanks(4)) { - faultsFoulCoil.severitySched = Sched::GetScheduleAlwaysOn(state); // not an availability schedule, but defaults to constant-1.0 - } else if ((faultsFoulCoil.severitySched = Sched::GetSchedule(state, cAlphaArgs(4))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(4), cAlphaArgs(4)); - state.dataFaultsMgr->ErrorsFound = true; - } + readFaultSchedules(state, faultsFoulCoil, eoh, cAlphaArgs, lAlphaFieldBlanks, cAlphaFieldNames, 3, 4, state.dataFaultsMgr->ErrorsFound); faultsFoulCoil.FoulingInputMethod = static_cast(getEnumValue(FouledCoilNamesUC, Util::makeUPPER(cAlphaArgs(5)))); if (faultsFoulCoil.FoulingInputMethod == FouledCoil::Invalid) { @@ -1852,31 +1607,13 @@ namespace FaultsManager { fault.Name = cAlphaArgs(1); - // check availability schedule - if (lAlphaFieldBlanks(2)) { - fault.availSched = Sched::GetScheduleAlwaysOn(state); // returns schedule value of 1 - } else if ((fault.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2)); - state.dataFaultsMgr->ErrorsFound = true; - } - - // check severity schedule - if (lAlphaFieldBlanks(3)) { - fault.severitySched = Sched::GetScheduleAlwaysOn(state); // not an availability schedule, but defaults to constant-1.0 - } else if ((fault.severitySched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - state.dataFaultsMgr->ErrorsFound = true; - } + readFaultSchedules(state, fault, eoh, cAlphaArgs, lAlphaFieldBlanks, cAlphaFieldNames, 2, 3, state.dataFaultsMgr->ErrorsFound); fault.ControllerType = cAlphaArgs(4); // check controller type - if (lAlphaFieldBlanks(4)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4))); - state.dataFaultsMgr->ErrorsFound = true; - } else { + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 4, state.dataFaultsMgr->ErrorsFound); + if (!lAlphaFieldBlanks(4)) { if (Util::makeUPPER(cAlphaArgs(4)) == "CONTROLLER:OUTDOORAIR") { fault.ControllerTypeEnum = iController_AirEconomizer; @@ -1888,13 +1625,8 @@ namespace FaultsManager { state.dataFaultsMgr->FaultsEconomizer(j).ControllerName = cAlphaArgs(5); // check controller name - if (lAlphaFieldBlanks(5)) { - ShowSevereError( - state, - EnergyPlus::format( - "{} = \"{}\" invalid {} = \"{}\" blank.", cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5))); - state.dataFaultsMgr->ErrorsFound = true; - } + validateRequiredAlphaField( + state, cFaultCurrentObject, cAlphaArgs(1), cAlphaFieldNames, cAlphaArgs, lAlphaFieldBlanks, 5, state.dataFaultsMgr->ErrorsFound); // offset - degree of fault state.dataFaultsMgr->FaultsEconomizer(j).Offset = rNumericArgs(1); diff --git a/src/EnergyPlus/FluidProperties.cc b/src/EnergyPlus/FluidProperties.cc index 4377733066d..4a1bf94a4d4 100644 --- a/src/EnergyPlus/FluidProperties.cc +++ b/src/EnergyPlus/FluidProperties.cc @@ -674,6 +674,115 @@ namespace Fluid { } // InitConstantFluidPropertiesData() + // Helper to initialize one default glycol property (Cp, Rho, Cond, or Visc) from compile-time data. + // This avoids repeating the same 15-line pattern 8 times (4 properties x 2 glycols). + static void initDefaultGlycolProperty(bool &dataPresent, + int &numTempPoints, + int &numConcPoints, + Array1D &temps, + Array1D &concs, + Array2D &values, + std::array, DefaultNumGlyConcs> const &defaultData) + { + dataPresent = true; + numTempPoints = DefaultNumGlyTemps; + numConcPoints = DefaultNumGlyConcs; + + temps.allocate(numTempPoints); + temps = DefaultGlycolTemps; + + concs.allocate(numConcPoints); + concs = DefaultGlycolConcs; + + values.allocate(numConcPoints, numTempPoints); + for (int i = 1; i <= numConcPoints; ++i) { + values(i, {1, numTempPoints}) = defaultData[i - 1]; + } + } + + // Helper to load glycol concentration property values from input into the raw glycol arrays. + // Returns false if the number of data points doesn't match the expected temperature points. + static bool loadGlycolConcValues(EnergyPlusData &state, + ErrorObjectHeader const &eoh, + std::string_view propName, + int numNumbers, + Array1D const &numbers, + int numTempPoints, + Array1D const &concs, + Array2D &values, + bool &errorsFound) + { + if ((numNumbers - 1) != numTempPoints) { + ShowSevereCustom(state, + eoh, + EnergyPlus::format( + "Number of {} points ({}) not equal to number of temperature points ({})", propName, numNumbers - 1, numTempPoints)); + errorsFound = true; + return false; + } + auto concFound = std::find(concs.begin(), concs.end(), numbers(1)); + assert(concFound != concs.end()); + int concNum = static_cast(concFound - concs.begin()) + 1; + values(concNum, {1, numTempPoints}) = numbers({2, numNumbers}); + return true; + } + + // Helper to allocate and initialize a glycol raw property's temperature/concentration arrays from FluidTemps data. + template + static void allocGlycolRawProperty(std::string const &tempArrayName, + FluidTempDataArray const &fluidTemps, + int &numTempPoints, + Array1D &temps, + int numConcPoints, + Array1D &concs, + Array2D &values) + { + if (tempArrayName.empty()) { + return; + } + int tempArrayNum = Util::FindItemInList(tempArrayName, fluidTemps); + auto const &tempArray = fluidTemps(tempArrayNum); + numTempPoints = tempArray.NumOfTemps; + temps.allocate(numTempPoints); + temps = tempArray.Temps; + values.allocate(numConcPoints, numTempPoints); + std::sort(concs.begin(), concs.end()); + } + + // Helper to register a glycol raw property concentration point and validate + // temperature array name consistency. Returns false if temp array names conflict. + static bool registerGlycolRawConcPoint(EnergyPlusData &state, + ErrorObjectHeader const &eoh, + std::string_view propName, + std::string const &enteredTempArrayName, + Real64 concValue, + std::string &tempArrayName, + Array1D &concs, + int &numConcPoints, + bool &dataPresent, + bool &errorsFound) + { + if (!tempArrayName.empty() && tempArrayName != enteredTempArrayName) { + ShowSevereCustom(state, + eoh, + EnergyPlus::format("All {} data for the same glycol must use the same temperature list" + "Expected name={}, Entered name={}", + propName, + tempArrayName, + enteredTempArrayName)); + errorsFound = true; + return false; + } + tempArrayName = enteredTempArrayName; + + if (std::find(concs.begin(), concs.end(), concValue) == concs.end()) { + concs.push_back(concValue); + ++numConcPoints; + } + dataPresent = true; + return true; + } + void GetFluidPropertiesData(EnergyPlusData &state) { @@ -1013,71 +1122,25 @@ namespace Fluid { for (auto const *refrig : df->refrigs) { ErrorObjectHeader eoh{routineName, CurrentModuleObject, refrig->Name}; - if (refrig->PsValues.empty()) { - ShowSevereCustom( - state, - eoh, - EnergyPlus::format(R"(No Gas/Fluid Saturation Pressure found. Need properties with {}="Pressure" and {}="FluidGas".)", - cAlphaFields(2), - cAlphaFields(3))); - ErrorsFound = true; - } - - if (refrig->HfValues.empty()) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format(R"(No Saturated Fluid Enthalpy found. Need properties with {}="Enthalpy" and {}="Fluid".)", - cAlphaFields(2), - cAlphaFields(3))); - ErrorsFound = true; - } - - if (refrig->HfgValues.empty()) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format(R"(No Saturated Gas/Fluid Enthalpy found. Need properties with {}="Enthalpy" and {}="FluidGas".)", - cAlphaFields(2), - cAlphaFields(3))); - ErrorsFound = true; - } - - if (refrig->CpfValues.empty()) { - ShowSevereCustom( - state, - eoh, - EnergyPlus::format(R"(No Saturated Fluid Specific Heat found. Need properties with {}="SpecificHeat" and {}="Fluid".)", - cAlphaFields(2), - cAlphaFields(3))); - ErrorsFound = true; - } - - if (refrig->CpfgValues.empty()) { - ShowSevereCustom( - state, - eoh, - EnergyPlus::format(R"(No Saturated Gas/Fluid Specific Heat found. Need properties with {}="SpecificHeat" and {}="FluidGas".)", - cAlphaFields(2), - cAlphaFields(3))); - ErrorsFound = true; - } - - if (refrig->RhofValues.empty()) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format(R"(No Saturated Fluid Density found. Need properties with {}="Density" and {}="Fluid".)", - cAlphaFields(2), - cAlphaFields(3))); - ErrorsFound = true; - } - if (refrig->RhofgValues.empty()) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format(R"(No Saturated Gas/Fluid Density found. Need properties with {}="Density" and {}="FluidGas".)", - cAlphaFields(2), - cAlphaFields(3))); - ErrorsFound = true; - } + // Check that each required saturated property has data + auto checkSatProp = [&](auto const &values, std::string_view desc, std::string_view propKey, std::string_view phaseKey) { + if (values.empty()) { + ShowSevereCustom( + state, + eoh, + EnergyPlus::format( + R"(No {} found. Need properties with {}="{}" and {}="{}".)", desc, cAlphaFields(2), propKey, cAlphaFields(3), phaseKey)); + ErrorsFound = true; + } + }; + checkSatProp(refrig->PsValues, "Gas/Fluid Saturation Pressure", "Pressure", "FluidGas"); + checkSatProp(refrig->HfValues, "Saturated Fluid Enthalpy", "Enthalpy", "Fluid"); + checkSatProp(refrig->HfgValues, "Saturated Gas/Fluid Enthalpy", "Enthalpy", "FluidGas"); + checkSatProp(refrig->CpfValues, "Saturated Fluid Specific Heat", "SpecificHeat", "Fluid"); + checkSatProp(refrig->CpfgValues, "Saturated Gas/Fluid Specific Heat", "SpecificHeat", "FluidGas"); + checkSatProp(refrig->RhofValues, "Saturated Fluid Density", "Density", "Fluid"); + checkSatProp(refrig->RhofgValues, "Saturated Gas/Fluid Density", "Density", "FluidGas"); } // for (refrigNum) // Check: TEMPERATURES for saturated density (must all be the same) @@ -1255,69 +1318,34 @@ namespace Fluid { ethylene->Num = df->glycolsRaw.isize(); } - // Specific Heat - ethylene->CpDataPresent = true; // Flag set when specific heat data is available - ethylene->NumCpTempPoints = DefaultNumGlyTemps; // Number of temperature points for specific heat - ethylene->NumCpConcPoints = DefaultNumGlyConcs; // Number of concentration points for specific heat - - ethylene->CpTemps.allocate(ethylene->NumCpTempPoints); // Temperatures for specific heat of glycol - ethylene->CpTemps = DefaultGlycolTemps; - - ethylene->CpConcs.allocate(ethylene->NumCpConcPoints); // Concentration for specific heat of glycol - ethylene->CpConcs = DefaultGlycolConcs; - - ethylene->CpValues.allocate(ethylene->NumCpConcPoints, ethylene->NumCpTempPoints); // Specific heat data values - for (int i = 1; i <= ethylene->NumCpConcPoints; ++i) { - ethylene->CpValues(i, {1, ethylene->NumCpTempPoints}) = DefaultEthGlyCpData[i - 1]; - } - - // Density - ethylene->RhoDataPresent = true; - ethylene->NumRhoTempPoints = DefaultNumGlyTemps; - ethylene->NumRhoConcPoints = DefaultNumGlyConcs; - - ethylene->RhoTemps.allocate(ethylene->NumRhoTempPoints); // Temperatures for density of glycol - ethylene->RhoTemps = DefaultGlycolTemps; - - ethylene->RhoConcs.allocate(ethylene->NumRhoConcPoints); // Concentration for density of glycol - ethylene->RhoConcs = DefaultGlycolConcs; - - ethylene->RhoValues.allocate(ethylene->NumRhoConcPoints, ethylene->NumRhoTempPoints); // Density data values - for (int i = 1; i <= ethylene->NumRhoConcPoints; ++i) { - ethylene->RhoValues(i, {1, ethylene->NumRhoTempPoints}) = DefaultEthGlyRhoData[i - 1]; - } - - // Conductivity - ethylene->CondDataPresent = true; - ethylene->NumCondTempPoints = DefaultNumGlyTemps; - ethylene->NumCondConcPoints = DefaultNumGlyConcs; - - ethylene->CondTemps.allocate(ethylene->NumCondTempPoints); // Temperatures for density of glycol - ethylene->CondTemps = DefaultGlycolTemps; - - ethylene->CondConcs.allocate(ethylene->NumCondConcPoints); // Concentration for density of glycol - ethylene->CondConcs = DefaultGlycolConcs; - - ethylene->CondValues.allocate(ethylene->NumCondConcPoints, ethylene->NumCondTempPoints); // Density data values - for (int i = 1; i <= ethylene->NumCondConcPoints; ++i) { - ethylene->CondValues(i, {1, ethylene->NumCondTempPoints}) = DefaultEthGlyCondData[i - 1]; - } - - // Viscosity - ethylene->ViscDataPresent = true; - ethylene->NumViscTempPoints = DefaultNumGlyTemps; - ethylene->NumViscConcPoints = DefaultNumGlyConcs; - - ethylene->ViscTemps.allocate(ethylene->NumViscTempPoints); // Temperatures for density of glycol - ethylene->ViscTemps = DefaultGlycolTemps; - - ethylene->ViscConcs.allocate(ethylene->NumViscConcPoints); // Concentration for density of glycol - ethylene->ViscConcs = DefaultGlycolConcs; - - ethylene->ViscValues.allocate(ethylene->NumViscConcPoints, ethylene->NumViscTempPoints); // Density data values - for (int i = 1; i <= ethylene->NumViscConcPoints; ++i) { - ethylene->ViscValues(i, {1, ethylene->NumViscTempPoints}) = DefaultEthGlyViscData[i - 1]; - } + initDefaultGlycolProperty(ethylene->CpDataPresent, + ethylene->NumCpTempPoints, + ethylene->NumCpConcPoints, + ethylene->CpTemps, + ethylene->CpConcs, + ethylene->CpValues, + DefaultEthGlyCpData); + initDefaultGlycolProperty(ethylene->RhoDataPresent, + ethylene->NumRhoTempPoints, + ethylene->NumRhoConcPoints, + ethylene->RhoTemps, + ethylene->RhoConcs, + ethylene->RhoValues, + DefaultEthGlyRhoData); + initDefaultGlycolProperty(ethylene->CondDataPresent, + ethylene->NumCondTempPoints, + ethylene->NumCondConcPoints, + ethylene->CondTemps, + ethylene->CondConcs, + ethylene->CondValues, + DefaultEthGlyCondData); + initDefaultGlycolProperty(ethylene->ViscDataPresent, + ethylene->NumViscTempPoints, + ethylene->NumViscConcPoints, + ethylene->ViscTemps, + ethylene->ViscConcs, + ethylene->ViscValues, + DefaultEthGlyViscData); // Propylene auto *propylene = GetGlycolRaw(state, "PROPYLENEGLYCOL"); @@ -1328,70 +1356,34 @@ namespace Fluid { propylene->Num = df->glycolsRaw.isize(); } - // Specific Heat - propylene->CpDataPresent = true; // Flag set when specific heat data is available - propylene->NumCpTempPoints = DefaultNumGlyTemps; // Number of temperature points for specific heat - propylene->NumCpConcPoints = DefaultNumGlyConcs; // Number of concentration points for specific heat - - // No ObjexxFCL templates for assigning std::array to Array1S, Probably want to covert these Array1D and 2D to std::vector eventually anyway - propylene->CpTemps.allocate(propylene->NumCpTempPoints); // Temperatures for specific heat of glycol - propylene->CpTemps = DefaultGlycolTemps; - - propylene->CpConcs.allocate(propylene->NumCpConcPoints); // Concentration for specific heat of glycol - propylene->CpConcs = DefaultGlycolConcs; - - propylene->CpValues.allocate(propylene->NumCpConcPoints, propylene->NumCpTempPoints); // Specific heat data values - for (int i = 1; i <= propylene->NumCpConcPoints; ++i) { - propylene->CpValues(i, {1, propylene->NumCpTempPoints}) = DefaultPropGlyCpData[i - 1]; - } - - // Density - propylene->RhoDataPresent = true; - propylene->NumRhoTempPoints = DefaultNumGlyTemps; - propylene->NumRhoConcPoints = DefaultNumGlyConcs; - - propylene->RhoTemps.allocate(propylene->NumRhoTempPoints); // Temperatures for density of glycol - propylene->RhoTemps = DefaultGlycolTemps; - - propylene->RhoConcs.allocate(propylene->NumRhoConcPoints); // Concentration for density of glycol - propylene->RhoConcs = DefaultGlycolConcs; - - propylene->RhoValues.allocate(propylene->NumRhoConcPoints, propylene->NumRhoTempPoints); // Density data values - for (int i = 1; i <= propylene->NumRhoConcPoints; ++i) { - propylene->RhoValues(i, {1, propylene->NumRhoTempPoints}) = DefaultPropGlyRhoData[i - 1]; - } - - // Conductivity - propylene->CondDataPresent = true; - propylene->NumCondTempPoints = DefaultNumGlyTemps; - propylene->NumCondConcPoints = DefaultNumGlyConcs; - - propylene->CondTemps.allocate(propylene->NumCondTempPoints); // Temperatures for density of glycol - propylene->CondTemps = DefaultGlycolTemps; - - propylene->CondConcs.allocate(propylene->NumCondConcPoints); // Concentration for density of glycol - propylene->CondConcs = DefaultGlycolConcs; - - propylene->CondValues.allocate(propylene->NumCondConcPoints, propylene->NumCondTempPoints); // Density data values - for (int i = 1; i <= propylene->NumCondConcPoints; ++i) { - propylene->CondValues(i, {1, propylene->NumCondTempPoints}) = DefaultPropGlyCondData[i - 1]; - } - - // Viscosity - propylene->ViscDataPresent = true; - propylene->NumViscTempPoints = DefaultNumGlyTemps; - propylene->NumViscConcPoints = DefaultNumGlyConcs; - - propylene->ViscTemps.allocate(propylene->NumViscTempPoints); // Temperatures for density of glycol - propylene->ViscTemps = DefaultGlycolTemps; - - propylene->ViscConcs.allocate(propylene->NumViscConcPoints); // Concentration for density of glycol - propylene->ViscConcs = DefaultGlycolConcs; - - propylene->ViscValues.allocate(propylene->NumViscConcPoints, propylene->NumViscTempPoints); // Density data values - for (int i = 1; i <= propylene->NumViscConcPoints; ++i) { - propylene->ViscValues(i, {1, propylene->NumViscTempPoints}) = DefaultPropGlyViscData[i - 1]; - } + initDefaultGlycolProperty(propylene->CpDataPresent, + propylene->NumCpTempPoints, + propylene->NumCpConcPoints, + propylene->CpTemps, + propylene->CpConcs, + propylene->CpValues, + DefaultPropGlyCpData); + initDefaultGlycolProperty(propylene->RhoDataPresent, + propylene->NumRhoTempPoints, + propylene->NumRhoConcPoints, + propylene->RhoTemps, + propylene->RhoConcs, + propylene->RhoValues, + DefaultPropGlyRhoData); + initDefaultGlycolProperty(propylene->CondDataPresent, + propylene->NumCondTempPoints, + propylene->NumCondConcPoints, + propylene->CondTemps, + propylene->CondConcs, + propylene->CondValues, + DefaultPropGlyCondData); + initDefaultGlycolProperty(propylene->ViscDataPresent, + propylene->NumViscTempPoints, + propylene->NumViscConcPoints, + propylene->ViscTemps, + propylene->ViscConcs, + propylene->ViscValues, + DefaultPropGlyViscData); // *************** RAW GLYCOLS *************** // Go through each glycol found in the fluid names statement and read in the data @@ -1438,83 +1430,59 @@ namespace Fluid { continue; } - // Can temperatue and pressure points be different for different properties? Why is this allowed? + // Can temperature and pressure points be different for different properties? Why is this allowed? if (Alphas(2) == "SPECIFICHEAT") { - if (!glycolRaw->CpTempArrayName.empty() && glycolRaw->CpTempArrayName != Alphas(3)) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format("All specific heat data for the same glycol must use the same temperature list" - "Expected name={}, Entered name={}", - glycolRaw->CpTempArrayName, - Alphas(3))); - ErrorsFound = true; + if (!registerGlycolRawConcPoint(state, + eoh, + "specific heat", + Alphas(3), + Numbers(1), + glycolRaw->CpTempArrayName, + glycolRaw->CpConcs, + glycolRaw->NumCpConcPoints, + glycolRaw->CpDataPresent, + ErrorsFound)) { continue; } - glycolRaw->CpTempArrayName = Alphas(3); - - if (std::find(glycolRaw->CpConcs.begin(), glycolRaw->CpConcs.end(), Numbers(1)) == glycolRaw->CpConcs.end()) { - glycolRaw->CpConcs.push_back(Numbers(1)); - ++glycolRaw->NumCpConcPoints; - } - glycolRaw->CpDataPresent = true; - } else if (Alphas(2) == "DENSITY") { - if (!glycolRaw->RhoTempArrayName.empty() && glycolRaw->RhoTempArrayName != Alphas(3)) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format("All density data for the same glycol must use the same temperature list" - "Expected name={}, Entered name={}", - glycolRaw->RhoTempArrayName, - Alphas(3))); - ErrorsFound = true; + if (!registerGlycolRawConcPoint(state, + eoh, + "density", + Alphas(3), + Numbers(1), + glycolRaw->RhoTempArrayName, + glycolRaw->RhoConcs, + glycolRaw->NumRhoConcPoints, + glycolRaw->RhoDataPresent, + ErrorsFound)) { continue; } - glycolRaw->RhoTempArrayName = Alphas(3); - - if (std::find(glycolRaw->RhoConcs.begin(), glycolRaw->RhoConcs.end(), Numbers(1)) == glycolRaw->RhoConcs.end()) { - glycolRaw->RhoConcs.push_back(Numbers(1)); - ++glycolRaw->NumRhoConcPoints; - } - glycolRaw->RhoDataPresent = true; - } else if (Alphas(2) == "CONDUCTIVITY") { - if (!glycolRaw->CondTempArrayName.empty() && glycolRaw->CondTempArrayName != Alphas(3)) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format("All conductivity data for the same glycol must use the same temperature list" - "Expected name={}, Entered name={}", - glycolRaw->CondTempArrayName, - Alphas(3))); - ErrorsFound = true; + if (!registerGlycolRawConcPoint(state, + eoh, + "conductivity", + Alphas(3), + Numbers(1), + glycolRaw->CondTempArrayName, + glycolRaw->CondConcs, + glycolRaw->NumCondConcPoints, + glycolRaw->CondDataPresent, + ErrorsFound)) { continue; } - glycolRaw->CondTempArrayName = Alphas(3); - - if (std::find(glycolRaw->CondConcs.begin(), glycolRaw->CondConcs.end(), Numbers(1)) == glycolRaw->CondConcs.end()) { - glycolRaw->CondConcs.push_back(Numbers(1)); - ++glycolRaw->NumCondConcPoints; - } - glycolRaw->CondDataPresent = true; - } else if (Alphas(2) == "VISCOSITY") { - if (!glycolRaw->ViscTempArrayName.empty() && glycolRaw->ViscTempArrayName != Alphas(3)) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format("All conductivity data for the same glycol must use the same temperature list" - "Expected name={}, Entered name={}", - glycolRaw->ViscTempArrayName, - Alphas(3))); - ErrorsFound = true; + if (!registerGlycolRawConcPoint(state, + eoh, + "viscosity", + Alphas(3), + Numbers(1), + glycolRaw->ViscTempArrayName, + glycolRaw->ViscConcs, + glycolRaw->NumViscConcPoints, + glycolRaw->ViscDataPresent, + ErrorsFound)) { continue; } - glycolRaw->ViscTempArrayName = Alphas(3); - - if (std::find(glycolRaw->ViscConcs.begin(), glycolRaw->ViscConcs.end(), Numbers(1)) == glycolRaw->ViscConcs.end()) { - glycolRaw->ViscConcs.push_back(Numbers(1)); - ++glycolRaw->NumViscConcPoints; - } - glycolRaw->ViscDataPresent = true; - } else { ShowSevereInvalidKey( state, eoh, cAlphaFields(2), Alphas(2), "Valid options are (\"Specific Heat\", \"Density\", \"Conductivity\", \"Viscosity\")"); @@ -1525,49 +1493,34 @@ namespace Fluid { // Allocate and sort temp point/conc point arrays for (auto *glycolRaw : df->glycolsRaw) { - if (!glycolRaw->CpTempArrayName.empty()) { - int cpTempArrayNum = Util::FindItemInList(glycolRaw->CpTempArrayName, FluidTemps); - auto const &cpTempArray = FluidTemps(cpTempArrayNum); - glycolRaw->NumCpTempPoints = cpTempArray.NumOfTemps; - glycolRaw->CpTemps.allocate(glycolRaw->NumCpTempPoints); - glycolRaw->CpTemps = cpTempArray.Temps; - - glycolRaw->CpValues.allocate(glycolRaw->NumCpConcPoints, glycolRaw->NumCpTempPoints); - std::sort(glycolRaw->CpConcs.begin(), glycolRaw->CpConcs.end()); - } - - if (!glycolRaw->RhoTempArrayName.empty()) { - int rhoTempArrayNum = Util::FindItemInList(glycolRaw->RhoTempArrayName, FluidTemps); - auto const &rhoTempArray = FluidTemps(rhoTempArrayNum); - glycolRaw->NumRhoTempPoints = rhoTempArray.NumOfTemps; - glycolRaw->RhoTemps.allocate(glycolRaw->NumRhoTempPoints); - glycolRaw->RhoTemps = rhoTempArray.Temps; - - glycolRaw->RhoValues.allocate(glycolRaw->NumRhoConcPoints, glycolRaw->NumRhoTempPoints); - std::sort(glycolRaw->RhoConcs.begin(), glycolRaw->RhoConcs.end()); - } - - if (!glycolRaw->CondTempArrayName.empty()) { - int condTempArrayNum = Util::FindItemInList(glycolRaw->CondTempArrayName, FluidTemps); - auto const &condTempArray = FluidTemps(condTempArrayNum); - glycolRaw->NumCondTempPoints = condTempArray.NumOfTemps; - glycolRaw->CondTemps.allocate(glycolRaw->NumCondTempPoints); - glycolRaw->CondTemps = condTempArray.Temps; - - glycolRaw->CondValues.allocate(glycolRaw->NumCondConcPoints, glycolRaw->NumCondTempPoints); - std::sort(glycolRaw->CondConcs.begin(), glycolRaw->CondConcs.end()); - } - - if (!glycolRaw->ViscTempArrayName.empty()) { - int viscTempArrayNum = Util::FindItemInList(glycolRaw->ViscTempArrayName, FluidTemps); - auto const &viscTempArray = FluidTemps(viscTempArrayNum); - glycolRaw->NumViscTempPoints = viscTempArray.NumOfTemps; - glycolRaw->ViscTemps.allocate(glycolRaw->NumViscTempPoints); - glycolRaw->ViscTemps = viscTempArray.Temps; - - glycolRaw->ViscValues.allocate(glycolRaw->NumViscConcPoints, glycolRaw->NumViscTempPoints); - std::sort(glycolRaw->ViscConcs.begin(), glycolRaw->ViscConcs.end()); - } + allocGlycolRawProperty(glycolRaw->CpTempArrayName, + FluidTemps, + glycolRaw->NumCpTempPoints, + glycolRaw->CpTemps, + glycolRaw->NumCpConcPoints, + glycolRaw->CpConcs, + glycolRaw->CpValues); + allocGlycolRawProperty(glycolRaw->RhoTempArrayName, + FluidTemps, + glycolRaw->NumRhoTempPoints, + glycolRaw->RhoTemps, + glycolRaw->NumRhoConcPoints, + glycolRaw->RhoConcs, + glycolRaw->RhoValues); + allocGlycolRawProperty(glycolRaw->CondTempArrayName, + FluidTemps, + glycolRaw->NumCondTempPoints, + glycolRaw->CondTemps, + glycolRaw->NumCondConcPoints, + glycolRaw->CondConcs, + glycolRaw->CondValues); + allocGlycolRawProperty(glycolRaw->ViscTempArrayName, + FluidTemps, + glycolRaw->NumViscTempPoints, + glycolRaw->ViscTemps, + glycolRaw->NumViscConcPoints, + glycolRaw->ViscConcs, + glycolRaw->ViscValues); } // Finally, get the specific heat and concentration values from the user input @@ -1595,64 +1548,53 @@ namespace Fluid { assert(glycolRaw != nullptr); // We've already tested for this, can just assert now if (Alphas(2) == "SPECIFICHEAT") { - if ((NumNumbers - 1) != glycolRaw->NumCpTempPoints) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format("Number of specific heat points ({}) not equal to number of temperature points ({})", - NumNumbers - 1, - glycolRaw->NumCpTempPoints)); - ErrorsFound = true; + if (!loadGlycolConcValues(state, + eoh, + "specific heat", + NumNumbers, + Numbers, + glycolRaw->NumCpTempPoints, + glycolRaw->CpConcs, + glycolRaw->CpValues, + ErrorsFound)) { continue; } - auto concFound = std::find(glycolRaw->CpConcs.begin(), glycolRaw->CpConcs.end(), Numbers(1)); - assert(concFound != glycolRaw->CpConcs.end()); - int concNum = (concFound - glycolRaw->CpConcs.begin()) + 1; - glycolRaw->CpValues(concNum, {1, glycolRaw->NumCpTempPoints}) = Numbers({2, NumNumbers}); - } else if (Alphas(2) == "DENSITY") { - if ((NumNumbers - 1) != glycolRaw->NumRhoTempPoints) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format("Number of density points ({}) not equal to number of temperature points ({})", - NumNumbers - 1, - glycolRaw->NumRhoTempPoints)); - ErrorsFound = true; + if (!loadGlycolConcValues(state, + eoh, + "density", + NumNumbers, + Numbers, + glycolRaw->NumRhoTempPoints, + glycolRaw->RhoConcs, + glycolRaw->RhoValues, + ErrorsFound)) { continue; } - auto concFound = std::find(glycolRaw->RhoConcs.begin(), glycolRaw->RhoConcs.end(), Numbers(1)); - assert(concFound != glycolRaw->RhoConcs.end()); - int concNum = (concFound - glycolRaw->RhoConcs.begin()) + 1; - glycolRaw->RhoValues(concNum, {1, glycolRaw->NumRhoTempPoints}) = Numbers({2, NumNumbers}); - } else if (Alphas(2) == "CONDUCTIVITY") { - if ((NumNumbers - 1) != glycolRaw->NumCondTempPoints) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format("Number of conductivity points ({}) not equal to number of temperature points ({})", - NumNumbers - 1, - glycolRaw->NumCondTempPoints)); - ErrorsFound = true; + if (!loadGlycolConcValues(state, + eoh, + "conductivity", + NumNumbers, + Numbers, + glycolRaw->NumCondTempPoints, + glycolRaw->CondConcs, + glycolRaw->CondValues, + ErrorsFound)) { continue; } - auto concFound = std::find(glycolRaw->CondConcs.begin(), glycolRaw->CondConcs.end(), Numbers(1)); - assert(concFound != glycolRaw->CondConcs.end()); - int concNum = (concFound - glycolRaw->CondConcs.begin()) + 1; - glycolRaw->CondValues(concNum, {1, glycolRaw->NumCondTempPoints}) = Numbers({2, NumNumbers}); - } else if (Alphas(2) == "VISCOSITY") { - if ((NumNumbers - 1) != glycolRaw->NumViscTempPoints) { - ShowSevereCustom(state, - eoh, - EnergyPlus::format("Number of viscosity points ({}) not equal to number of temperature points ({})", - NumNumbers - 1, - glycolRaw->NumViscTempPoints)); - ErrorsFound = true; + if (!loadGlycolConcValues(state, + eoh, + "viscosity", + NumNumbers, + Numbers, + glycolRaw->NumViscTempPoints, + glycolRaw->ViscConcs, + glycolRaw->ViscValues, + ErrorsFound)) { continue; } - auto concFound = std::find(glycolRaw->ViscConcs.begin(), glycolRaw->ViscConcs.end(), Numbers(1)); - assert(concFound != glycolRaw->ViscConcs.end()); - int concNum = (concFound - glycolRaw->ViscConcs.begin()) + 1; - glycolRaw->ViscValues(concNum, {1, glycolRaw->NumViscTempPoints}) = Numbers({2, NumNumbers}); } } // for (InData) diff --git a/src/EnergyPlus/Furnaces.cc b/src/EnergyPlus/Furnaces.cc index 018c03775bb..77ff52f7d1d 100644 --- a/src/EnergyPlus/Furnaces.cc +++ b/src/EnergyPlus/Furnaces.cc @@ -718,6 +718,484 @@ namespace Furnaces { // Get Input Section of the Module //****************************************************************************** + // Helper: read hot water heating coil data into thisFurnace fields. + // Populates CoilControlNode, MaxHeatCoilFluidFlow, HWCoilAirInletNode, HWCoilAirOutletNode. + // Also checks for a conflicting Controller:WaterCoil object. + // Returns inlet and outlet node numbers via HeatingCoilInletNode / HeatingCoilOutletNode. + static void readHeatWaterCoilData(EnergyPlusData &state, + FurnaceEquipConditions &thisFurnace, + std::string_view CurrentModuleObject, + const std::string &HeatingCoilName, + int &HeatingCoilInletNode, + int &HeatingCoilOutletNode, + bool &ErrorsFound) + { + bool errFlag = false; + thisFurnace.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + thisFurnace.MaxHeatCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", HeatingCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + HeatingCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag); + thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode; + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + HeatingCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag); + thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode; + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag); + if (!errFlag) { + ShowSevereError(state, + EnergyPlus::format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name)); + ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems."); + ShowContinueError(state, "No water coil controller should be input for the coil."); + ErrorsFound = true; + } + } + + // Helper: read steam heating coil data into thisFurnace fields. + // Populates HeatingCoilIndex, CoilControlNode, MaxHeatCoilFluidFlow, HWCoilAirInletNode, HWCoilAirOutletNode. + // Returns inlet and outlet node numbers via HeatingCoilInletNode / HeatingCoilOutletNode. + static void readHeatSteamCoilData(EnergyPlusData &state, + FurnaceEquipConditions &thisFurnace, + std::string_view CurrentModuleObject, + std::string_view coilAlphaField, + const std::string &HeatingCoilName, + std::string_view routineNameForSteam, + int &HeatingCoilInletNode, + int &HeatingCoilOutletNode, + bool &ErrorsFound) + { + bool errFlag = false; + thisFurnace.HeatingCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag); + if (thisFurnace.HeatingCoilIndex == 0) { + ShowSevereError(state, EnergyPlus::format("{} illegal {} = {}", CurrentModuleObject, coilAlphaField, HeatingCoilName)); + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + thisFurnace.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, errFlag); + if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) { + Real64 SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, routineNameForSteam); + thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity; + } + + errFlag = false; + HeatingCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag); + thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode; + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + HeatingCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag); + thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode; + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + } + + // Helper: read supplemental/reheat hot-water coil data into thisFurnace fields. + // Populates SuppCoilControlNode, MaxSuppCoilFluidFlow, SuppCoilAirInletNode, SuppCoilAirOutletNode. + // Also checks for a conflicting Controller:WaterCoil object. + // Returns inlet and outlet node numbers via coilInletNode / coilOutletNode. + static void readSuppWaterCoilData(EnergyPlusData &state, + FurnaceEquipConditions &thisFurnace, + std::string_view CurrentModuleObject, + const std::string &SuppCoilName, + int &coilInletNode, + int &coilOutletNode, + bool &ErrorsFound) + { + bool errFlag = false; + thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", SuppCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + thisFurnace.MaxSuppCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", SuppCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + coilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", SuppCoilName, errFlag); + thisFurnace.SuppCoilAirInletNode = coilInletNode; + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + coilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", SuppCoilName, errFlag); + thisFurnace.SuppCoilAirOutletNode = coilOutletNode; + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag); + if (!errFlag) { + ShowSevereError(state, + EnergyPlus::format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name)); + ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems."); + ShowContinueError(state, "No water coil controller should be input for the coil."); + ErrorsFound = true; + } + } + + // Helper: read supplemental/reheat steam coil data into thisFurnace fields. + // Populates SuppHeatCoilIndex, SuppCoilControlNode, MaxSuppCoilFluidFlow, SuppCoilAirInletNode, SuppCoilAirOutletNode. + // Returns inlet and outlet node numbers via coilInletNode / coilOutletNode. + static void readSuppSteamCoilData(EnergyPlusData &state, + FurnaceEquipConditions &thisFurnace, + std::string_view CurrentModuleObject, + std::string_view coilAlphaField, + const std::string &SuppCoilName, + std::string_view routineNameForSteam, + int &coilInletNode, + int &coilOutletNode, + bool &ErrorsFound) + { + bool errFlag = false; + thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", SuppCoilName, errFlag); + if (thisFurnace.SuppHeatCoilIndex == 0) { + ShowSevereError(state, EnergyPlus::format("{} illegal {} = {}", CurrentModuleObject, coilAlphaField, SuppCoilName)); + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "COIL:HEATING:STEAM", SuppCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag); + if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) { + Real64 SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, routineNameForSteam); + thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity; + } + + errFlag = false; + coilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, SuppCoilName, errFlag); + thisFurnace.SuppCoilAirInletNode = coilInletNode; + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + + errFlag = false; + coilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, SuppCoilName, errFlag); + thisFurnace.SuppCoilAirOutletNode = coilOutletNode; + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + } + + // Helper: verify the control zone has a humidistat when Humidistat is enabled. + // Sets AirNodeFound to true if a matching ZoneControl:Humidistat is found. + // Reports a severe error if none is found. + static void checkHumidistatZone(EnergyPlusData &state, + FurnaceEquipConditions &thisFurnace, + std::string_view CurrentModuleObject, + std::string_view zoneAlphaField, + std::string_view zoneAlphaValue, + bool &AirNodeFound, + bool &ErrorsFound) + { + if (!thisFurnace.Humidistat) { + return; + } + AirNodeFound = false; + for (int HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) { + if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum == thisFurnace.ControlZoneNum) { + AirNodeFound = true; + } + } + if (!AirNodeFound) { + ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisFurnace.Name)); + ShowContinueError(state, "Did not find Air Node (Zone with Humidistat)."); + ShowContinueError(state, EnergyPlus::format("Specified {} = {}", zoneAlphaField, zoneAlphaValue)); + ErrorsFound = true; + } + } + + // Helper: find controlled zone and verify it is served by the furnace air loop. + // Populates NodeNumOfControlledZone, ZoneInletNode, and airloopNum on thisFurnace. + // Reports errors when the zone or air loop cannot be found. + // Helper: look up the control zone by name, validate it, then find the air loop and inlet node. + // Sets ControlZoneNum, NodeNumOfControlledZone, ZoneInletNode, and airloopNum on thisFurnace. + static void findControlledZoneAirLoop(EnergyPlusData &state, + FurnaceEquipConditions &thisFurnace, + std::string_view CurrentModuleObject, + std::string_view zoneAlphaField, + std::string_view zoneAlphaValue, + bool &ErrorsFound) + { + thisFurnace.ControlZoneNum = Util::FindItemInList(std::string{zoneAlphaValue}, state.dataHeatBal->Zone); + if (thisFurnace.ControlZoneNum == 0) { + ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisFurnace.Name)); + ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", zoneAlphaField, zoneAlphaValue)); + ErrorsFound = true; + } + if (thisFurnace.ControlZoneNum <= 0) { + return; + } + + bool AirNodeFound = false; + bool AirLoopFound = false; + int ControlledZoneNum = thisFurnace.ControlZoneNum; + + thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode; + + for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) { + int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode); + thisFurnace.airloopNum = AirLoopNumber; + if (AirLoopNumber > 0) { + for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) { + for (int CompNum = 1; CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents; + ++CompNum) { + if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name, + thisFurnace.Name) || + !Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf, + CurrentModuleObject)) { + continue; + } + AirLoopFound = true; + thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode); + break; + } + if (AirLoopFound) { + break; + } + } + for (int TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) { + if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum == thisFurnace.ControlZoneNum) { + AirNodeFound = true; + } + } + for (int TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) { + if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum == thisFurnace.ControlZoneNum) { + AirNodeFound = true; + } + } + } + if (AirLoopFound) { + break; + } + } + if (!AirNodeFound) { + ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisFurnace.Name)); + ShowContinueError(state, "Did not find air node (zone with thermostat)."); + ShowContinueError(state, EnergyPlus::format("Specified {} = {}", zoneAlphaField, zoneAlphaValue)); + ShowContinueError(state, + "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone."); + ErrorsFound = true; + } + if (!AirLoopFound) { + ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisFurnace.Name)); + ShowContinueError(state, "Did not find correct AirLoopHVAC."); + ShowContinueError(state, EnergyPlus::format("Specified {} = {}", zoneAlphaField, zoneAlphaValue)); + ErrorsFound = true; + } + } + + // Helper: read gas/electric primary heating coil data into thisFurnace fields. + // Populates HeatingCoilType_Num, HeatingCoilIndex, DesignHeatingCapacity, inlet/outlet nodes. + // If plfCurveIndex is non-null, also fetches the PLF curve index (used by HeatCool loop). + // If setHWCoilAirInletNode is true, also assigns HWCoilAirInletNode (used by HeatOnly loop). + static void readHeatGasElecCoilData(EnergyPlusData &state, + FurnaceEquipConditions &thisFurnace, + std::string_view CurrentModuleObject, + const std::string &HeatingCoilType, + const std::string &HeatingCoilName, + int &HeatingCoilInletNode, + int &HeatingCoilOutletNode, + bool setHWCoilAirInletNode, + int *plfCurveIndex, + bool &ErrorsFound) + { + bool errFlag = false; + bool IsNotOK = false; + thisFurnace.HeatingCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } else { + ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject); + if (IsNotOK) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } else { // mine data from heating coil + errFlag = false; + HeatingCoils::GetCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + errFlag = false; + thisFurnace.DesignHeatingCapacity = HeatingCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag); + if (errFlag) { + // Original HeatOnly path used "...occurs in {} ={}" (no space before =); HeatCool used "...occurs in {} = {}" + ShowContinueError(state, + EnergyPlus::format(setHWCoilAirInletNode ? "...occurs in {} ={}" : "...occurs in {} = {}", + CurrentModuleObject, + thisFurnace.Name)); + ErrorsFound = true; + } + errFlag = false; + HeatingCoilInletNode = HeatingCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag); + if (setHWCoilAirInletNode) { + thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode; + } + if (errFlag) { + ShowContinueError(state, + EnergyPlus::format(setHWCoilAirInletNode ? "...occurs in {} ={}" : "...occurs in {} = {}", + CurrentModuleObject, + thisFurnace.Name)); + ErrorsFound = true; + } + errFlag = false; + HeatingCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, + EnergyPlus::format(setHWCoilAirInletNode ? "...occurs in {} ={}" : "...occurs in {} = {}", + CurrentModuleObject, + thisFurnace.Name)); + ErrorsFound = true; + } + if (plfCurveIndex != nullptr) { + errFlag = false; + *plfCurveIndex = HeatingCoils::GetHeatingCoilPLFCurveIndex(state, HeatingCoilType, HeatingCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + } + } // IF (IsNotOK) THEN + } + } + + // Helper: read supplemental heating coil data (gas/electric, water, or steam) into thisFurnace fields. + // Handles all coil types for both HeatPump AirToAir and WaterToAir supplemental coil inputs. + // SuppCoilTypeAlphaIndex is the 0-based alpha index for the coil type field used in error messages. + static void readSuppHeatCoilData(EnergyPlusData &state, + FurnaceEquipConditions &thisFurnace, + std::string_view CurrentModuleObject, + const std::string &SuppHeatCoilType, + const std::string &SuppHeatCoilName, + std::string_view coilTypeAlphaField, + int &SupHeatCoilInletNode, + int &SupHeatCoilOutletNode, + bool &ErrorsFound) + { + bool errFlag = false; + bool IsNotOK = false; + if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Fuel") || Util::SameString(SuppHeatCoilType, "Coil:Heating:Electric")) { + thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } else { + IsNotOK = false; + ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject); + if (IsNotOK) { + ShowContinueError(state, EnergyPlus::format("In {} \"{}\"", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } else { // mine data from the supplemental heating coil + HeatingCoils::GetCoilIndex(state, SuppHeatCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK); + if (IsNotOK) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + errFlag = false; + SupHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + errFlag = false; + SupHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + errFlag = false; + thisFurnace.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } + } // IF (IsNotOK) THEN + } + } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Water")) { + thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater; + ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject); + if (IsNotOK) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } else { + readSuppWaterCoilData( + state, thisFurnace, CurrentModuleObject, SuppHeatCoilName, SupHeatCoilInletNode, SupHeatCoilOutletNode, ErrorsFound); + } + } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Steam")) { + thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam; + ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject); + if (IsNotOK) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ErrorsFound = true; + } else { + readSuppSteamCoilData(state, + thisFurnace, + CurrentModuleObject, + coilTypeAlphaField, + SuppHeatCoilName, + "GetAirLoopHVACHeatCoolInput", + SupHeatCoilInletNode, + SupHeatCoilOutletNode, + ErrorsFound); + } + } else { + ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisFurnace.Name)); + ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", coilTypeAlphaField, SuppHeatCoilType)); + ErrorsFound = true; + } + } + void GetFurnaceInput(EnergyPlusData &state) { @@ -761,10 +1239,7 @@ namespace Furnaces { std::string CompSetHeatOutlet; bool ErrorsFound(false); // If errors detected in input bool IsNotOK; // Flag to verify name - bool AirNodeFound; // Used to determine if control zone is valid - bool AirLoopFound; // Used to determine if control zone is served by furnace air loop - int TstatZoneNum; // Used to determine if control zone has a thermostat object - int HStatZoneNum; // Used to determine if control zone has a humidistat object + bool AirNodeFound; // Used to determine if control zone has a humidistat object bool errFlag; // Mining function error flag int FanInletNode; // Used for node checking warning messages int FanOutletNode; // Used for node checking warning messages @@ -785,7 +1260,6 @@ namespace Furnaces { std::string FanName; // Used in mining function CALLS bool PrintMessage; // Used in mining function CALLS int HeatingCoilPLFCurveIndex; // index of heating coil PLF curve - Real64 SteamDensity; // density of steam at 100C int DXCoilIndex; // Index to DX coil in HXAssited object std::string IHPCoilName; // IHP cooling coil name auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject; @@ -848,6 +1322,216 @@ namespace Furnaces { int IHPCoilIndex = 0; + // Lambda: set AirFlowControl based on the fan operating mode schedule. + // AirFlowControl is only relevant when the fan runs continuously (ContFanCycComp). + // If the schedule is always zero the compressor-on flow is used; otherwise the + // user-specified no-load flow rate is used. + auto setAirFlowControl = [&](FurnaceEquipConditions &furn) { + if (furn.fanOpModeSched != nullptr) { + if (!furn.fanOpModeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 0.0)) { + furn.AirFlowControl = (furn.MaxNoCoolHeatAirVolFlow == 0.0) ? AirFlowControlConstFan::UseCompressorOnFlow + : AirFlowControlConstFan::UseCompressorOffFlow; + } + } + }; + + // Lambda: warn and reset MaxCoolAirVolFlow and MaxHeatAirVolFlow when they exceed + // the fan's actual flow rate. coolFieldName/heatFieldName are the numeric-field + // description strings used in the error message so callers can pass the correct + // cNumericFields entry for each object type. + auto checkFanFlowVsHVACFlowRates = [&](FurnaceEquipConditions &furn, + std::string_view objName, + std::string_view coolFieldName, + std::string_view heatFieldName, + const std::string &fanName) { + if (furn.ActualFanVolFlowRate == DataSizing::AutoSize) { + return; + } + if (furn.ActualFanVolFlowRate < furn.MaxCoolAirVolFlow && furn.MaxCoolAirVolFlow != DataSizing::AutoSize) { + ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, objName)); + ShowContinueError(state, + EnergyPlus::format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow " + "rate in cooling mode.", + furn.ActualFanVolFlowRate, + fanName)); + ShowContinueError(state, EnergyPlus::format(" The {} is reset to the fan flow rate and the simulation continues.", coolFieldName)); + furn.MaxCoolAirVolFlow = furn.ActualFanVolFlowRate; + furn.DesignFanVolFlowRate = furn.ActualFanVolFlowRate; + } + if (furn.ActualFanVolFlowRate < furn.MaxHeatAirVolFlow && furn.MaxHeatAirVolFlow != DataSizing::AutoSize) { + ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, objName)); + ShowContinueError(state, + EnergyPlus::format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow " + "rate in heating mode.", + furn.ActualFanVolFlowRate, + fanName)); + ShowContinueError(state, EnergyPlus::format(" The {} is reset to the fan flow rate and the simulation continues.", heatFieldName)); + furn.MaxHeatAirVolFlow = furn.ActualFanVolFlowRate; + furn.DesignFanVolFlowRate = furn.ActualFanVolFlowRate; + } + }; + + // Lambda: for a Coil:Cooling:DX:VariableSpeed (or IHP) cooling coil, populate + // CoolingCoilIndex, IHPCoilName, CoolingCoilInletNode, CoolingCoilOutletNode, and + // CondenserNodeNum on thisFurnace. The caller is responsible for ValidateComponent + // before invoking this lambda. On entry, thisFurnace.bIsIHP must already be set. + auto readVSCoolingCoilNodes = [&](FurnaceEquipConditions &furn, + std::string_view objName, + const std::string &coolCoilType, + const std::string &coolCoilName, + int &coolInletNode, + int &coolOutletNode) { + errFlag = false; + if (furn.bIsIHP) { + furn.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, coolCoilType, coolCoilName, errFlag); + IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(furn.CoolingCoilIndex).SCCoilName; + } else { + furn.CoolingCoilIndex = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, coolCoilType, coolCoilName, errFlag); + IHPCoilName = coolCoilName; + } + + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("...specified in {}=\"{}\".", CurrentModuleObject, objName)); + ErrorsFound = true; + } + + if (furn.bIsIHP) { + coolInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag); + coolOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag); + furn.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag); + } else { + coolInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, coolCoilType, coolCoilName, errFlag); + coolOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, coolCoilType, coolCoilName, errFlag); + furn.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, coolCoilName, errFlag); + } + + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, objName)); + ErrorsFound = true; + } + }; + + // Function-pointer type shared by WaterToAirHeatPump, WaterToAirHeatPumpSimple, + // and VariableSpeedCoils for GetCoilIndex / GetCoilInletNode / GetCoilOutletNode. + using CoilNodeFn = int (*)(EnergyPlusData &, std::string const &, std::string const &, bool &); + using CoilCapFn = Real64 (*)(EnergyPlusData &, std::string const &, std::string const &, bool &); + + // Descriptor for a single WaterToAir coil variant. The three supported + // coil types (ParameterEstimation, EquationFit, VariableSpeedEquationFit) + // differ only in the HVAC constant and the namespace of the getter functions. + struct WAHPCoilDesc + { + std::string_view typeString; // upper-case IDF object name to match + int coilTypeNum; // HVAC::Coil_* constant + CoilNodeFn getIndex; + CoilNodeFn getInletNode; + CoilNodeFn getOutletNode; + CoilCapFn getCapacity; + }; + + static constexpr int numWAHPVariants = 3; + + // Heating coil dispatch table. + const std::array wahpHeatingCoils = {{ + {"COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION", + HVAC::Coil_HeatingWaterToAirHP, + WaterToAirHeatPump::GetCoilIndex, + WaterToAirHeatPump::GetCoilInletNode, + WaterToAirHeatPump::GetCoilOutletNode, + WaterToAirHeatPump::GetCoilCapacity}, + {"COIL:HEATING:WATERTOAIRHEATPUMP:EQUATIONFIT", + HVAC::Coil_HeatingWaterToAirHPSimple, + WaterToAirHeatPumpSimple::GetCoilIndex, + WaterToAirHeatPumpSimple::GetCoilInletNode, + WaterToAirHeatPumpSimple::GetCoilOutletNode, + WaterToAirHeatPumpSimple::GetCoilCapacity}, + {"COIL:HEATING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT", + HVAC::Coil_HeatingWaterToAirHPVSEquationFit, + VariableSpeedCoils::GetCoilIndexVariableSpeed, + VariableSpeedCoils::GetCoilInletNodeVariableSpeed, + VariableSpeedCoils::GetCoilOutletNodeVariableSpeed, + VariableSpeedCoils::GetCoilCapacityVariableSpeed}, + }}; + + // Cooling coil dispatch table. + const std::array wahpCoolingCoils = {{ + {"COIL:COOLING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION", + HVAC::Coil_CoolingWaterToAirHP, + WaterToAirHeatPump::GetCoilIndex, + WaterToAirHeatPump::GetCoilInletNode, + WaterToAirHeatPump::GetCoilOutletNode, + WaterToAirHeatPump::GetCoilCapacity}, + {"COIL:COOLING:WATERTOAIRHEATPUMP:EQUATIONFIT", + HVAC::Coil_CoolingWaterToAirHPSimple, + WaterToAirHeatPumpSimple::GetCoilIndex, + WaterToAirHeatPumpSimple::GetCoilInletNode, + WaterToAirHeatPumpSimple::GetCoilOutletNode, + WaterToAirHeatPumpSimple::GetCoilCapacity}, + {"COIL:COOLING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT", + HVAC::Coil_CoolingWaterToAirHPVSEquationFit, + VariableSpeedCoils::GetCoilIndexVariableSpeed, + VariableSpeedCoils::GetCoilInletNodeVariableSpeed, + VariableSpeedCoils::GetCoilOutletNodeVariableSpeed, + VariableSpeedCoils::GetCoilCapacityVariableSpeed}, + }}; + + // Lambda: look up a WaterToAir coil by type string, populate the furnace + // coil index and node numbers via the matching dispatch-table entry. + // Returns true if a matching coil type was found (even if validation fails). + auto readWaterToAirCoil = [&](const std::array &table, + std::string_view alphaType, + std::string_view alphaName, + std::string_view /* alphaFieldType */, + int &coilIndex, + int &coilTypeNum, + std::string &coilType, + std::string &coilName, + int &inletNode, + int &outletNode) -> bool { + for (auto const &desc : table) { + if (alphaType != desc.typeString) { + continue; + } + + coilType = std::string(alphaType); + coilTypeNum = desc.coilTypeNum; + coilName = std::string(alphaName); + ValidateComponent(state, coilType, coilName, IsNotOK, CurrentModuleObject); + if (IsNotOK) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); + ErrorsFound = true; + } else { + coilIndex = desc.getIndex(state, coilType, coilName, errFlag); + inletNode = desc.getInletNode(state, coilType, coilName, errFlag); + outletNode = desc.getOutletNode(state, coilType, coilName, errFlag); + } + return true; + } + return false; + }; + + // Lambda: retrieve design capacity for a WaterToAir coil whose type has + // already been identified. Dispatches through the same table used by + // readWaterToAirCoil. + auto getWaterToAirCoilCapacity = [&](const std::array &table, + int coilTypeNum, + const std::string &coilType, + const std::string &coilName) -> Real64 { + for (auto const &desc : table) { + if (coilTypeNum != desc.coilTypeNum) { + continue; + } + errFlag = false; + Real64 cap = desc.getCapacity(state, coilType, coilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); + ErrorsFound = true; + } + return cap; + } + return 0.0; + }; + // Get the data for the HeatOnly Furnace for (int HeatOnlyNum = 1; HeatOnlyNum <= NumHeatOnly + NumUnitaryHeatOnly; ++HeatOnlyNum) { @@ -935,77 +1619,8 @@ namespace Furnaces { // Get the Controlling Zone or Location of the Furnace Thermostat - thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(6), state.dataHeatBal->Zone); - if (thisFurnace.ControlZoneNum == 0) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(6), Alphas(6))); - ErrorsFound = true; - } - // Get the node number for the zone with the thermostat - if (thisFurnace.ControlZoneNum > 0) { - AirNodeFound = false; - AirLoopFound = false; - int ControlledZoneNum = thisFurnace.ControlZoneNum; - // Find the controlled zone number for the specified thermostat location - thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode; - // Determine if furnace is on air loop served by the thermostat location specified - for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) { - int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode); - thisFurnace.airloopNum = AirLoopNumber; - if (AirLoopNumber > 0) { - for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) { - for (int CompNum = 1; - CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents; - ++CompNum) { - if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name, - thisFurnace.Name) || - !Util::SameString( - state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf, - CurrentModuleObject)) { - continue; - } - AirLoopFound = true; - thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode); - break; - } - if (AirLoopFound) { - break; - } - } - for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) { - if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) { - continue; - } - AirNodeFound = true; - } - for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) { - if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) { - continue; - } - AirNodeFound = true; - } - } - if (AirLoopFound) { - break; - } - } - if (!AirNodeFound) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Did not find Air Node (Zone with Thermostat)."); - ShowContinueError(state, EnergyPlus::format("Specified {} = {}", cAlphaFields(6), Alphas(6))); - ShowContinueError( - state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone."); - ErrorsFound = true; - } - if (!AirLoopFound) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Did not find correct Primary Air Loop."); - ShowContinueError( - state, EnergyPlus::format("Specified {} = {} is not served by this AirLoopHVAC equipment.", cAlphaFields(6), Alphas(6))); - ErrorsFound = true; - } - } + findControlledZoneAirLoop(state, thisFurnace, CurrentModuleObject, cAlphaFields(6), Alphas(6), ErrorsFound); // Get fan data FanName = Alphas(8); @@ -1061,54 +1676,16 @@ namespace Furnaces { thisFurnace.HeatingCoilType = HeatingCoilType; thisFurnace.HeatingCoilName = HeatingCoilName; if (Util::SameString(HeatingCoilType, "Coil:Heating:Fuel") || Util::SameString(HeatingCoilType, "Coil:Heating:Electric")) { - errFlag = false; - thisFurnace.HeatingCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - - } else { // mine data from heating coil object - - // Get index to Heating Coil - errFlag = false; - HeatingCoils::GetCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the furnace design capacity - errFlag = false; - thisFurnace.DesignHeatingCapacity = HeatingCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} ={}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the Heating Coil Inlet Node - errFlag = false; - HeatingCoilInletNode = HeatingCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag); - thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} ={}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the Heating Coil Outlet Node - errFlag = false; - HeatingCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} ={}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - } // IF (IsNotOK) THEN - } + readHeatGasElecCoilData(state, + thisFurnace, + CurrentModuleObject, + HeatingCoilType, + HeatingCoilName, + HeatingCoilInletNode, + HeatingCoilOutletNode, + /*setHWCoilAirInletNode=*/true, + /*plfCurveIndex=*/nullptr, + ErrorsFound); } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Water")) { thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWater; @@ -1116,53 +1693,9 @@ namespace Furnaces { if (IsNotOK) { ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; - } else { // mine data from heating coil object - - // Get the Heating Coil water Inlet or control Node number - errFlag = false; - thisFurnace.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil hot water max volume flow rate - errFlag = false; - thisFurnace.MaxHeatCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil Inlet Node - errFlag = false; - HeatingCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag); - thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil Outlet Node - errFlag = false; - HeatingCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag); - thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // check if user has also used a water coil controller, which they should not do - errFlag = false; - HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag); - if (!errFlag) { // then did find a controller so that is bad - ShowSevereError( - state, - EnergyPlus::format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name)); - ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems."); - ShowContinueError(state, "No water coil controller should be input for the coil."); - ErrorsFound = true; - } + } else { + readHeatWaterCoilData( + state, thisFurnace, CurrentModuleObject, HeatingCoilName, HeatingCoilInletNode, HeatingCoilOutletNode, ErrorsFound); } } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Steam")) { @@ -1171,48 +1704,16 @@ namespace Furnaces { if (IsNotOK) { ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; - } else { // mine data from heating coil object - - errFlag = false; - thisFurnace.HeatingCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag); - if (thisFurnace.HeatingCoilIndex == 0) { - ShowSevereError(state, EnergyPlus::format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), HeatingCoilName)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil steam inlet node number - errFlag = false; - thisFurnace.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil steam max volume flow rate - thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, errFlag); - if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) { - SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getUnitaryHeatOnly); - thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity; - } - - // Get the Heating Coil Inlet Node - errFlag = false; - HeatingCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag); - thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil Outlet Node - errFlag = false; - HeatingCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag); - thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } + } else { + readHeatSteamCoilData(state, + thisFurnace, + CurrentModuleObject, + cAlphaFields(11), + HeatingCoilName, + getUnitaryHeatOnly, + HeatingCoilInletNode, + HeatingCoilOutletNode, + ErrorsFound); } } else { @@ -1491,76 +1992,8 @@ namespace Furnaces { } // Get the Controlling Zone or Location of the Furnace Thermostat - thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(6), state.dataHeatBal->Zone); - if (thisFurnace.ControlZoneNum == 0) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(6), Alphas(6))); - ErrorsFound = true; - } - // Get the node number for the zone with the thermostat - if (thisFurnace.ControlZoneNum > 0) { - AirNodeFound = false; - AirLoopFound = false; - int ControlledZoneNum = thisFurnace.ControlZoneNum; - // Find the controlled zone number for the specified thermostat location - thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode; - // Determine if system is on air loop served by the thermostat location specified - for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) { - int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode); - thisFurnace.airloopNum = AirLoopNumber; - if (AirLoopNumber > 0) { - for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) { - for (int CompNum = 1; - CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents; - ++CompNum) { - if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name, - Alphas(1)) || - !Util::SameString( - state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf, - CurrentModuleObject)) { - continue; - } - AirLoopFound = true; - thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode); - break; - } - if (AirLoopFound) { - break; - } - } - for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) { - if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) { - continue; - } - AirNodeFound = true; - } - for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) { - if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) { - continue; - } - AirNodeFound = true; - } - } - if (AirLoopFound) { - break; - } - } - if (!AirNodeFound) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Did not find air node (zone with thermostat)."); - ShowContinueError(state, EnergyPlus::format("Specified {} = {}", cAlphaFields(6), Alphas(6))); - ShowContinueError( - state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone."); - ErrorsFound = true; - } - if (!AirLoopFound) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Did not find correct AirLoopHVAC."); - ShowContinueError(state, EnergyPlus::format("Specified {} = {}", cAlphaFields(6), Alphas(6))); - ErrorsFound = true; - } - } + findControlledZoneAirLoop(state, thisFurnace, CurrentModuleObject, cAlphaFields(6), Alphas(6), ErrorsFound); // Get fan data FanName = Alphas(8); @@ -1617,62 +2050,16 @@ namespace Furnaces { thisFurnace.HeatingCoilType = HeatingCoilType; thisFurnace.HeatingCoilName = HeatingCoilName; if (Util::SameString(HeatingCoilType, "Coil:Heating:Fuel") || Util::SameString(HeatingCoilType, "Coil:Heating:Electric")) { - errFlag = false; - thisFurnace.HeatingCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - - ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - - } else { // mine data from heating coil - - // Get heating coil index - errFlag = false; - HeatingCoils::GetCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the design heating capacity - errFlag = false; - thisFurnace.DesignHeatingCapacity = HeatingCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the Heating Coil Inlet Node - errFlag = false; - HeatingCoilInletNode = HeatingCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the Heating Coil Outlet Node - errFlag = false; - HeatingCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the Heating Coil PLF Curve Index - errFlag = false; - HeatingCoilPLFCurveIndex = HeatingCoils::GetHeatingCoilPLFCurveIndex(state, HeatingCoilType, HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - } // IF (IsNotOK) THEN - } + readHeatGasElecCoilData(state, + thisFurnace, + CurrentModuleObject, + HeatingCoilType, + HeatingCoilName, + HeatingCoilInletNode, + HeatingCoilOutletNode, + /*setHWCoilAirInletNode=*/false, + /*plfCurveIndex=*/&HeatingCoilPLFCurveIndex, + ErrorsFound); } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Water")) { thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWater; @@ -1680,53 +2067,9 @@ namespace Furnaces { if (IsNotOK) { ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; - } else { // mine data from heating coil object - - // Get the Heating Coil water Inlet or control Node number - errFlag = false; - thisFurnace.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil hot water max volume flow rate - errFlag = false; - thisFurnace.MaxHeatCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil Inlet Node - errFlag = false; - HeatingCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag); - thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil Outlet Node - errFlag = false; - HeatingCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag); - thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // check if user has also used a water coil controller, which they should not do - errFlag = false; - HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag); - if (!errFlag) { // then did find a controller so that is bad - ShowSevereError( - state, - EnergyPlus::format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name)); - ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems."); - ShowContinueError(state, "No water coil controller should be input for the coil."); - ErrorsFound = true; - } + } else { + readHeatWaterCoilData( + state, thisFurnace, CurrentModuleObject, HeatingCoilName, HeatingCoilInletNode, HeatingCoilOutletNode, ErrorsFound); } } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Steam")) { @@ -1735,49 +2078,16 @@ namespace Furnaces { if (IsNotOK) { ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; - } else { // mine data from heating coil object - - errFlag = false; - thisFurnace.HeatingCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag); - if (thisFurnace.HeatingCoilIndex == 0) { - ShowSevereError(state, EnergyPlus::format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), HeatingCoilName)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil steam inlet node number - errFlag = false; - thisFurnace.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil steam max volume flow rate - thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, errFlag); - if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) { - SteamDensity = - Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput); - thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity; - } - - // Get the Heating Coil Inlet Node - errFlag = false; - HeatingCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag); - thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil Outlet Node - errFlag = false; - HeatingCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag); - thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } + } else { + readHeatSteamCoilData(state, + thisFurnace, + CurrentModuleObject, + cAlphaFields(11), + HeatingCoilName, + getAirLoopHVACHeatCoolInput, + HeatingCoilInletNode, + HeatingCoilOutletNode, + ErrorsFound); } } else { @@ -1961,47 +2271,17 @@ namespace Furnaces { } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) { // BOS ADDED, AUG/2012, VARIIABLE SPEED DX COOLING COIL // Furnace(FurnaceNum)%DXCoolCoilType = 'COIL:COOLING:DX:VARIABLESPEED' - // Furnace(FurnaceNum)%DXCoolCoilName = CoolingCoilName - if (Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) { - thisFurnace.bIsIHP = true; - } - ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject); - - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - errFlag = false; - if (thisFurnace.bIsIHP) { - thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag); - IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName; - } else { - thisFurnace.CoolingCoilIndex = - VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag); - IHPCoilName = CoolingCoilName; - } - - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - if (thisFurnace.bIsIHP) { - CoolingCoilInletNode = - VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag); - CoolingCoilOutletNode = - VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag); - thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag); - } else { - CoolingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag); - CoolingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag); - thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag); - } + // Furnace(FurnaceNum)%DXCoolCoilName = CoolingCoilName + if (Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) { + thisFurnace.bIsIHP = true; + } + ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } + if (IsNotOK) { + ShowContinueError(state, EnergyPlus::format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1))); + ErrorsFound = true; + } else { + readVSCoolingCoilNodes(thisFurnace, Alphas(1), CoolingCoilType, CoolingCoilName, CoolingCoilInletNode, CoolingCoilOutletNode); } } else { ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); @@ -2046,20 +2326,7 @@ namespace Furnaces { thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None; thisFurnace.Humidistat = false; } - if (thisFurnace.Humidistat) { - for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) { - if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) { - continue; - } - AirNodeFound = true; - } - if (!AirNodeFound) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Did not find Air Node (Zone with Humidistat)."); - ShowContinueError(state, EnergyPlus::format("Specified {} = {}", cAlphaFields(6), Alphas(6))); - ErrorsFound = true; - } - } + checkHumidistatZone(state, thisFurnace, CurrentModuleObject, cAlphaFields(6), Alphas(6), AirNodeFound, ErrorsFound); } else { // invalid input ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(14), Alphas(14))); @@ -2142,54 +2409,9 @@ namespace Furnaces { if (IsNotOK) { ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; - } else { // mine data from heating coil object - - // Get the Heating Coil water Inlet or control Node number - errFlag = false; - thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the ReHeat Coil hot water max volume flow rate - errFlag = false; - thisFurnace.MaxSuppCoilFluidFlow = - WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", ReheatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the ReHeat Coil Inlet Node - errFlag = false; - ReheatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag); - thisFurnace.SuppCoilAirInletNode = ReheatCoilInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the ReHeat Coil Outlet Node - errFlag = false; - ReheatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag); - thisFurnace.SuppCoilAirOutletNode = ReheatCoilOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // check if user has also used a water coil controller, which they should not do - errFlag = false; - HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag); - if (!errFlag) { // then did find a controller so that is bad - ShowSevereError( - state, - EnergyPlus::format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name)); - ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems."); - ShowContinueError(state, "No water coil controller should be input for the coil."); - ErrorsFound = true; - } + } else { + readSuppWaterCoilData( + state, thisFurnace, CurrentModuleObject, ReheatingCoilName, ReheatCoilInletNode, ReheatCoilOutletNode, ErrorsFound); } } else if (Util::SameString(ReheatingCoilType, "Coil:Heating:Steam")) { @@ -2198,51 +2420,16 @@ namespace Furnaces { if (IsNotOK) { ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; - } else { // mine data from heating coil object - - errFlag = false; - thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", ReheatingCoilName, errFlag); - if (thisFurnace.SuppHeatCoilIndex == 0) { - ShowSevereError(state, - EnergyPlus::format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), ReheatingCoilName)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil steam inlet node number - errFlag = false; - thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", ReheatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil steam max volume flow rate - thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag); - if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) { - SteamDensity = - Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput); - thisFurnace.MaxSuppCoilFluidFlow = - SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity; - } - - // Get the Heating Coil Inlet Node - errFlag = false; - ReheatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, ReheatingCoilName, errFlag); - thisFurnace.SuppCoilAirInletNode = ReheatCoilInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil Outlet Node - errFlag = false; - ReheatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, ReheatingCoilName, errFlag); - thisFurnace.SuppCoilAirOutletNode = ReheatCoilOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } + } else { + readSuppSteamCoilData(state, + thisFurnace, + CurrentModuleObject, + cAlphaFields(11), + ReheatingCoilName, + getAirLoopHVACHeatCoolInput, + ReheatCoilInletNode, + ReheatCoilOutletNode, + ErrorsFound); } } else { // Illegal heating coil @@ -2688,49 +2875,9 @@ namespace Furnaces { } } - if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) { - if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxCoolAirVolFlow && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError( - state, - EnergyPlus::format( - "... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in cooling mode.", - thisFurnace.ActualFanVolFlowRate, - FanName)); - ShowContinueError(state, - EnergyPlus::format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(2))); - thisFurnace.MaxCoolAirVolFlow = thisFurnace.ActualFanVolFlowRate; - thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate; - } - if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxHeatAirVolFlow && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError( - state, - EnergyPlus::format( - "... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in heating mode.", - thisFurnace.ActualFanVolFlowRate, - FanName)); - ShowContinueError(state, - EnergyPlus::format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(3))); - thisFurnace.MaxHeatAirVolFlow = thisFurnace.ActualFanVolFlowRate; - thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate; - } - } + checkFanFlowVsHVACFlowRates(thisFurnace, Alphas(1), cNumericFields(2), cNumericFields(3), FanName); - if (thisFurnace.fanOpModeSched != nullptr) { - // Is this correct? 0.0 for max also? - if (!thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 0.0)) { - // set air flow control mode: - // UseCompressorOnFlow = operate at last cooling or heating air flow requested when compressor is off - // UseCompressorOffFlow = operate at value specified by user - // AirFlowControl only valid if fan opmode = ContFanCycComp - if (thisFurnace.MaxNoCoolHeatAirVolFlow == 0.0) { - thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow; - } else { - thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOffFlow; - } - } - } + setAirFlowControl(thisFurnace); if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) { errFlag = false; @@ -2833,76 +2980,8 @@ namespace Furnaces { Node::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes"); // Get the Controlling Zone or Location of the Furnace Thermostat - thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(5), state.dataHeatBal->Zone); - if (thisFurnace.ControlZoneNum == 0) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(5), Alphas(5))); - ErrorsFound = true; - } - // Get the node number for the zone with the thermostat - if (thisFurnace.ControlZoneNum > 0) { - AirNodeFound = false; - AirLoopFound = false; - int ControlledZoneNum = thisFurnace.ControlZoneNum; - // Find the controlled zone number for the specified thermostat location - thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode; - // Determine if furnace is on air loop served by the thermostat location specified - for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) { - int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode); - thisFurnace.airloopNum = AirLoopNumber; - if (AirLoopNumber > 0) { - for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) { - for (int CompNum = 1; - CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents; - ++CompNum) { - if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name, - Alphas(1)) || - !Util::SameString( - state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf, - CurrentModuleObject)) { - continue; - } - AirLoopFound = true; - thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode); - break; - } - if (AirLoopFound) { - break; - } - } - for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) { - if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) { - continue; - } - AirNodeFound = true; - } - for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) { - if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) { - continue; - } - AirNodeFound = true; - } - } - if (AirLoopFound) { - break; - } - } - if (!AirNodeFound) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Did not find air node (zone with thermostat)."); - ShowContinueError(state, EnergyPlus::format("Specified {} = {}", cAlphaFields(5), Alphas(5))); - ShowContinueError( - state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone."); - ErrorsFound = true; - } - if (!AirLoopFound) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Did not find correct AirLoopHVAC."); - ShowContinueError(state, EnergyPlus::format("Specified {} = {}", cAlphaFields(5), Alphas(5))); - ErrorsFound = true; - } - } + findControlledZoneAirLoop(state, thisFurnace, CurrentModuleObject, cAlphaFields(5), Alphas(5), ErrorsFound); // Get fan data FanName = Alphas(7); @@ -3035,281 +3114,99 @@ namespace Furnaces { errFlag = false; PrintMessage = false; thisFurnace.CoolingCoilType_Num = - HVACHXAssistedCoolingCoil::GetCoilGroupTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage); - } - - if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) { - - // Get the cooling coil node numbers - errFlag = false; - DXCoils::GetDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, errFlag); - CoolingCoilInletNode = DXCoils::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag); - CoolingCoilOutletNode = DXCoils::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the DX cooling coil design capacity - errFlag = false; - thisFurnace.DesignCoolingCapacity = DXCoils::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) { - - // Get the cooling coil node numbers - errFlag = false; - HVACHXAssistedCoolingCoil::GetHXDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, errFlag); - CoolingCoilInletNode = HVACHXAssistedCoolingCoil::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag); - CoolingCoilOutletNode = HVACHXAssistedCoolingCoil::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the heat exchanger assisted cooling coil design capacity - errFlag = false; - thisFurnace.DesignCoolingCapacity = HVACHXAssistedCoolingCoil::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // get the actual index to the DX cooling coil object - DXCoilIndex = HVACHXAssistedCoolingCoil::GetActualDXCoilIndex(state, CoolingCoilType, CoolingCoilName, ErrorsFound); - thisFurnace.ActualDXCoilIndexForHXAssisted = DXCoilIndex; - - } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) { - // BOS ADDED, AUG/2012, VARIIABLE SPEED DX COOLING COIL - // Furnace(FurnaceNum)%DXCoolCoilType = 'COIL:COOLING:DX:VARIABLESPEED' - // Furnace(FurnaceNum)%DXCoolCoilName = CoolingCoilName - ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - errFlag = false; - if (thisFurnace.bIsIHP) { - thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag); - IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName; - } else { - thisFurnace.CoolingCoilIndex = - VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag); - IHPCoilName = CoolingCoilName; - } - - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - if (thisFurnace.bIsIHP) { - CoolingCoilInletNode = - VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag); - CoolingCoilOutletNode = - VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag); - thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag); - } else { - CoolingCoilInletNode = - VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag); - CoolingCoilOutletNode = - VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag); - thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag); - } - - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(10), Alphas(10))); - ErrorsFound = true; - } - } - - if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed && - thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) { - // Furnace(FurnaceNum)%WatertoAirHPType = WatertoAir_VarSpeedEquationFit - if (thisFurnace.bIsIHP) { - VariableSpeedCoils::SetVarSpeedCoilData(state, - state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilIndex, - ErrorsFound, - _, - state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilIndex); - } else { - VariableSpeedCoils::SetVarSpeedCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, _, thisFurnace.HeatingCoilIndex); - } - } - - // Get supplemental heating coil information - SuppHeatCoilType = Alphas(12); - SuppHeatCoilName = Alphas(13); - thisFurnace.SuppHeatCoilType = SuppHeatCoilType; - thisFurnace.SuppHeatCoilName = SuppHeatCoilName; - errFlag = false; - if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Fuel") || Util::SameString(SuppHeatCoilType, "Coil:Heating:Electric")) { - - thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - IsNotOK = false; - ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("In {} \"{}\"", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - - } else { // mine data from the supplemental heating coil - - HeatingCoils::GetCoilIndex(state, SuppHeatCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the Supplemental Heating Coil Inlet Node Number - errFlag = false; - SupHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the Supplemental Heating Coil Outlet Node Number - errFlag = false; - SupHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); - - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the supplemental heating coil design capacity - errFlag = false; - thisFurnace.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - } // IF (IsNotOK) THEN - } - } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Water")) { - thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater; - ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { // mine data from heating coil object - - // Get the Heating Coil water Inlet or control Node number - errFlag = false; - thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the ReHeat Coil hot water max volume flow rate - errFlag = false; - thisFurnace.MaxSuppCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the ReHeat Coil Inlet Node - errFlag = false; - SupHeatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag); - thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the ReHeat Coil Outlet Node - errFlag = false; - SupHeatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag); - thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - errFlag = false; - HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag); - if (!errFlag) { // then did find a controller so that is bad - ShowSevereError( - state, - EnergyPlus::format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name)); - ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems."); - ShowContinueError(state, "No water coil controller should be input for the coil."); - ErrorsFound = true; - } - } - - } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Steam")) { - thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam; - ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { // mine data from heating coil object + HVACHXAssistedCoolingCoil::GetCoilGroupTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage); + } + + if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) { + // Get the cooling coil node numbers errFlag = false; - thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", SuppHeatCoilName, errFlag); - if (thisFurnace.SuppHeatCoilIndex == 0) { - ShowSevereError(state, EnergyPlus::format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(12), SuppHeatCoilName)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + DXCoils::GetDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, errFlag); + CoolingCoilInletNode = DXCoils::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag); + CoolingCoilOutletNode = DXCoils::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag); + if (errFlag) { + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; } - // Get the Heating Coil steam inlet node number + // Get the DX cooling coil design capacity errFlag = false; - thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", SuppHeatCoilName, errFlag); + thisFurnace.DesignCoolingCapacity = DXCoils::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag); if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; } - // Get the Heating Coil steam max volume flow rate - thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag); - if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) { - SteamDensity = - Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput); - thisFurnace.MaxSuppCoilFluidFlow = - SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity; - } + } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) { - // Get the Heating Coil Inlet Node + // Get the cooling coil node numbers errFlag = false; - SupHeatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag); - thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode; + HVACHXAssistedCoolingCoil::GetHXDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, errFlag); + CoolingCoilInletNode = HVACHXAssistedCoolingCoil::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag); + CoolingCoilOutletNode = HVACHXAssistedCoolingCoil::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag); if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); ErrorsFound = true; } - // Get the Heating Coil Outlet Node + // Get the heat exchanger assisted cooling coil design capacity errFlag = false; - SupHeatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag); - thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode; + thisFurnace.DesignCoolingCapacity = HVACHXAssistedCoolingCoil::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag); if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); + ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); + ErrorsFound = true; + } + + // get the actual index to the DX cooling coil object + DXCoilIndex = HVACHXAssistedCoolingCoil::GetActualDXCoilIndex(state, CoolingCoilType, CoolingCoilName, ErrorsFound); + thisFurnace.ActualDXCoilIndexForHXAssisted = DXCoilIndex; + + } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) { + // BOS ADDED, AUG/2012, VARIIABLE SPEED DX COOLING COIL + // Furnace(FurnaceNum)%DXCoolCoilType = 'COIL:COOLING:DX:VARIABLESPEED' + // Furnace(FurnaceNum)%DXCoolCoilName = CoolingCoilName + ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject); + if (IsNotOK) { + ShowContinueError(state, EnergyPlus::format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1))); ErrorsFound = true; + } else { + readVSCoolingCoilNodes(thisFurnace, Alphas(1), CoolingCoilType, CoolingCoilName, CoolingCoilInletNode, CoolingCoilOutletNode); } + } else { + ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); + ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(10), Alphas(10))); + ErrorsFound = true; } + } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(12), Alphas(12))); - ErrorsFound = true; - } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc. + if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed && + thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) { + // Furnace(FurnaceNum)%WatertoAirHPType = WatertoAir_VarSpeedEquationFit + if (thisFurnace.bIsIHP) { + VariableSpeedCoils::SetVarSpeedCoilData(state, + state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilIndex, + ErrorsFound, + _, + state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilIndex); + } else { + VariableSpeedCoils::SetVarSpeedCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, _, thisFurnace.HeatingCoilIndex); + } + } + + // Get supplemental heating coil information + SuppHeatCoilType = Alphas(12); + SuppHeatCoilName = Alphas(13); + thisFurnace.SuppHeatCoilType = SuppHeatCoilType; + thisFurnace.SuppHeatCoilName = SuppHeatCoilName; + readSuppHeatCoilData(state, + thisFurnace, + CurrentModuleObject, + SuppHeatCoilType, + SuppHeatCoilName, + cAlphaFields(12), + SupHeatCoilInletNode, + SupHeatCoilOutletNode, + ErrorsFound); thisFurnace.fanPlace = static_cast(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(14))); assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid); @@ -3363,20 +3260,7 @@ namespace Furnaces { thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None; thisFurnace.Humidistat = false; } - if (thisFurnace.Humidistat) { - for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) { - if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) { - continue; - } - AirNodeFound = true; - } - if (!AirNodeFound) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Did not find Air Node (Zone with Humidistat)."); - ShowContinueError(state, EnergyPlus::format("Specified {} = {}", cAlphaFields(5), Alphas(5))); - ErrorsFound = true; - } - } + checkHumidistatZone(state, thisFurnace, CurrentModuleObject, cAlphaFields(5), Alphas(5), AirNodeFound, ErrorsFound); } else { // invalid input or blank if (!lAlphaBlanks(16)) { ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); @@ -3550,19 +3434,7 @@ namespace Furnaces { ErrorsFound = true; } - if (thisFurnace.fanOpModeSched != nullptr) { - if (!thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 0.0)) { // Autodesk:Note Range is 0 to 0? - // set air flow control mode: - // UseCompressorOnFlow = operate at last cooling or heating air flow requested when compressor is off - // UseCompressorOffFlow = operate at value specified by user - // AirFlowControl only valid if fan opmode = ContFanCycComp - if (thisFurnace.MaxNoCoolHeatAirVolFlow == 0.0) { - thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow; - } else { - thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOffFlow; - } - } - } + setAirFlowControl(thisFurnace); if (Numbers(1) != DataSizing::AutoSize && Numbers(2) != DataSizing::AutoSize && Numbers(3) != DataSizing::AutoSize) { thisFurnace.DesignFanVolFlowRate = max(Numbers(1), Numbers(2), Numbers(3)); @@ -3600,34 +3472,7 @@ namespace Furnaces { } } - if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) { - if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxCoolAirVolFlow && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError( - state, - EnergyPlus::format( - "... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in cooling mode.", - thisFurnace.ActualFanVolFlowRate, - FanName)); - ShowContinueError(state, - EnergyPlus::format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(1))); - thisFurnace.MaxCoolAirVolFlow = thisFurnace.ActualFanVolFlowRate; - thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate; - } - if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxHeatAirVolFlow && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError( - state, - EnergyPlus::format( - "... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in heating mode.", - thisFurnace.ActualFanVolFlowRate, - FanName)); - ShowContinueError(state, - EnergyPlus::format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(2))); - thisFurnace.MaxHeatAirVolFlow = thisFurnace.ActualFanVolFlowRate; - thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate; - } - } + checkFanFlowVsHVACFlowRates(thisFurnace, Alphas(1), cNumericFields(1), cNumericFields(2), FanName); // Set heating convergence tolerance thisFurnace.HeatingConvergenceTolerance = 0.001; @@ -3780,76 +3625,8 @@ namespace Furnaces { Node::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes"); // Get the Controlling Zone or Location of the Furnace Thermostat - thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(5), state.dataHeatBal->Zone); - if (thisFurnace.ControlZoneNum == 0) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(5), Alphas(5))); - ErrorsFound = true; - } - // Get the node number for the zone with the thermostat - if (thisFurnace.ControlZoneNum > 0) { - AirNodeFound = false; - AirLoopFound = false; - int ControlledZoneNum = thisFurnace.ControlZoneNum; - // Find the controlled zone number for the specified thermostat location - thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode; - // Determine if furnace is on air loop served by the thermostat location specified - for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) { - int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode); - thisFurnace.airloopNum = AirLoopNumber; - if (AirLoopNumber > 0) { - for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) { - for (int CompNum = 1; - CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents; - ++CompNum) { - if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name, - Alphas(1)) || - !Util::SameString( - state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf, - CurrentModuleObject)) { - continue; - } - AirLoopFound = true; - thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode); - break; - } - if (AirLoopFound) { - break; - } - } - for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) { - if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) { - continue; - } - AirNodeFound = true; - } - for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) { - if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) { - continue; - } - AirNodeFound = true; - } - } - if (AirLoopFound) { - break; - } - } - if (!AirNodeFound) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Did not find air node (zone with thermostat)."); - ShowContinueError(state, EnergyPlus::format("Specified {} = {}", cAlphaFields(5), Alphas(5))); - ShowContinueError( - state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone."); - ErrorsFound = true; - } - if (!AirLoopFound) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Did not find correct AirLoopHVAC."); - ShowContinueError(state, EnergyPlus::format("Specified {} = {}", cAlphaFields(5), Alphas(5))); - ErrorsFound = true; - } - } + findControlledZoneAirLoop(state, thisFurnace, CurrentModuleObject, cAlphaFields(5), Alphas(5), ErrorsFound); // Get fan data FanName = Alphas(7); @@ -3873,92 +3650,32 @@ namespace Furnaces { } // Get heating coil type and name data - if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") { - HeatingCoilType = Alphas(8); - thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHP; - HeatingCoilName = Alphas(9); - ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - thisFurnace.HeatingCoilIndex = WaterToAirHeatPump::GetCoilIndex(state, HeatingCoilType, HeatingCoilName, errFlag); - HeatingCoilInletNode = WaterToAirHeatPump::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag); - HeatingCoilOutletNode = WaterToAirHeatPump::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag); - } - } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:EQUATIONFIT") { - HeatingCoilType = Alphas(8); - thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHPSimple; - HeatingCoilName = Alphas(9); - ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - thisFurnace.HeatingCoilIndex = WaterToAirHeatPumpSimple::GetCoilIndex(state, HeatingCoilType, HeatingCoilName, errFlag); - HeatingCoilInletNode = WaterToAirHeatPumpSimple::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag); - HeatingCoilOutletNode = WaterToAirHeatPumpSimple::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag); - } - } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT") { - HeatingCoilType = Alphas(8); - thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHPVSEquationFit; - HeatingCoilName = Alphas(9); - ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - thisFurnace.HeatingCoilIndex = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag); - HeatingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag); - HeatingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag); - } - } else { + if (!readWaterToAirCoil(wahpHeatingCoils, + Alphas(8), + Alphas(9), + cAlphaFields(8), + thisFurnace.HeatingCoilIndex, + thisFurnace.HeatingCoilType_Num, + HeatingCoilType, + HeatingCoilName, + HeatingCoilInletNode, + HeatingCoilOutletNode)) { ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(8), Alphas(8))); ErrorsFound = true; } // Get Cooling Coil Information if available - if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") { - CoolingCoilType = Alphas(10); - thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHP; - CoolingCoilName = Alphas(11); - ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - thisFurnace.CoolingCoilIndex = WaterToAirHeatPump::GetCoilIndex(state, CoolingCoilType, CoolingCoilName, errFlag); - CoolingCoilInletNode = WaterToAirHeatPump::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag); - CoolingCoilOutletNode = WaterToAirHeatPump::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag); - } - } else if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:EQUATIONFIT") { - CoolingCoilType = Alphas(10); - thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHPSimple; - CoolingCoilName = Alphas(11); - ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - thisFurnace.CoolingCoilIndex = WaterToAirHeatPumpSimple::GetCoilIndex(state, CoolingCoilType, CoolingCoilName, errFlag); - CoolingCoilInletNode = WaterToAirHeatPumpSimple::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag); - CoolingCoilOutletNode = WaterToAirHeatPumpSimple::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag); - } - } else if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT") { - CoolingCoilType = Alphas(10); - thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHPVSEquationFit; - CoolingCoilName = Alphas(11); - ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - thisFurnace.CoolingCoilIndex = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag); - CoolingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag); - CoolingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag); - } - } else { + if (!readWaterToAirCoil(wahpCoolingCoils, + Alphas(10), + Alphas(11), + cAlphaFields(10), + thisFurnace.CoolingCoilIndex, + thisFurnace.CoolingCoilType_Num, + CoolingCoilType, + CoolingCoilName, + CoolingCoilInletNode, + CoolingCoilOutletNode)) { ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(10), Alphas(10))); ErrorsFound = true; @@ -3981,176 +3698,26 @@ namespace Furnaces { thisFurnace.WatertoAirHPType = WAHPCoilType::VarSpeedEquationFit; VariableSpeedCoils::SetVarSpeedCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, _, thisFurnace.HeatingCoilIndex); } else { - ShowContinueError(state, EnergyPlus::format("For {} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Cooling coil and heating coil should be of same general type"); - ErrorsFound = true; - } - - // Get supplemental heating coil information - - SuppHeatCoilType = Alphas(12); - SuppHeatCoilName = Alphas(13); - thisFurnace.SuppHeatCoilType = SuppHeatCoilType; - thisFurnace.SuppHeatCoilName = SuppHeatCoilName; - errFlag = false; - if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Fuel") || Util::SameString(SuppHeatCoilType, "Coil:Heating:Electric")) { - - thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { - IsNotOK = false; - ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("In {} \"{}\"", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - - } else { // mine data from the supplemental heating coil - - HeatingCoils::GetCoilIndex(state, SuppHeatCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the Supplemental Heating Coil Inlet Node Number - errFlag = false; - SupHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the Supplemental Heating Coil Outlet Node Number - errFlag = false; - SupHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - // Get the supplemental heating coil design capacity - errFlag = false; - thisFurnace.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - - } // IF (IsNotOK) THEN - } - } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Water")) { - thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater; - ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { // mine data from heating coil object - - // Get the Heating Coil water Inlet or control Node number - errFlag = false; - thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the ReHeat Coil hot water max volume flow rate - errFlag = false; - thisFurnace.MaxSuppCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the ReHeat Coil Inlet Node - errFlag = false; - SupHeatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag); - thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the ReHeat Coil Outlet Node - errFlag = false; - SupHeatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag); - thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - errFlag = false; - HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag); - if (!errFlag) { // then did find a controller so that is bad - ShowSevereError( - state, - EnergyPlus::format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name)); - ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems."); - ShowContinueError(state, "No water coil controller should be input for the coil."); - ErrorsFound = true; - } - } - - } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Steam")) { - thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam; - ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else { // mine data from heating coil object - - errFlag = false; - thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, SuppHeatCoilType, SuppHeatCoilName, errFlag); - if (thisFurnace.SuppHeatCoilIndex == 0) { - ShowSevereError(state, EnergyPlus::format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(12), SuppHeatCoilName)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil steam inlet node number - errFlag = false; - thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", SuppHeatCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil steam max volume flow rate - thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag); - if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) { - SteamDensity = - Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput); - thisFurnace.MaxSuppCoilFluidFlow = - SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity; - } - - // Get the Heating Coil Inlet Node - errFlag = false; - SupHeatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag); - thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - - // Get the Heating Coil Outlet Node - errFlag = false; - SupHeatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag); - thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode; - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name)); - ErrorsFound = true; - } - } - - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(12), Alphas(12))); + ShowContinueError(state, EnergyPlus::format("For {} = {}", CurrentModuleObject, Alphas(1))); + ShowContinueError(state, "Cooling coil and heating coil should be of same general type"); ErrorsFound = true; - } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc. + } + + // Get supplemental heating coil information + + SuppHeatCoilType = Alphas(12); + SuppHeatCoilName = Alphas(13); + thisFurnace.SuppHeatCoilType = SuppHeatCoilType; + thisFurnace.SuppHeatCoilName = SuppHeatCoilName; + readSuppHeatCoilData(state, + thisFurnace, + CurrentModuleObject, + SuppHeatCoilType, + SuppHeatCoilName, + cAlphaFields(12), + SupHeatCoilInletNode, + SupHeatCoilOutletNode, + ErrorsFound); if (lAlphaBlanks(14)) { thisFurnace.CondenserNodeNum = 0; @@ -4209,20 +3776,7 @@ namespace Furnaces { thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None; thisFurnace.Humidistat = false; } - if (thisFurnace.Humidistat) { - for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) { - if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) { - continue; - } - AirNodeFound = true; - } - if (!AirNodeFound) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); - ShowContinueError(state, "Did not find Air Node (Zone with Humidistat)."); - ShowContinueError(state, EnergyPlus::format("Specified {} = {}", cAlphaFields(5), Alphas(5))); - ErrorsFound = true; - } - } + checkHumidistatZone(state, thisFurnace, CurrentModuleObject, cAlphaFields(5), Alphas(5), AirNodeFound, ErrorsFound); } else { // invalid input or blank if (!lAlphaBlanks(17)) { ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, Alphas(1))); @@ -4445,58 +3999,14 @@ namespace Furnaces { } } - // Set the heat pump heating coil capacity - // Get from coil module. - if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP) { - errFlag = false; - thisFurnace.DesignHeatingCapacity = WaterToAirHeatPump::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) { - errFlag = false; - thisFurnace.DesignHeatingCapacity = WaterToAirHeatPumpSimple::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) { - errFlag = false; - thisFurnace.DesignHeatingCapacity = - VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - } + // Set the heat pump heating coil capacity via dispatch table + thisFurnace.DesignHeatingCapacity = + getWaterToAirCoilCapacity(wahpHeatingCoils, thisFurnace.HeatingCoilType_Num, HeatingCoilType, HeatingCoilName); // Set the heat pump heating coil convergence thisFurnace.HeatingConvergenceTolerance = Numbers(2); - // Set the heat pump cooling coil capacity (Total capacity) - // Get from coil module. - if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHP) { - errFlag = false; - thisFurnace.DesignCoolingCapacity = WaterToAirHeatPump::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPSimple) { - errFlag = false; - thisFurnace.DesignCoolingCapacity = WaterToAirHeatPumpSimple::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPVSEquationFit) { - errFlag = false; - thisFurnace.DesignCoolingCapacity = - VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag); - if (errFlag) { - ShowContinueError(state, EnergyPlus::format("...occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } - } + // Set the heat pump cooling coil capacity (Total capacity) via dispatch table + thisFurnace.DesignCoolingCapacity = + getWaterToAirCoilCapacity(wahpCoolingCoils, thisFurnace.CoolingCoilType_Num, CoolingCoilType, CoolingCoilName); // Set the heat pump cooling coil convergence thisFurnace.CoolingConvergenceTolerance = Numbers(3); @@ -4526,54 +4036,13 @@ namespace Furnaces { ShowFatalError(state, "Errors found in getting Furnace or Unitary System input."); } - for (int HeatOnlyNum = 1; HeatOnlyNum <= NumHeatOnly; ++HeatOnlyNum) { - FurnaceNum = HeatOnlyNum; - auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum); - // Setup Report variables for the Furnace that are not reported in the components themselves - SetupOutputVariable(state, - "Unitary System Fan Part Load Ratio", - Constant::Units::None, - thisFurnace.FanPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - if (state.dataGlobal->AnyEnergyManagementSystemInModel) { - SetupEMSActuator(state, - "AirLoopHVAC:Unitary:Furnace:HeatOnly", - thisFurnace.Name, - "Autosized Supply Air Flow Rate", - "[m3/s]", - thisFurnace.DesignFanVolFlowRateEMSOverrideOn, - thisFurnace.DesignFanVolFlowRateEMSOverrideValue); - } - } - - for (int UnitaryHeatOnlyNum = NumHeatOnly + 1; UnitaryHeatOnlyNum <= NumHeatOnly + NumUnitaryHeatOnly; ++UnitaryHeatOnlyNum) { - FurnaceNum = UnitaryHeatOnlyNum; + // Single loop over all furnaces registers output variables and EMS actuators. + // The "Fan Part Load Ratio" variable is common to every type; additional variables + // and actuator object-type strings vary by UnitarySysType. + for (FurnaceNum = 1; FurnaceNum <= state.dataFurnaces->NumFurnaces; ++FurnaceNum) { auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum); - // Setup Report variables for Unitary System that are not reported in the components themselves - SetupOutputVariable(state, - "Unitary System Fan Part Load Ratio", - Constant::Units::None, - thisFurnace.FanPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - if (state.dataGlobal->AnyEnergyManagementSystemInModel) { - SetupEMSActuator(state, - "AirLoopHVAC:UnitaryHeatOnly", - thisFurnace.Name, - "Autosized Supply Air Flow Rate", - "[m3/s]", - thisFurnace.DesignFanVolFlowRateEMSOverrideOn, - thisFurnace.DesignFanVolFlowRateEMSOverrideValue); - } - } - for (int HeatCoolNum = NumHeatOnly + NumUnitaryHeatOnly + 1; HeatCoolNum <= NumHeatOnly + NumUnitaryHeatOnly + NumHeatCool; ++HeatCoolNum) { - FurnaceNum = HeatCoolNum; - auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum); - // Setup Report variables for the Furnace that are not reported in the components themselves + // All furnace/unitary types report fan PLR SetupOutputVariable(state, "Unitary System Fan Part Load Ratio", Constant::Units::None, @@ -4581,194 +4050,123 @@ namespace Furnaces { OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, thisFurnace.Name); - SetupOutputVariable(state, - "Unitary System Compressor Part Load Ratio", - Constant::Units::None, - thisFurnace.CompPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - if (state.dataGlobal->AnyEnergyManagementSystemInModel) { - SetupEMSActuator(state, - "AirLoopHVAC:Unitary:Furnace:HeatCool", - thisFurnace.Name, - "Autosized Supply Air Flow Rate", - "[m3/s]", - thisFurnace.DesignFanVolFlowRateEMSOverrideOn, - thisFurnace.DesignFanVolFlowRateEMSOverrideValue); - SetupEMSActuator(state, - "AirLoopHVAC:Unitary:Furnace:HeatCool", - thisFurnace.Name, - "Autosized Supply Air Flow Rate During Cooling Operation", - "[m3/s]", - thisFurnace.MaxCoolAirVolFlowEMSOverrideOn, - thisFurnace.MaxCoolAirVolFlowEMSOverrideValue); - SetupEMSActuator(state, - "AirLoopHVAC:Unitary:Furnace:HeatCool", - thisFurnace.Name, - "Autosized Supply Air Flow Rate During Heating Operation", - "[m3/s]", - thisFurnace.MaxHeatAirVolFlowEMSOverrideOn, - thisFurnace.MaxHeatAirVolFlowEMSOverrideValue); - SetupEMSActuator(state, - "AirLoopHVAC:Unitary:Furnace:HeatCool", - thisFurnace.Name, - "Autosized Supply Air Flow Rate During No Heating or Cooling Operation", - "[m3/s]", - thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideOn, - thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideValue); + switch (thisFurnace.type) { + case HVAC::UnitarySysType::Furnace_HeatCool: + case HVAC::UnitarySysType::Unitary_HeatCool: + case HVAC::UnitarySysType::Unitary_HeatPump_AirToAir: + case HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir: + SetupOutputVariable(state, + "Unitary System Compressor Part Load Ratio", + Constant::Units::None, + thisFurnace.CompPartLoadRatio, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisFurnace.Name); + break; + default: + break; } - } - for (int UnitaryHeatCoolNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + 1; - UnitaryHeatCoolNum <= NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool; - ++UnitaryHeatCoolNum) { - FurnaceNum = UnitaryHeatCoolNum; - auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum); - // Setup Report variables for Unitary System that are not reported in the components themselves - SetupOutputVariable(state, - "Unitary System Fan Part Load Ratio", - Constant::Units::None, - thisFurnace.FanPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - SetupOutputVariable(state, - "Unitary System Compressor Part Load Ratio", - Constant::Units::None, - thisFurnace.CompPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - if (state.dataGlobal->AnyEnergyManagementSystemInModel) { - SetupEMSActuator(state, - "AirLoopHVAC:UnitaryHeatCool", - thisFurnace.Name, - "Autosized Supply Air Flow Rate", - "[m3/s]", - thisFurnace.DesignFanVolFlowRateEMSOverrideOn, - thisFurnace.DesignFanVolFlowRateEMSOverrideValue); - SetupEMSActuator(state, - "AirLoopHVAC:UnitaryHeatCool", - thisFurnace.Name, - "Autosized Supply Air Flow Rate During Cooling Operation", - "[m3/s]", - thisFurnace.MaxCoolAirVolFlowEMSOverrideOn, - thisFurnace.MaxCoolAirVolFlowEMSOverrideValue); - SetupEMSActuator(state, - "AirLoopHVAC:UnitaryHeatCool", - thisFurnace.Name, - "Autosized Supply Air Flow Rate During Heating Operation", - "[m3/s]", - thisFurnace.MaxHeatAirVolFlowEMSOverrideOn, - thisFurnace.MaxHeatAirVolFlowEMSOverrideValue); - SetupEMSActuator(state, - "AirLoopHVAC:UnitaryHeatCool", - thisFurnace.Name, - "Autosized Supply Air Flow Rate During No Heating or Cooling Operation", - "[m3/s]", - thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideOn, - thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideValue); + if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) { + SetupOutputVariable(state, + "Unitary System Dehumidification Induced Heating Demand Rate", + Constant::Units::W, + thisFurnace.DehumidInducedHeatingDemandRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisFurnace.Name); + } + + if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) { + SetupOutputVariable(state, + "Unitary System Requested Sensible Cooling Rate", + Constant::Units::W, + thisFurnace.CoolingCoilSensDemand, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisFurnace.Name); + SetupOutputVariable(state, + "Unitary System Requested Latent Cooling Rate", + Constant::Units::W, + thisFurnace.CoolingCoilLatentDemand, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisFurnace.Name); + SetupOutputVariable(state, + "Unitary System Requested Heating Rate", + Constant::Units::W, + thisFurnace.HeatingCoilSensDemand, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisFurnace.Name); + SetupOutputVariable(state, + "Unitary System Dehumidification Induced Heating Demand Rate", + Constant::Units::W, + thisFurnace.DehumidInducedHeatingDemandRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisFurnace.Name); } - } - - for (int HeatPumpNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + 1; - HeatPumpNum <= state.dataFurnaces->NumFurnaces - NumWaterToAirHeatPump; - ++HeatPumpNum) { - FurnaceNum = HeatPumpNum; - auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum); - // Setup Report variables for Unitary System that are not reported in the components themselves - SetupOutputVariable(state, - "Unitary System Fan Part Load Ratio", - Constant::Units::None, - thisFurnace.FanPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - SetupOutputVariable(state, - "Unitary System Compressor Part Load Ratio", - Constant::Units::None, - thisFurnace.CompPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - SetupOutputVariable(state, - "Unitary System Dehumidification Induced Heating Demand Rate", - Constant::Units::W, - thisFurnace.DehumidInducedHeatingDemandRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); if (state.dataGlobal->AnyEnergyManagementSystemInModel) { + // Determine the EMS object-type string for this furnace type + std::string_view emsObjType; + switch (thisFurnace.type) { + case HVAC::UnitarySysType::Furnace_HeatOnly: + emsObjType = "AirLoopHVAC:Unitary:Furnace:HeatOnly"; + break; + case HVAC::UnitarySysType::Unitary_HeatOnly: + emsObjType = "AirLoopHVAC:UnitaryHeatOnly"; + break; + case HVAC::UnitarySysType::Furnace_HeatCool: + emsObjType = "AirLoopHVAC:Unitary:Furnace:HeatCool"; + break; + case HVAC::UnitarySysType::Unitary_HeatCool: + emsObjType = "AirLoopHVAC:UnitaryHeatCool"; + break; + case HVAC::UnitarySysType::Unitary_HeatPump_AirToAir: + emsObjType = "AirLoopHVAC:UnitaryHeatPump:AirToAir"; + break; + case HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir: + emsObjType = "AirLoopHVAC:UnitaryHeatPump:WaterToAir"; + break; + default: + emsObjType = ""; + break; + } SetupEMSActuator(state, - "AirLoopHVAC:UnitaryHeatPump:AirToAir", + emsObjType, thisFurnace.Name, "Autosized Supply Air Flow Rate", "[m3/s]", thisFurnace.DesignFanVolFlowRateEMSOverrideOn, thisFurnace.DesignFanVolFlowRateEMSOverrideValue); - } - } - - for (int HeatPumpNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + NumHeatPump + 1; - HeatPumpNum <= state.dataFurnaces->NumFurnaces; - ++HeatPumpNum) { - FurnaceNum = HeatPumpNum; - auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum); - // Setup Report variables for Unitary System that are not reported in the components themselves - SetupOutputVariable(state, - "Unitary System Fan Part Load Ratio", - Constant::Units::None, - thisFurnace.FanPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - SetupOutputVariable(state, - "Unitary System Compressor Part Load Ratio", - Constant::Units::None, - thisFurnace.CompPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - SetupOutputVariable(state, - "Unitary System Requested Sensible Cooling Rate", - Constant::Units::W, - thisFurnace.CoolingCoilSensDemand, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - SetupOutputVariable(state, - "Unitary System Requested Latent Cooling Rate", - Constant::Units::W, - thisFurnace.CoolingCoilLatentDemand, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - SetupOutputVariable(state, - "Unitary System Requested Heating Rate", - Constant::Units::W, - thisFurnace.HeatingCoilSensDemand, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - SetupOutputVariable(state, - "Unitary System Dehumidification Induced Heating Demand Rate", - Constant::Units::W, - thisFurnace.DehumidInducedHeatingDemandRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisFurnace.Name); - if (state.dataGlobal->AnyEnergyManagementSystemInModel) { - SetupEMSActuator(state, - "AirLoopHVAC:UnitaryHeatPump:WaterToAir", - thisFurnace.Name, - "Autosized Supply Air Flow Rate", - "[m3/s]", - thisFurnace.DesignFanVolFlowRateEMSOverrideOn, - thisFurnace.DesignFanVolFlowRateEMSOverrideValue); + // HeatCool types additionally register per-mode flow-rate actuators + if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool || thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool) { + SetupEMSActuator(state, + emsObjType, + thisFurnace.Name, + "Autosized Supply Air Flow Rate During Cooling Operation", + "[m3/s]", + thisFurnace.MaxCoolAirVolFlowEMSOverrideOn, + thisFurnace.MaxCoolAirVolFlowEMSOverrideValue); + SetupEMSActuator(state, + emsObjType, + thisFurnace.Name, + "Autosized Supply Air Flow Rate During Heating Operation", + "[m3/s]", + thisFurnace.MaxHeatAirVolFlowEMSOverrideOn, + thisFurnace.MaxHeatAirVolFlowEMSOverrideValue); + SetupEMSActuator(state, + emsObjType, + thisFurnace.Name, + "Autosized Supply Air Flow Rate During No Heating or Cooling Operation", + "[m3/s]", + thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideOn, + thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideValue); + } } } @@ -6784,6 +6182,55 @@ namespace Furnaces { furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace; } + // Helper: create a CalcFurnaceResidual lambda and solve for PLR via RegulaFalsi. + // Returns SolFlag (>0 = converged iterations, -1 = max-iter, -2 = bounds error). + // On return, resultPLR holds the solved part-load ratio and OnOffAirFlowRatio is + // restored from the saved value. + static int solveFurnaceResidual(EnergyPlusData &state, + Real64 const errorToler, + int const maxIter, + Real64 &resultPLR, + int const FurnaceNum, + bool const FirstHVACIteration, + HVAC::FanOp const fanOp, + HVAC::CompressorOp const compressorOp, + Real64 const loadToBeMet, + Real64 const par6_loadFlag, + Real64 const par7_sensLatentFlag, + Real64 const par9_HXOnFlag, + Real64 const par10_HeatingCoilPLR, + Real64 const plrMin, + Real64 const plrMax, + Real64 &OnOffAirFlowRatio) + { + int SolFlag = 0; + auto f = [&state, + FurnaceNum, + FirstHVACIteration, + fanOp, + compressorOp, + loadToBeMet, + par6_loadFlag, + par7_sensLatentFlag, + par9_HXOnFlag, + par10_HeatingCoilPLR](Real64 const PartLoadRatio) { + return CalcFurnaceResidual(state, + PartLoadRatio, + FurnaceNum, + FirstHVACIteration, + fanOp, + compressorOp, + loadToBeMet, + par6_loadFlag, + par7_sensLatentFlag, + par9_HXOnFlag, + par10_HeatingCoilPLR); + }; + General::SolveRoot(state, errorToler, maxIter, SolFlag, resultPLR, f, plrMin, plrMax); + OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave; + return SolFlag; + } + void CalcNewZoneHeatCoolFlowRates(EnergyPlusData &state, int const FurnaceNum, bool const FirstHVACIteration, @@ -6881,6 +6328,9 @@ namespace Furnaces { Real64 &SystemSensibleLoad = state.dataFurnaces->SystemSensibleLoad; auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum); + bool const isHP = + thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir || + (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple); // Set local variables int FurnaceOutletNode = thisFurnace.FurnaceOutletNodeNum; int FurnaceInletNode = thisFurnace.FurnaceInletNodeNum; @@ -6919,8 +6369,7 @@ namespace Furnaces { // Init for heating if (state.dataFurnaces->HeatingLoad) { - if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir || - (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) { + if (isHP) { thisFurnace.HeatPartLoadRatio = 1.0; HeatCoilLoad = 0.0; thisFurnace.HeatingCoilSensDemand = 0.0; @@ -6966,8 +6415,7 @@ namespace Furnaces { Real64 &CoolCoilLoad = state.dataFurnaces->CoolCoilLoad; if (state.dataFurnaces->HeatingLoad) { CoolCoilLoad = 0.0; - if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir || - (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) { + if (isHP) { SystemSensibleLoad = ZoneLoad; SystemMoistureLoad = 0.0; HeatCoilLoad = 0.0; @@ -7014,8 +6462,7 @@ namespace Furnaces { if ((thisFurnace.availSched->getCurrentVal() > 0.0) && (state.dataFurnaces->HeatingLoad)) { // Heat pumps only calculate a single PLR each time step (i.e. only cooling or heating allowed in a single time step) - if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir || - (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) { + if (isHP) { state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace; @@ -7077,24 +6524,22 @@ namespace Furnaces { // Calculate the part load ratio through iteration HeatErrorToler = thisFurnace.HeatingConvergenceTolerance; // Error tolerance for convergence from input deck - int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect - // HeatErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate - auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) { - return CalcFurnaceResidual(state, - PartLoadRatio, - FurnaceNum, - FirstHVACIteration, - fanOp, - compressorOp, - SystemSensibleLoad, - 0.0, // par6_loadFlag, - 1.0, // par7_sensLatentFlag, - 0.0, // par9_HXOnFlag, - 0.0); // par10_HeatingCoilPLR); - }; - General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0); - // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR. - OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave; + int SolFlag = solveFurnaceResidual(state, + HeatErrorToler, + MaxIter, + PartLoadRatio, + FurnaceNum, + FirstHVACIteration, + fanOp, + compressorOp, + SystemSensibleLoad, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 1.0, + OnOffAirFlowRatio); if (SolFlag < 0) { if (SolFlag == -1) { CalcFurnaceOutput(state, @@ -7302,24 +6747,22 @@ namespace Furnaces { // Calculate the part load ratio through iteration HeatErrorToler = thisFurnace.HeatingConvergenceTolerance; // Error tolerance for convergence from input deck - int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect - // HeatErrorToler is in fraction load, MaxIter = 30, SolFalg = # of iterations or error as appropriate - auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) { - return CalcFurnaceResidual(state, - PartLoadRatio, - FurnaceNum, - FirstHVACIteration, - fanOp, - compressorOp, - SystemSensibleLoad, - 0.0, // par6_loadFlag, - 1.0, // par7_sensLatentFlag, - 0.0, // par9_HXOnFlag, - 0.0); // par10_HeatingCoilPLR); - }; - General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0); - // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR. - OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave; + int SolFlag = solveFurnaceResidual(state, + HeatErrorToler, + MaxIter, + PartLoadRatio, + FurnaceNum, + FirstHVACIteration, + fanOp, + compressorOp, + SystemSensibleLoad, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 1.0, + OnOffAirFlowRatio); // Reset HeatCoilLoad calculated in CalcFurnaceResidual (in case it was reset because output temp > // DesignMaxOutletTemp) if (state.dataFurnaces->ModifiedHeatCoilLoad > 0.0) { @@ -7375,21 +6818,22 @@ namespace Furnaces { false); } // Now solve again with tighter PLR limits - auto f2 = // (AUTO_OK_LAMBDA) - [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) { - return CalcFurnaceResidual(state, - PartLoadRatio, - FurnaceNum, - FirstHVACIteration, - fanOp, - compressorOp, - SystemSensibleLoad, - 0.0, // par6_loadFlag, - 1.0, // par7_sensLatentFlag, - 0.0, // par9_HXOnFlag, - 0.0); // par10_HeatingCoilPLR); - }; - General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f2, TempMinPLR, TempMaxPLR); + SolFlag = solveFurnaceResidual(state, + HeatErrorToler, + MaxIter, + PartLoadRatio, + FurnaceNum, + FirstHVACIteration, + fanOp, + compressorOp, + SystemSensibleLoad, + 0.0, + 1.0, + 0.0, + 0.0, + TempMinPLR, + TempMaxPLR, + OnOffAirFlowRatio); if (state.dataFurnaces->ModifiedHeatCoilLoad > 0.0) { HeatCoilLoad = state.dataFurnaces->ModifiedHeatCoilLoad; } else { @@ -7602,26 +7046,23 @@ namespace Furnaces { // Calculate the sensible part load ratio through iteration CoolErrorToler = thisFurnace.CoolingConvergenceTolerance; // Error tolerance for convergence from input deck - int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect Real64 par8_HXFlag = HXUnitOn ? 1.0 : 0.0; - // CoolErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate - auto f = - [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, CoolCoilLoad, par8_HXFlag](Real64 const PartLoadRatio) { - return CalcFurnaceResidual(state, + int SolFlag = solveFurnaceResidual(state, + CoolErrorToler, + MaxIter, PartLoadRatio, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, CoolCoilLoad, - 1.0, // par6_loadFlag, - 1.0, // par7_sensLatentFlag, - par8_HXFlag, // par9_HXOnFlag, - 0.0); // par10_HeatingCoilPLR); - }; - General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0); - // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR. - OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave; + 1.0, + 1.0, + par8_HXFlag, + 0.0, + 0.0, + 1.0, + OnOffAirFlowRatio); if (SolFlag < 0) { if (SolFlag == -1) { CalcFurnaceOutput(state, @@ -7805,31 +7246,22 @@ namespace Furnaces { } else { par9_HtgCoilPLR = 0.0; } - auto f = [&state, - FurnaceNum, - FirstHVACIteration, - fanOp, - compressorOp, - par4_load, - par6_LatentSens, - par8_HXUnit, - par9_HtgCoilPLR](Real64 const PartLoadRatio) { - return CalcFurnaceResidual(state, - PartLoadRatio, + SolFlag = solveFurnaceResidual(state, + CoolErrorToler, + MaxIter, + LatentPartLoadRatio, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, par4_load, - 1.0, // par6_loadFlag, - par6_LatentSens, // par7_sensLatentFlag, - par8_HXUnit, // par9_HXOnFlag, - par9_HtgCoilPLR); // par10_HeatingCoilPLR); - }; - // CoolErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate - General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, LatentPartLoadRatio, f, 0.0, 1.0); - // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR. - OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave; + 1.0, + par6_LatentSens, + par8_HXUnit, + par9_HtgCoilPLR, + 0.0, + 1.0, + OnOffAirFlowRatio); if (SolFlag == -1) { // RegulaFalsi may not find latent PLR when the latent degradation model is used. // If iteration limit is exceeded, find tighter boundary of solution and repeat RegulaFalsi @@ -7905,30 +7337,22 @@ namespace Furnaces { CoolingHeatingPLRRatio); } // tighter boundary of solution has been found, call RegulaFalsi a second time - auto f2 = [&state, - FurnaceNum, - FirstHVACIteration, - fanOp, - compressorOp, - par4_load, - par6_LatentSens, - par8_HXUnit, - par9_HtgCoilPLR](Real64 const PartLoadRatio) { - return CalcFurnaceResidual(state, - PartLoadRatio, + SolFlag = solveFurnaceResidual(state, + CoolErrorToler, + MaxIter, + LatentPartLoadRatio, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, par4_load, - 1.0, // par6_loadFlag, - par6_LatentSens, // par7_sensLatentFlag, - par8_HXUnit, // par9_HXOnFlag, - par9_HtgCoilPLR); // par10_HeatingCoilPLR); - }; - General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, LatentPartLoadRatio, f2, TempMinPLR2, TempMaxPLR); - // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR. - OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave; + 1.0, + par6_LatentSens, + par8_HXUnit, + par9_HtgCoilPLR, + TempMinPLR2, + TempMaxPLR, + OnOffAirFlowRatio); if (SolFlag == -1) { // Set cooling to heating PLR for use with Subroutine CalcFurnaceOutput. @@ -8143,9 +7567,7 @@ namespace Furnaces { // the heating coil pick up the load due to outdoor air. ReheatCoilLoad = max(0.0, (ActualSensibleOutput - NoCoolOutput) * (-1.0)); // Dehumidification is not required - if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir || - (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && - thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) { + if (isHP) { ReheatCoilLoad = max(QToHeatSetPt, QToHeatSetPt - ActualSensibleOutput); } thisFurnace.DehumidInducedHeatingDemandRate = max(0.0, ActualSensibleOutput * (-1.0)); @@ -8177,8 +7599,7 @@ namespace Furnaces { } thisFurnace.MdotFurnace = state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate; - if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir || - (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) { + if (isHP) { } else { // Non-HeatPump (non-DX) heating coils do not set PLR, reset to 0 here. This variable was set for non-DX // coils to allow the SetAverageAirFlow CALL above to set the correct air mass flow rate. See this diff --git a/src/EnergyPlus/HVACMultiSpeedHeatPump.cc b/src/EnergyPlus/HVACMultiSpeedHeatPump.cc index 41fb2d40947..9de7e725699 100644 --- a/src/EnergyPlus/HVACMultiSpeedHeatPump.cc +++ b/src/EnergyPlus/HVACMultiSpeedHeatPump.cc @@ -446,6 +446,106 @@ namespace HVACMultiSpeedHeatPump { //****************************************************************************** + // Helper: validate that speed-level volume flow rates are positive and in ascending order. + // Used for both heating and cooling flow rate arrays. + static void validateSpeedFlowRates(EnergyPlusData &state, + std::string_view objName, + Array1D const &flowRates, + int numSpeeds, + int numericOffset, + Array1D_string const &cNumericFields, + bool alwaysValidatePositive, + bool &ErrorsFound) + { + // Validate positive flow rates + for (int i = 1; i <= numSpeeds; ++i) { + if (alwaysValidatePositive) { + if (flowRates(i) <= 0.0 && flowRates(i) != DataSizing::AutoSize) { + ShowSevereError(state, + EnergyPlus::format("{}, \"{}\", {} must be greater than zero.", + state.dataHVACMultiSpdHP->CurrentModuleObject, + objName, + cNumericFields(numericOffset + i))); + ErrorsFound = true; + } + } + } + // Ensure flow rate at high speed is >= flow rate at low speed + for (int i = 2; i <= numSpeeds; ++i) { + if (flowRates(i) == DataSizing::AutoSize) { + continue; + } + bool Found = false; + int j = 0; + for (j = i - 1; j >= 1; --j) { + if (flowRates(i) != DataSizing::AutoSize) { + Found = true; + break; + } + } + if (Found) { + if (flowRates(i) < flowRates(j)) { + ShowSevereError(state, + EnergyPlus::format( + "{}, \"{}\", {}", state.dataHVACMultiSpdHP->CurrentModuleObject, objName, cNumericFields(numericOffset + i))); + ShowContinueError(state, EnergyPlus::format(" cannot be less than {}", cNumericFields(numericOffset + j))); + ErrorsFound = true; + } + } + } + } + + // Helper: read supplemental heating coil data for Fuel or Electric coil types. + // Both branches share the same logic differing only in the HVAC type constant and coil type string. + static void readSuppHeatingCoilFuelOrElectric(EnergyPlusData &state, + MSHeatPumpData &thisMSHP, + int suppHeatCoilHVACType, + std::string_view coilTypeStr, + Array1D_string const &Alphas, + Array1D_string const &cAlphaFields, + bool &ErrorsFound, + int &SuppHeatCoilInletNode, + int &SuppHeatCoilOutletNode) + { + thisMSHP.SuppHeatCoilType = suppHeatCoilHVACType; + bool errFlag = false; + thisMSHP.SuppHeatCoilNum = HeatingCoils::GetHeatingCoilIndex(state, std::string{coilTypeStr}, Alphas(15), errFlag); + if (thisMSHP.SuppHeatCoilNum <= 0 || errFlag) { + ShowContinueError(state, + EnergyPlus::format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); + ShowContinueError(state, EnergyPlus::format("{} of type {} \"{}\" not found.", cAlphaFields(15), coilTypeStr, Alphas(15))); + ErrorsFound = true; + } + + // Get the Supplemental Heating Coil Node Numbers + bool LocalError = false; + SuppHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, Alphas(14), Alphas(15), LocalError); + if (LocalError) { + ShowSevereError(state, EnergyPlus::format("The inlet node number of {} is not found \"{}\"", cAlphaFields(15), Alphas(15))); + ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); + ErrorsFound = true; + LocalError = false; + } + SuppHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, Alphas(14), Alphas(15), LocalError); + if (LocalError) { + ShowSevereError(state, EnergyPlus::format("The outlet node number of {} is not found \"{}\"", cAlphaFields(15), Alphas(15))); + ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); + ErrorsFound = true; + LocalError = false; + } + + // Get supplemental heating coil capacity to see if it is autosize + thisMSHP.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, Alphas(14), Alphas(15), LocalError); + if (LocalError) { + ShowSevereError(state, EnergyPlus::format("The capacity {} is not found \"{}\"", cAlphaFields(15), Alphas(15))); + ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); + ErrorsFound = true; + LocalError = false; + } + Node::SetUpCompSets( + state, state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name, coilTypeStr, thisMSHP.SuppHeatCoilName, "UNDEFINED", "UNDEFINED"); + } + void GetMSHeatPumpInput(EnergyPlusData &state) { // SUBROUTINE INFORMATION: @@ -470,8 +570,6 @@ namespace HVACMultiSpeedHeatPump { bool AirNodeFound; // True when an air node is found bool AirLoopFound; // True when an air loop is found int i; // Index to speeds - int j; // Index to speeds - bool Found; // Flag to find autosize bool LocalError; // Local error flag Array1D_string Alphas; // Alpha input items for object Array1D_string cAlphaFields; // Alpha field names @@ -763,44 +861,23 @@ namespace HVACMultiSpeedHeatPump { } else if (Util::SameString(Alphas(10), "Coil:Heating:Electric:MultiStage") || Util::SameString(Alphas(10), "Coil:Heating:Gas:MultiStage")) { - if (Util::SameString(Alphas(10), "Coil:Heating:Electric:MultiStage")) { - thisMSHP.HeatCoilType = HVAC::Coil_HeatingElectric_MultiStage; - thisMSHP.HeatCoilNum = - state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Coil:Heating:Electric:MultiStage", Alphas(11)); - if (thisMSHP.HeatCoilNum <= 0) { - ShowSevereError( - state, EnergyPlus::format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("{} \"{}\" not found.", cAlphaFields(11), Alphas(11))); - ShowContinueError(state, EnergyPlus::format("{} must be Coil:Heating:Electric:MultiStage ", cAlphaFields(10))); - ShowFatalError(state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", - RoutineName, - state.dataHVACMultiSpdHP->CurrentModuleObject)); - ErrorsFound = true; - } - } else { - thisMSHP.HeatCoilType = HVAC::Coil_HeatingGas_MultiStage; - thisMSHP.HeatCoilNum = - state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Coil:Heating:Gas:MultiStage", Alphas(11)); - if (thisMSHP.HeatCoilNum <= 0) { - ShowSevereError( - state, EnergyPlus::format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("{} \"{}\" not found.", cAlphaFields(11), Alphas(11))); - ShowContinueError(state, EnergyPlus::format("{} must be Coil:Heating:Gas:MultiStage ", cAlphaFields(10))); - ShowFatalError(state, - EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", - RoutineName, - state.dataHVACMultiSpdHP->CurrentModuleObject)); - ErrorsFound = true; - } + thisMSHP.HeatCoilType = Util::SameString(Alphas(10), "Coil:Heating:Electric:MultiStage") ? HVAC::Coil_HeatingElectric_MultiStage + : HVAC::Coil_HeatingGas_MultiStage; + thisMSHP.HeatCoilNum = state.dataInputProcessing->inputProcessor->getObjectItemNum(state, Alphas(10), Alphas(11)); + if (thisMSHP.HeatCoilNum <= 0) { + ShowSevereError(state, + EnergyPlus::format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); + ShowContinueError(state, EnergyPlus::format("{} \"{}\" not found.", cAlphaFields(11), Alphas(11))); + ShowContinueError(state, EnergyPlus::format("{} must be {} ", cAlphaFields(10), Alphas(10))); + ShowFatalError(state, + EnergyPlus::format("{}Errors found in getting {} input. Preceding condition(s) causes termination.", + RoutineName, + state.dataHVACMultiSpdHP->CurrentModuleObject)); + ErrorsFound = true; } thisMSHP.HeatCoilName = Alphas(11); LocalError = false; - if (Util::SameString(Alphas(10), "Coil:Heating:Electric:MultiStage")) { - HeatingCoils::GetCoilIndex(state, thisMSHP.HeatCoilName, thisMSHP.HeatCoilIndex, LocalError); - } else { - HeatingCoils::GetCoilIndex(state, thisMSHP.HeatCoilName, thisMSHP.HeatCoilIndex, LocalError); - } + HeatingCoils::GetCoilIndex(state, thisMSHP.HeatCoilName, thisMSHP.HeatCoilIndex, LocalError); if (LocalError) { ShowSevereError(state, EnergyPlus::format("The index of {} is not found \"{}\"", cAlphaFields(11), Alphas(11))); ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); @@ -821,23 +898,8 @@ namespace HVACMultiSpeedHeatPump { ErrorsFound = true; LocalError = false; } - if (Util::SameString(Alphas(10), "Coil:Heating:Electric:MultiStage")) { - Node::SetUpCompSets(state, - state.dataHVACMultiSpdHP->CurrentModuleObject, - thisMSHP.Name, - "Coil:Heating:Electric:MultiStage", - thisMSHP.HeatCoilName, - "UNDEFINED", - "UNDEFINED"); - } else { - Node::SetUpCompSets(state, - state.dataHVACMultiSpdHP->CurrentModuleObject, - thisMSHP.Name, - "Coil:Heating:Gas:MultiStage", - thisMSHP.HeatCoilName, - "UNDEFINED", - "UNDEFINED"); - } + Node::SetUpCompSets( + state, state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name, Alphas(10), thisMSHP.HeatCoilName, "UNDEFINED", "UNDEFINED"); } else if (Util::SameString(Alphas(10), "Coil:Heating:Water")) { thisMSHP.HeatCoilType = HVAC::Coil_HeatingWater; ValidateComponent(state, Alphas(10), Alphas(11), IsNotOK, state.dataHVACMultiSpdHP->CurrentModuleObject); @@ -1030,93 +1092,26 @@ namespace HVACMultiSpeedHeatPump { // Get supplemental heating coil data thisMSHP.SuppHeatCoilName = Alphas(15); if (Util::SameString(Alphas(14), "Coil:Heating:Fuel")) { - thisMSHP.SuppHeatCoilType = HVAC::Coil_HeatingGasOrOtherFuel; - errFlag = false; - thisMSHP.SuppHeatCoilNum = HeatingCoils::GetHeatingCoilIndex(state, "Coil:Heating:Fuel", Alphas(15), errFlag); - if (thisMSHP.SuppHeatCoilNum <= 0 || errFlag) { - ShowContinueError( - state, EnergyPlus::format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("{} of type Coil:Heating:Fuel \"{}\" not found.", cAlphaFields(15), Alphas(15))); - ErrorsFound = true; - } - - // Get the Supplemental Heating Coil Node Numbers - LocalError = false; - SuppHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, Alphas(14), Alphas(15), LocalError); - if (LocalError) { - ShowSevereError(state, EnergyPlus::format("The inlet node number of {} is not found \"{}\"", cAlphaFields(15), Alphas(15))); - ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - LocalError = false; - } - SuppHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, Alphas(14), Alphas(15), LocalError); - if (LocalError) { - ShowSevereError(state, EnergyPlus::format("The outlet node number of {} is not found \"{}\"", cAlphaFields(15), Alphas(15))); - ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - LocalError = false; - } - - // Get supplemental heating coil capacity to see if it is autosize - thisMSHP.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, Alphas(14), Alphas(15), LocalError); - if (LocalError) { - ShowSevereError(state, EnergyPlus::format("The capacity {} is not found \"{}\"", cAlphaFields(15), Alphas(15))); - ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - LocalError = false; - } - Node::SetUpCompSets(state, - state.dataHVACMultiSpdHP->CurrentModuleObject, - thisMSHP.Name, - "Coil:Heating:Fuel", - thisMSHP.SuppHeatCoilName, - "UNDEFINED", - "UNDEFINED"); + readSuppHeatingCoilFuelOrElectric(state, + thisMSHP, + HVAC::Coil_HeatingGasOrOtherFuel, + "Coil:Heating:Fuel", + Alphas, + cAlphaFields, + ErrorsFound, + SuppHeatCoilInletNode, + SuppHeatCoilOutletNode); } if (Util::SameString(Alphas(14), "Coil:Heating:Electric")) { - thisMSHP.SuppHeatCoilType = HVAC::Coil_HeatingElectric; - errFlag = false; - thisMSHP.SuppHeatCoilNum = HeatingCoils::GetHeatingCoilIndex(state, "Coil:Heating:Electric", Alphas(15), errFlag); - if (thisMSHP.SuppHeatCoilNum <= 0 || errFlag) { - ShowContinueError( - state, EnergyPlus::format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("{} of type Coil:Heating:Electric \"{}\" not found.", cAlphaFields(15), Alphas(15))); - ErrorsFound = true; - } - - // Get the Supplemental Heating Coil Node Numbers - LocalError = false; - SuppHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, Alphas(14), Alphas(15), LocalError); - if (LocalError) { - ShowSevereError(state, EnergyPlus::format("The inlet node number of {} is not found \"{}\"", cAlphaFields(15), Alphas(15))); - ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - LocalError = false; - } - SuppHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, Alphas(14), Alphas(15), LocalError); - if (LocalError) { - ShowSevereError(state, EnergyPlus::format("The outlet node number of {} is not found \"{}\"", cAlphaFields(15), Alphas(15))); - ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - LocalError = false; - } - - // Get supplemental heating coil capacity to see if it is autosize - thisMSHP.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, Alphas(14), Alphas(15), LocalError); - if (LocalError) { - ShowSevereError(state, EnergyPlus::format("The capacity {} is not found \"{}\"", cAlphaFields(15), Alphas(15))); - ShowContinueError(state, EnergyPlus::format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - LocalError = false; - } - - Node::SetUpCompSets(state, - state.dataHVACMultiSpdHP->CurrentModuleObject, - thisMSHP.Name, - "Coil:Heating:Electric", - thisMSHP.SuppHeatCoilName, - "UNDEFINED", - "UNDEFINED"); + readSuppHeatingCoilFuelOrElectric(state, + thisMSHP, + HVAC::Coil_HeatingElectric, + "Coil:Heating:Electric", + Alphas, + cAlphaFields, + ErrorsFound, + SuppHeatCoilInletNode, + SuppHeatCoilOutletNode); } if (Util::SameString(Alphas(14), "Coil:Heating:Water")) { @@ -1410,40 +1405,16 @@ namespace HVACMultiSpeedHeatPump { thisMSHP.HeatingSpeedRatio = 1.0; for (i = 1; i <= thisMSHP.NumOfSpeedHeating; ++i) { thisMSHP.HeatVolumeFlowRate(i) = Numbers(10 + i); - if (thisMSHP.HeatCoilType == HVAC::CoilDX_MultiSpeedHeating) { - if (thisMSHP.HeatVolumeFlowRate(i) <= 0.0 && thisMSHP.HeatVolumeFlowRate(i) != DataSizing::AutoSize) { - ShowSevereError(state, - EnergyPlus::format("{}, \"{}\", {} must be greater than zero.", - state.dataHVACMultiSpdHP->CurrentModuleObject, - thisMSHP.Name, - cNumericFields(10 + i))); - ErrorsFound = true; - } - } - } - // Ensure flow rate at high speed should be greater or equal to the flow rate at low speed - for (i = 2; i <= thisMSHP.NumOfSpeedHeating; ++i) { - if (thisMSHP.HeatVolumeFlowRate(i) == DataSizing::AutoSize) { - continue; - } - Found = false; - for (j = i - 1; j >= 1; --j) { - if (thisMSHP.HeatVolumeFlowRate(i) != DataSizing::AutoSize) { - Found = true; - break; - } - } - if (Found) { - if (thisMSHP.HeatVolumeFlowRate(i) < thisMSHP.HeatVolumeFlowRate(j)) { - ShowSevereError( - state, - EnergyPlus::format( - "{}, \"{}\", {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name, cNumericFields(10 + i))); - ShowContinueError(state, EnergyPlus::format(" cannot be less than {}", cNumericFields(10 + j))); - ErrorsFound = true; - } - } } + bool alwaysValidatePositive = (thisMSHP.HeatCoilType == HVAC::CoilDX_MultiSpeedHeating); + validateSpeedFlowRates(state, + thisMSHP.Name, + thisMSHP.HeatVolumeFlowRate, + thisMSHP.NumOfSpeedHeating, + 10, + cNumericFields, + alwaysValidatePositive, + ErrorsFound); } if (state.dataGlobal->DoCoilDirectSolutions) { @@ -1459,38 +1430,9 @@ namespace HVACMultiSpeedHeatPump { thisMSHP.CoolingSpeedRatio = 1.0; for (i = 1; i <= thisMSHP.NumOfSpeedCooling; ++i) { thisMSHP.CoolVolumeFlowRate(i) = Numbers(14 + i); - if (thisMSHP.CoolVolumeFlowRate(i) <= 0.0 && thisMSHP.CoolVolumeFlowRate(i) != DataSizing::AutoSize) { - ShowSevereError(state, - EnergyPlus::format("{}, \"{}\", {} must be greater than zero.", - state.dataHVACMultiSpdHP->CurrentModuleObject, - thisMSHP.Name, - cNumericFields(14 + i))); - ErrorsFound = true; - } - } - // Ensure flow rate at high speed should be greater or equal to the flow rate at low speed - for (i = 2; i <= thisMSHP.NumOfSpeedCooling; ++i) { - if (thisMSHP.CoolVolumeFlowRate(i) == DataSizing::AutoSize) { - continue; - } - Found = false; - for (j = i - 1; j >= 1; --j) { - if (thisMSHP.CoolVolumeFlowRate(i) != DataSizing::AutoSize) { - Found = true; - break; - } - } - if (Found) { - if (thisMSHP.CoolVolumeFlowRate(i) < thisMSHP.CoolVolumeFlowRate(j)) { - ShowSevereError( - state, - EnergyPlus::format( - "{}, \"{}\", {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name, cNumericFields(14 + i))); - ShowContinueError(state, EnergyPlus::format(" cannot be less than {}", cNumericFields(14 + j))); - ErrorsFound = true; - } - } } + validateSpeedFlowRates( + state, thisMSHP.Name, thisMSHP.CoolVolumeFlowRate, thisMSHP.NumOfSpeedCooling, 14, cNumericFields, true, ErrorsFound); } // Check node integrity diff --git a/src/EnergyPlus/HVACUnitaryBypassVAV.cc b/src/EnergyPlus/HVACUnitaryBypassVAV.cc index a228ea3175c..b037edefd3a 100644 --- a/src/EnergyPlus/HVACUnitaryBypassVAV.cc +++ b/src/EnergyPlus/HVACUnitaryBypassVAV.cc @@ -2041,6 +2041,201 @@ namespace HVACUnitaryBypassVAV { } } + // Report SolveRoot iteration-exceeded or solver-failed errors for DX coil PLR calculations. + // Estimates PLR from inlet/outlet temperatures on solver failure (SolFla == -2). + // Checks WarmupFlag when checkWarmup is true (used by HX-Assisted and SingleSpeed coils). + static void reportDXCoilPLRSolverError(EnergyPlusData &state, + CBVAVData const &cBVAV, + int const SolFla, + Real64 &PartLoadFrac, + bool const checkWarmup, + int &iterExceededCounter, + int &iterExceededIndex, + std::string const &iterExceededMsg, + std::string const &iterExceededRecurMsg, + int &iterFailedCounter, + int &iterFailedIndex, + std::string const &iterFailedMsg, + std::string const &iterFailedRecurMsg) + { + if (checkWarmup && state.dataGlobal->WarmupFlag) { + return; + } + + if (SolFla == -1) { + if (iterExceededCounter < 1) { + ++iterExceededCounter; + ShowWarningError(state, iterExceededMsg); + ShowContinueError(state, EnergyPlus::format("Calculated part-load ratio = {:.3R}", PartLoadFrac)); + ShowContinueErrorTimeStamp(state, "The calculated part-load ratio will be used and the simulation continues. Occurrence info:"); + } else { + ShowRecurringWarningErrorAtEnd(state, iterExceededRecurMsg, iterExceededIndex, PartLoadFrac, PartLoadFrac); + } + } else if (SolFla == -2) { + PartLoadFrac = + max(0.0, + min(1.0, + (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - cBVAV.CoilTempSetPoint) / + (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - state.dataLoopNodes->Node(cBVAV.DXCoilOutletNode).Temp))); + if (iterFailedCounter < 1) { + ++iterFailedCounter; + ShowSevereError(state, iterFailedMsg); + ShowContinueError(state, EnergyPlus::format("Estimated part-load ratio = {:.3R}", PartLoadFrac)); + ShowContinueErrorTimeStamp(state, "The estimated part-load ratio will be used and the simulation continues. Occurrence info:"); + } else { + ShowRecurringWarningErrorAtEnd(state, iterFailedRecurMsg, iterFailedIndex, PartLoadFrac, PartLoadFrac); + } + } + } + + // Find the part-load ratio for a DX MultiMode coil to meet the coil temp setpoint. + // Handles full-load sim, inlet/outlet temp checks, SolveRoot, and error reporting. + static void findMultiModeDXCoilPLR(EnergyPlusData &state, + CBVAVData &cBVAV, + bool const FirstHVACIteration, + HVAC::CoilMode const DehumidMode, + Real64 &PartLoadFrac, + int &iterExceededCounter, + int &iterExceededIndex, + std::string const &iterExceededMsg, + std::string const &iterExceededRecurMsg, + int &iterFailedCounter, + int &iterFailedIndex, + std::string const &iterFailedMsg, + std::string const &iterFailedRecurMsg) + { + int constexpr MaxIte(500); + int SolFla; + + // Get full load result + DXCoils::SimDXCoilMultiMode(state, + cBVAV.DXCoolCoilName, + HVAC::CompressorOp::On, + FirstHVACIteration, + PartLoadFrac, + DehumidMode, + cBVAV.CoolCoilCompIndex, + HVAC::FanOp::Continuous); + if (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp <= cBVAV.CoilTempSetPoint) { + PartLoadFrac = 0.0; + DXCoils::SimDXCoilMultiMode(state, + cBVAV.DXCoolCoilName, + HVAC::CompressorOp::On, + FirstHVACIteration, + PartLoadFrac, + DehumidMode, + cBVAV.CoolCoilCompIndex, + HVAC::FanOp::Continuous); + } else if (state.dataLoopNodes->Node(cBVAV.DXCoilOutletNode).Temp > cBVAV.CoilTempSetPoint) { + PartLoadFrac = 1.0; + } else { + auto f = [&state, &cBVAV, DehumidMode](Real64 const PartLoadRatio) { + DXCoils::SimDXCoilMultiMode( + state, "", HVAC::CompressorOp::On, false, PartLoadRatio, DehumidMode, cBVAV.CoolCoilCompIndex, HVAC::FanOp::Continuous); + return cBVAV.CoilTempSetPoint - state.dataDXCoils->DXCoilOutletTemp(cBVAV.CoolCoilCompIndex); + }; + General::SolveRoot(state, HVAC::SmallTempDiff, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0); + if (SolFla == -1) { + if (iterExceededCounter < 1) { + ++iterExceededCounter; + ShowWarningError(state, iterExceededMsg); + ShowContinueErrorTimeStamp(state, EnergyPlus::format("Part-load ratio returned = {:.2R}", PartLoadFrac)); + ShowContinueErrorTimeStamp(state, "The calculated part-load ratio will be used and the simulation continues. Occurrence info:"); + } else { + ShowRecurringWarningErrorAtEnd(state, iterExceededRecurMsg, iterExceededIndex, PartLoadFrac, PartLoadFrac); + } + } else if (SolFla == -2) { + PartLoadFrac = + max(0.0, + min(1.0, + (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - cBVAV.CoilTempSetPoint) / + (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - state.dataLoopNodes->Node(cBVAV.DXCoilOutletNode).Temp))); + if (iterFailedCounter < 1) { + ++iterFailedCounter; + ShowSevereError(state, iterFailedMsg); + ShowContinueError(state, EnergyPlus::format("Estimated part-load ratio = {:.3R}", PartLoadFrac)); + ShowContinueErrorTimeStamp(state, "The estimated part-load ratio will be used and the simulation continues. Occurrence info:"); + } else { + ShowRecurringWarningErrorAtEnd(state, iterFailedRecurMsg, iterFailedIndex, PartLoadFrac, PartLoadFrac); + } + } + } + } + + // Simulate the cooling coil with compressor off (all coil types). + // When savePLR is true, also updates SaveCompressorPLR. + static void simulateCoolingCoilOff(EnergyPlusData &state, + CBVAVData &cBVAV, + bool const FirstHVACIteration, + Real64 const OnOffAirFlowRatio, + bool const HXUnitOn, + bool const savePLR) + { + switch (cBVAV.CoolCoilType) { + case HVAC::CoilType::DXCoolingHXAssisted: { + HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state, + cBVAV.DXCoolCoilName, + FirstHVACIteration, + HVAC::CompressorOp::Off, + 0.0, + cBVAV.CoolCoilCompIndex, + HVAC::FanOp::Continuous, + HXUnitOn); + if (savePLR) { + state.dataHVACUnitaryBypassVAV->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(cBVAV.DXCoolCoilIndexNum); + } + } break; + case HVAC::CoilType::DXCoolingSingleSpeed: { + DXCoils::SimDXCoil(state, + cBVAV.DXCoolCoilName, + HVAC::CompressorOp::Off, + FirstHVACIteration, + cBVAV.CoolCoilCompIndex, + HVAC::FanOp::Continuous, + 0.0, + OnOffAirFlowRatio); + if (savePLR) { + state.dataHVACUnitaryBypassVAV->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(cBVAV.DXCoolCoilIndexNum); + } + } break; + case HVAC::CoilType::DXCoolingTwoStageWHumControl: { + DXCoils::SimDXCoilMultiMode(state, + cBVAV.DXCoolCoilName, + HVAC::CompressorOp::Off, + FirstHVACIteration, + 0.0, + HVAC::CoilMode::Normal, + cBVAV.CoolCoilCompIndex, + HVAC::FanOp::Continuous); + if (savePLR) { + state.dataHVACUnitaryBypassVAV->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(cBVAV.DXCoolCoilIndexNum); + } + } break; + case HVAC::CoilType::CoolingAirToAirVariableSpeed: { + Real64 LocalPartLoadFrac = 0.0; + Real64 QZnReq = 0.0; + Real64 QLatReq = 0.0; + Real64 SpeedRatio = 0.0; + int SpeedNum = 1; + VariableSpeedCoils::SimVariableSpeedCoils(state, + cBVAV.DXCoolCoilName, + cBVAV.CoolCoilCompIndex, + HVAC::FanOp::Continuous, + HVAC::CompressorOp::Off, + LocalPartLoadFrac, + SpeedNum, + SpeedRatio, + QZnReq, + QLatReq); + if (savePLR) { + state.dataHVACUnitaryBypassVAV->SaveCompressorPLR = VariableSpeedCoils::getVarSpeedPartLoadRatio(state, cBVAV.CoolCoilCompIndex); + } + } break; + default: + break; + } + } + void CalcCBVAV(EnergyPlusData &state, int const CBVAVNum, // Unit index in fan coil array bool const FirstHVACIteration, // Flag for 1st HVAC iteration @@ -2158,51 +2353,23 @@ namespace HVACUnitaryBypassVAV { cBVAV.CoolCoilCompIndex, HVAC::FanOp::Continuous, HXUnitOn); - if (SolFla == -1 && !state.dataGlobal->WarmupFlag) { - if (cBVAV.HXDXIterationExceeded < 1) { - ++cBVAV.HXDXIterationExceeded; - ShowWarningError( - state, - EnergyPlus::format("Iteration limit exceeded calculating HX assisted DX unit part-load ratio, for unit = {}", - cBVAV.DXCoolCoilName)); - ShowContinueError(state, EnergyPlus::format("Calculated part-load ratio = {:.3R}", PartLoadFrac)); - ShowContinueErrorTimeStamp( - state, "The calculated part-load ratio will be used and the simulation continues. Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd( - state, - cBVAV.Name + ", Iteration limit exceeded for HX assisted DX unit part-load ratio error continues.", - cBVAV.HXDXIterationExceededIndex, - PartLoadFrac, - PartLoadFrac); - } - } else if (SolFla == -2 && !state.dataGlobal->WarmupFlag) { - PartLoadFrac = max(0.0, - min(1.0, - (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - cBVAV.CoilTempSetPoint) / - (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - - state.dataLoopNodes->Node(cBVAV.DXCoilOutletNode).Temp))); - if (cBVAV.HXDXIterationFailed < 1) { - ++cBVAV.HXDXIterationFailed; - ShowSevereError( - state, - EnergyPlus::format( - "HX assisted DX unit part-load ratio calculation failed: part-load ratio limits exceeded, for unit = {}", - cBVAV.DXCoolCoilName)); - ShowContinueErrorTimeStamp( - state, - EnergyPlus::format( - "An estimated part-load ratio of {:.3R}will be used and the simulation continues. Occurrence info:", - PartLoadFrac)); - } else { - ShowRecurringWarningErrorAtEnd(state, - cBVAV.Name + - ", Part-load ratio calculation failed for HX assisted DX unit error continues.", - cBVAV.HXDXIterationFailedIndex, - PartLoadFrac, - PartLoadFrac); - } - } + reportDXCoilPLRSolverError( + state, + cBVAV, + SolFla, + PartLoadFrac, + /*checkWarmup=*/true, + cBVAV.HXDXIterationExceeded, + cBVAV.HXDXIterationExceededIndex, + EnergyPlus::format("Iteration limit exceeded calculating HX assisted DX unit part-load ratio, for unit = {}", + cBVAV.DXCoolCoilName), + cBVAV.Name + ", Iteration limit exceeded for HX assisted DX unit part-load ratio error continues.", + cBVAV.HXDXIterationFailed, + cBVAV.HXDXIterationFailedIndex, + EnergyPlus::format( + "HX assisted DX unit part-load ratio calculation failed: part-load ratio limits exceeded, for unit = {}", + cBVAV.DXCoolCoilName), + cBVAV.Name + ", Part-load ratio calculation failed for HX assisted DX unit error continues."); } } break; case HVAC::CoilType::DXCoolingSingleSpeed: { @@ -2248,48 +2415,21 @@ namespace HVACUnitaryBypassVAV { HVAC::FanOp::Continuous, PartLoadFrac, OnOffAirFlowRatio); - if (SolFla == -1 && !state.dataGlobal->WarmupFlag) { - if (cBVAV.DXIterationExceeded < 1) { - ++cBVAV.DXIterationExceeded; - ShowWarningError(state, - EnergyPlus::format("Iteration limit exceeded calculating DX unit part-load ratio, for unit = {}", - cBVAV.DXCoolCoilName)); - ShowContinueError(state, EnergyPlus::format("Calculated part-load ratio = {:.3R}", PartLoadFrac)); - ShowContinueErrorTimeStamp( - state, "The calculated part-load ratio will be used and the simulation continues. Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd( - state, - cBVAV.Name + ", Iteration limit exceeded for DX unit part-load ratio calculation error continues.", - cBVAV.DXIterationExceededIndex, - PartLoadFrac, - PartLoadFrac); - } - } else if (SolFla == -2 && !state.dataGlobal->WarmupFlag) { - PartLoadFrac = max(0.0, - min(1.0, - (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - cBVAV.CoilTempSetPoint) / - (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - - state.dataLoopNodes->Node(cBVAV.DXCoilOutletNode).Temp))); - if (cBVAV.DXIterationFailed < 1) { - ++cBVAV.DXIterationFailed; - ShowSevereError( - state, - EnergyPlus::format("DX unit part-load ratio calculation failed: part-load ratio limits exceeded, for unit = {}", - cBVAV.DXCoolCoilName)); - ShowContinueErrorTimeStamp( - state, - EnergyPlus::format( - "An estimated part-load ratio of {:.3R}will be used and the simulation continues. Occurrence info:", - PartLoadFrac)); - } else { - ShowRecurringWarningErrorAtEnd(state, - cBVAV.Name + ", Part-load ratio calculation failed for DX unit error continues.", - cBVAV.DXIterationFailedIndex, - PartLoadFrac, - PartLoadFrac); - } - } + reportDXCoilPLRSolverError( + state, + cBVAV, + SolFla, + PartLoadFrac, + /*checkWarmup=*/true, + cBVAV.DXIterationExceeded, + cBVAV.DXIterationExceededIndex, + EnergyPlus::format("Iteration limit exceeded calculating DX unit part-load ratio, for unit = {}", cBVAV.DXCoolCoilName), + cBVAV.Name + ", Iteration limit exceeded for DX unit part-load ratio calculation error continues.", + cBVAV.DXIterationFailed, + cBVAV.DXIterationFailedIndex, + EnergyPlus::format("DX unit part-load ratio calculation failed: part-load ratio limits exceeded, for unit = {}", + cBVAV.DXCoolCoilName), + cBVAV.Name + ", Part-load ratio calculation failed for DX unit error continues."); } state.dataHVACUnitaryBypassVAV->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(cBVAV.DXCoolCoilIndexNum); } break; @@ -2630,85 +2770,22 @@ namespace HVACUnitaryBypassVAV { // still runs to meet the sensible load // Determine required part load for normal mode - - // Get full load result HVAC::CoilMode DehumidMode = HVAC::CoilMode::Normal; // Dehumidification mode (0=normal, 1=enhanced) cBVAV.DehumidificationMode = DehumidMode; - DXCoils::SimDXCoilMultiMode(state, - cBVAV.DXCoolCoilName, - HVAC::CompressorOp::On, - FirstHVACIteration, - PartLoadFrac, - DehumidMode, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous); - if (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp <= cBVAV.CoilTempSetPoint) { - PartLoadFrac = 0.0; - DXCoils::SimDXCoilMultiMode(state, - cBVAV.DXCoolCoilName, - HVAC::CompressorOp::On, - FirstHVACIteration, - PartLoadFrac, - DehumidMode, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous); - } else if (state.dataLoopNodes->Node(cBVAV.DXCoilOutletNode).Temp > cBVAV.CoilTempSetPoint) { - PartLoadFrac = 1.0; - } else { - auto f = [&state, CBVAVNum, DehumidMode](Real64 const PartLoadRatio) { - auto &thisCBVAV = state.dataHVACUnitaryBypassVAV->CBVAV(CBVAVNum); - DXCoils::SimDXCoilMultiMode(state, - "", - HVAC::CompressorOp::On, - false, - PartLoadRatio, - DehumidMode, - thisCBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous); - return thisCBVAV.CoilTempSetPoint - state.dataDXCoils->DXCoilOutletTemp(thisCBVAV.CoolCoilCompIndex); - }; - General::SolveRoot(state, HVAC::SmallTempDiff, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0); - if (SolFla == -1) { - if (cBVAV.MMDXIterationExceeded < 1) { - ++cBVAV.MMDXIterationExceeded; - ShowWarningError( - state, - EnergyPlus::format("Iteration limit exceeded calculating DX unit part-load ratio, for unit={}", cBVAV.Name)); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Part-load ratio returned = {:.2R}", PartLoadFrac)); - ShowContinueErrorTimeStamp( - state, "The calculated part-load ratio will be used and the simulation continues. Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd(state, - cBVAV.Name + - ", Iteration limit exceeded calculating DX unit part-load ratio error continues.", - cBVAV.MMDXIterationExceededIndex, - PartLoadFrac, - PartLoadFrac); - } - } else if (SolFla == -2) { - PartLoadFrac = max(0.0, - min(1.0, - (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - cBVAV.CoilTempSetPoint) / - (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - - state.dataLoopNodes->Node(cBVAV.DXCoilOutletNode).Temp))); - if (cBVAV.MMDXIterationFailed < 1) { - ++cBVAV.MMDXIterationFailed; - ShowSevereError( - state, - EnergyPlus::format("DX unit part-load ratio calculation failed: part-load ratio limits exceeded, for unit={}", - cBVAV.Name)); - ShowContinueError(state, EnergyPlus::format("Estimated part-load ratio = {:.3R}", PartLoadFrac)); - ShowContinueErrorTimeStamp( - state, "The estimated part-load ratio will be used and the simulation continues. Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd(state, - cBVAV.Name + ", Part-load ratio calculation failed for DX unit error continues.", - cBVAV.MMDXIterationFailedIndex, - PartLoadFrac, - PartLoadFrac); - } - } - } + findMultiModeDXCoilPLR( + state, + cBVAV, + FirstHVACIteration, + DehumidMode, + PartLoadFrac, + cBVAV.MMDXIterationExceeded, + cBVAV.MMDXIterationExceededIndex, + EnergyPlus::format("Iteration limit exceeded calculating DX unit part-load ratio, for unit={}", cBVAV.Name), + cBVAV.Name + ", Iteration limit exceeded calculating DX unit part-load ratio error continues.", + cBVAV.MMDXIterationFailed, + cBVAV.MMDXIterationFailedIndex, + EnergyPlus::format("DX unit part-load ratio calculation failed: part-load ratio limits exceeded, for unit={}", cBVAV.Name), + cBVAV.Name + ", Part-load ratio calculation failed for DX unit error continues."); // If humidity setpoint is not satisfied and humidity control type is Multimode, // then turn on enhanced dehumidification mode 1 @@ -2718,81 +2795,26 @@ namespace HVACUnitaryBypassVAV { (cBVAV.DehumidControlType == DehumidControl::Multimode) && state.dataLoopNodes->Node(OutletNode).HumRatMax > 0.0) { // Determine required part load for enhanced dehumidification mode 1 - - // Get full load result PartLoadFrac = 1.0; DehumidMode = HVAC::CoilMode::Enhanced; cBVAV.DehumidificationMode = DehumidMode; - DXCoils::SimDXCoilMultiMode(state, - cBVAV.DXCoolCoilName, - HVAC::CompressorOp::On, - FirstHVACIteration, - PartLoadFrac, - DehumidMode, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous); - if (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp <= cBVAV.CoilTempSetPoint) { - PartLoadFrac = 0.0; - } else if (state.dataLoopNodes->Node(cBVAV.DXCoilOutletNode).Temp > cBVAV.CoilTempSetPoint) { - PartLoadFrac = 1.0; - } else { - auto f = [&state, CBVAVNum, DehumidMode](Real64 const PartLoadRatio) { - auto &thisCBVAV = state.dataHVACUnitaryBypassVAV->CBVAV(CBVAVNum); - DXCoils::SimDXCoilMultiMode(state, - "", - HVAC::CompressorOp::On, - false, - PartLoadRatio, - DehumidMode, - thisCBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous); - return thisCBVAV.CoilTempSetPoint - state.dataDXCoils->DXCoilOutletTemp(thisCBVAV.CoolCoilCompIndex); - }; - General::SolveRoot(state, HVAC::SmallTempDiff, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0); - if (SolFla == -1) { - if (cBVAV.DMDXIterationExceeded < 1) { - ++cBVAV.DMDXIterationExceeded; - ShowWarningError( - state, - EnergyPlus::format( - "Iteration limit exceeded calculating DX unit dehumidifying part-load ratio, for unit = {}", cBVAV.Name)); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Part-load ratio returned={:.2R}", PartLoadFrac)); - ShowContinueErrorTimeStamp( - state, "The calculated part-load ratio will be used and the simulation continues. Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd( - state, - cBVAV.Name + ", Iteration limit exceeded calculating DX unit dehumidifying part-load ratio error continues.", - cBVAV.DMDXIterationExceededIndex, - PartLoadFrac, - PartLoadFrac); - } - } else if (SolFla == -2) { - PartLoadFrac = max(0.0, - min(1.0, - (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - cBVAV.CoilTempSetPoint) / - (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - - state.dataLoopNodes->Node(cBVAV.DXCoilOutletNode).Temp))); - if (cBVAV.DMDXIterationFailed < 1) { - ++cBVAV.DMDXIterationFailed; - ShowSevereError( - state, - EnergyPlus::format("DX unit dehumidifying part-load ratio calculation failed: part-load ratio limits " - "exceeded, for unit = {}", - cBVAV.Name)); - ShowContinueError(state, EnergyPlus::format("Estimated part-load ratio = {:.3R}", PartLoadFrac)); - ShowContinueErrorTimeStamp( - state, "The estimated part-load ratio will be used and the simulation continues. Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd( - state, - cBVAV.Name + ", Dehumidifying part-load ratio calculation failed for DX unit error continues.", - cBVAV.DMDXIterationFailedIndex, - PartLoadFrac, - PartLoadFrac); - } - } - } + findMultiModeDXCoilPLR( + state, + cBVAV, + FirstHVACIteration, + DehumidMode, + PartLoadFrac, + cBVAV.DMDXIterationExceeded, + cBVAV.DMDXIterationExceededIndex, + EnergyPlus::format("Iteration limit exceeded calculating DX unit dehumidifying part-load ratio, for unit = {}", + cBVAV.Name), + cBVAV.Name + ", Iteration limit exceeded calculating DX unit dehumidifying part-load ratio error continues.", + cBVAV.DMDXIterationFailed, + cBVAV.DMDXIterationFailedIndex, + EnergyPlus::format( + "DX unit dehumidifying part-load ratio calculation failed: part-load ratio limits exceeded, for unit = {}", + cBVAV.Name), + cBVAV.Name + ", Dehumidifying part-load ratio calculation failed for DX unit error continues."); } // End if humidity ratio setpoint not met - multimode humidity control // If humidity setpoint is not satisfied and humidity control type is CoolReheat, @@ -2814,81 +2836,24 @@ namespace HVACUnitaryBypassVAV { cBVAV.CoilTempSetPoint = min(cBVAV.CoilTempSetPoint, (DesiredDewPoint + ApproachTemp)); // Determine required part load for cool reheat at adjusted DesiredOutletTemp - - // Get full load result PartLoadFrac = 1.0; DehumidMode = HVAC::CoilMode::Normal; cBVAV.DehumidificationMode = DehumidMode; - DXCoils::SimDXCoilMultiMode(state, - cBVAV.DXCoolCoilName, - HVAC::CompressorOp::On, - FirstHVACIteration, - PartLoadFrac, - DehumidMode, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous); - if (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp <= cBVAV.CoilTempSetPoint) { - PartLoadFrac = 0.0; - } else if (state.dataLoopNodes->Node(cBVAV.DXCoilOutletNode).Temp > cBVAV.CoilTempSetPoint) { - PartLoadFrac = 1.0; - } else { - auto f = [&state, CBVAVNum, DehumidMode](Real64 const PartLoadRatio) { - auto &thisCBVAV = state.dataHVACUnitaryBypassVAV->CBVAV(CBVAVNum); - DXCoils::SimDXCoilMultiMode(state, - "", - HVAC::CompressorOp::On, - false, - PartLoadRatio, - DehumidMode, - thisCBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous); - return thisCBVAV.CoilTempSetPoint - state.dataDXCoils->DXCoilOutletTemp(thisCBVAV.CoolCoilCompIndex); - }; - General::SolveRoot(state, HVAC::SmallTempDiff, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0); - if (SolFla == -1) { - if (cBVAV.CRDXIterationExceeded < 1) { - ++cBVAV.CRDXIterationExceeded; - ShowWarningError( - state, - EnergyPlus::format("Iteration limit exceeded calculating DX unit cool reheat part-load ratio, for unit = {}", - cBVAV.Name)); - ShowContinueErrorTimeStamp(state, EnergyPlus::format("Part-load ratio returned = {:.2R}", PartLoadFrac)); - ShowContinueErrorTimeStamp( - state, "The calculated part-load ratio will be used and the simulation continues. Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd( - state, - cBVAV.Name + ", Iteration limit exceeded calculating cool reheat part-load ratio DX unit error continues.", - cBVAV.CRDXIterationExceededIndex, - PartLoadFrac, - PartLoadFrac); - } - } else if (SolFla == -2) { - PartLoadFrac = max(0.0, - min(1.0, - (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - cBVAV.CoilTempSetPoint) / - (state.dataLoopNodes->Node(cBVAV.DXCoilInletNode).Temp - - state.dataLoopNodes->Node(cBVAV.DXCoilOutletNode).Temp))); - if (cBVAV.CRDXIterationFailed < 1) { - ++cBVAV.CRDXIterationFailed; - ShowSevereError( - state, - EnergyPlus::format( - "DX unit cool reheat part-load ratio calculation failed: part-load ratio limits exceeded, for unit = {}", - cBVAV.Name)); - ShowContinueError(state, EnergyPlus::format("Estimated part-load ratio = {:.3R}", PartLoadFrac)); - ShowContinueErrorTimeStamp( - state, "The estimated part-load ratio will be used and the simulation continues. Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd( - state, - cBVAV.Name + ", Dehumidifying part-load ratio calculation failed for DX unit error continues.", - cBVAV.DMDXIterationFailedIndex, - PartLoadFrac, - PartLoadFrac); - } - } - } + findMultiModeDXCoilPLR( + state, + cBVAV, + FirstHVACIteration, + DehumidMode, + PartLoadFrac, + cBVAV.CRDXIterationExceeded, + cBVAV.CRDXIterationExceededIndex, + EnergyPlus::format("Iteration limit exceeded calculating DX unit cool reheat part-load ratio, for unit = {}", cBVAV.Name), + cBVAV.Name + ", Iteration limit exceeded calculating cool reheat part-load ratio DX unit error continues.", + cBVAV.CRDXIterationFailed, + cBVAV.CRDXIterationFailedIndex, + EnergyPlus::format( + "DX unit cool reheat part-load ratio calculation failed: part-load ratio limits exceeded, for unit = {}", cBVAV.Name), + cBVAV.Name + ", Dehumidifying part-load ratio calculation failed for DX unit error continues."); } // End if humidity ratio setpoint not met - CoolReheat humidity control if (PartLoadFrac > 1.0) { @@ -2906,106 +2871,12 @@ namespace HVACUnitaryBypassVAV { } } else { // IF(OutdoorDryBulbTemp .GE. cBVAV%MinOATCompressor)THEN // Simulate DX cooling coil with compressor off - if (cBVAV.CoolCoilType == HVAC::CoilType::DXCoolingHXAssisted) { - HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state, - cBVAV.DXCoolCoilName, - FirstHVACIteration, - HVAC::CompressorOp::Off, - 0.0, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous, - HXUnitOn); - state.dataHVACUnitaryBypassVAV->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(cBVAV.DXCoolCoilIndexNum); - } else if (cBVAV.CoolCoilType == HVAC::CoilType::DXCoolingSingleSpeed) { - DXCoils::SimDXCoil(state, - cBVAV.DXCoolCoilName, - HVAC::CompressorOp::Off, - FirstHVACIteration, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous, - 0.0, - OnOffAirFlowRatio); - state.dataHVACUnitaryBypassVAV->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(cBVAV.DXCoolCoilIndexNum); - } else if (cBVAV.CoolCoilType == HVAC::CoilType::DXCoolingTwoStageWHumControl) { - DXCoils::SimDXCoilMultiMode(state, - cBVAV.DXCoolCoilName, - HVAC::CompressorOp::Off, - FirstHVACIteration, - 0.0, - HVAC::CoilMode::Normal, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous); - state.dataHVACUnitaryBypassVAV->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(cBVAV.DXCoolCoilIndexNum); - } else if (cBVAV.CoolCoilType == HVAC::CoilType::CoolingAirToAirVariableSpeed) { - // Real64 PartLoadFrac(0.0); - Real64 LocalPartLoadFrac = 0.0; - Real64 QZnReq = 0.0; // Zone load (W), input to variable-speed DX coil - Real64 QLatReq = 0.0; // Zone latent load, input to variable-speed DX coil - Real64 SpeedRatio = 0.0; - int SpeedNum = 1; - // Get no load result - VariableSpeedCoils::SimVariableSpeedCoils(state, - cBVAV.DXCoolCoilName, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous, - HVAC::CompressorOp::Off, - LocalPartLoadFrac, - SpeedNum, - SpeedRatio, - QZnReq, - QLatReq); - state.dataHVACUnitaryBypassVAV->SaveCompressorPLR = VariableSpeedCoils::getVarSpeedPartLoadRatio(state, cBVAV.CoolCoilCompIndex); - } + simulateCoolingCoilOff(state, cBVAV, FirstHVACIteration, OnOffAirFlowRatio, HXUnitOn, /*savePLR=*/true); } // Simulate cooling coil with compressor off if zone requires heating } else { // HeatCoolMode == HeatingMode and no cooling is required, set PLR to 0 - if (cBVAV.CoolCoilType == HVAC::CoilType::DXCoolingHXAssisted) { - HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state, - cBVAV.DXCoolCoilName, - FirstHVACIteration, - HVAC::CompressorOp::Off, - 0.0, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous, - HXUnitOn); - } else if (cBVAV.CoolCoilType == HVAC::CoilType::DXCoolingSingleSpeed) { - DXCoils::SimDXCoil(state, - cBVAV.DXCoolCoilName, - HVAC::CompressorOp::Off, - FirstHVACIteration, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous, - 0.0, - OnOffAirFlowRatio); - } else if (cBVAV.CoolCoilType == HVAC::CoilType::CoolingAirToAirVariableSpeed) { - Real64 QZnReq = 0.0; // Zone load (W), input to variable-speed DX coil - Real64 QLatReq = 0.0; // Zone latent load, input to variable-speed DX coil - Real64 LocalPartLoadFrac = 0.0; - Real64 SpeedRatio = 0.0; - int SpeedNum = 1; - // run model with no load - VariableSpeedCoils::SimVariableSpeedCoils(state, - cBVAV.DXCoolCoilName, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous, - HVAC::CompressorOp::Off, - LocalPartLoadFrac, - SpeedNum, - SpeedRatio, - QZnReq, - QLatReq); - - } else if (cBVAV.CoolCoilType == HVAC::CoilType::DXCoolingTwoStageWHumControl) { - DXCoils::SimDXCoilMultiMode(state, - cBVAV.DXCoolCoilName, - HVAC::CompressorOp::Off, - FirstHVACIteration, - 0.0, - HVAC::CoilMode::Normal, - cBVAV.CoolCoilCompIndex, - HVAC::FanOp::Continuous); - } + simulateCoolingCoilOff(state, cBVAV, FirstHVACIteration, OnOffAirFlowRatio, HXUnitOn, /*savePLR=*/false); } // Simulate the heating coil based on coil type diff --git a/src/EnergyPlus/HVACVariableRefrigerantFlow.cc b/src/EnergyPlus/HVACVariableRefrigerantFlow.cc index d71cf9345b3..86ef420ae3b 100644 --- a/src/EnergyPlus/HVACVariableRefrigerantFlow.cc +++ b/src/EnergyPlus/HVACVariableRefrigerantFlow.cc @@ -1406,6 +1406,218 @@ void GetVRFInput(EnergyPlusData &state) } } +// Helper: validate an EIR-f-PLR curve's X range against MinPLR and expected max of 1.0. +static void checkEIRFPLRCurveRange(EnergyPlusData &state, + bool &ErrorsFound, + int curveIndex, + Real64 MinPLR, + std::string_view routineName, + std::string_view objectType, + std::string_view objectName, + std::string_view fieldName, + std::string_view curveName) +{ + Real64 minX = 0.0; + Real64 maxX = 0.0; + Curve::GetCurveMinMaxValues(state, curveIndex, minX, maxX); + if (minX > MinPLR) { + ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", routineName, objectType, objectName)); + ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", fieldName, curveName)); + ShowContinueError( + state, EnergyPlus::format("...Curve minimum value of X = {:.3T} must be <= Minimum Heat Pump Part-Load Ratio = {:.3T}.", minX, MinPLR)); + ErrorsFound = true; + } + if (maxX < 1.0) { + ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", suspicious", routineName, objectType, objectName)); + ShowContinueError(state, EnergyPlus::format("...{} = {} has unexpected value.", fieldName, curveName)); + ShowContinueError( + state, EnergyPlus::format("...Curve maximum value of X = {:.3T} should be 1 and will result in lower energy use than expected.", maxX)); + } +} + +// Helper: validate a PLF curve's output range [0.7, 1.0], capping if out of bounds. +static void checkAndCapPLFCurve(EnergyPlusData &state, + bool &ErrorsFound, + int curveIndex, + std::string_view routineName, + std::string_view objectType, + std::string_view objectName, + std::string_view fieldName, + std::string_view curveName) +{ + using Curve::CurveValue; + Real64 MinCurveVal = 999.0; + Real64 MaxCurveVal = -999.0; + Real64 MinCurvePLR = 0.0; + Real64 MaxCurvePLR = 1.0; + for (int i = 0; i <= 100; ++i) { + const Real64 CurveInput = i / 100.0; + Real64 CurveVal = CurveValue(state, curveIndex, CurveInput); + if (CurveVal < MinCurveVal) { + MinCurveVal = CurveVal; + MinCurvePLR = CurveInput; + } + if (CurveVal > MaxCurveVal) { + MaxCurveVal = CurveVal; + MaxCurvePLR = CurveInput; + } + } + if (MinCurveVal < 0.7) { + ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", routineName, objectType, objectName)); + ShowContinueError(state, EnergyPlus::format("...{}=\"{}\" has out of range values.", fieldName, curveName)); + ShowContinueError(state, + EnergyPlus::format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", MinCurvePLR, MinCurveVal)); + ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues."); + Curve::SetCurveOutputMinValue(state, curveIndex, ErrorsFound, 0.7); + } + if (MaxCurveVal > 1.0) { + ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", routineName, objectType, objectName)); + ShowContinueError(state, EnergyPlus::format("...{}=\"{}\" has out of range values.", fieldName, curveName)); + ShowContinueError(state, + EnergyPlus::format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", MaxCurvePLR, MaxCurveVal)); + ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues."); + Curve::SetCurveOutputMaxValue(state, curveIndex, ErrorsFound, 1.0); + } +} + +// Helper: look up a required quadratic curve and extract its 3 coefficients. +// Returns true on success, sets ErrorsFound on failure. +static bool getRequiredQuadraticCurveCoeffs(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view routineName, + std::string_view objectType, + std::string_view objectName, + std::string const &curveName, + std::string_view fieldName, + bool fieldIsBlank, + Real64 &C1, + Real64 &C2, + Real64 &C3) +{ + int idx = Curve::GetCurveIndex(state, curveName); + if (idx == 0) { + if (fieldIsBlank) { + ShowSevereError(state, std::string{routineName} + std::string{objectType} + "=\"" + std::string{objectName} + "\", missing"); + ShowContinueError(state, "...required " + std::string{fieldName} + " is blank."); + } else { + ShowSevereError(state, std::string{routineName} + std::string{objectType} + "=\"" + std::string{objectName} + "\", invalid"); + ShowContinueError(state, "...not found " + std::string{fieldName} + "=\"" + curveName + "\"."); + } + ErrorsFound = true; + return false; + } + if (state.dataCurveManager->curves(idx)->curveType == Curve::CurveType::Quadratic) { + C1 = state.dataCurveManager->curves(idx)->coeff[0]; + C2 = state.dataCurveManager->curves(idx)->coeff[1]; + C3 = state.dataCurveManager->curves(idx)->coeff[2]; + return true; + } + ShowSevereError(state, std::string{routineName} + std::string{objectType} + "=\"" + std::string{objectName} + "\", invalid"); + ShowContinueError(state, + EnergyPlus::format("...illegal {} type for this object = {}", + fieldName, + Curve::objectNames[static_cast(state.dataCurveManager->curves(idx)->curveType)])); + ShowContinueError(state, "... Curve type must be Quadratic."); + ErrorsFound = true; + return false; +} + +// Helper: look up a curve by name and validate its dimensionality. +// Returns the curve index (0 when the name is blank / not found). +static int getAndCheckCurve(EnergyPlusData &state, + bool &ErrorsFound, + std::string const &curveName, + std::vector const &validDims, + std::string_view routineName, + std::string_view objectType, + std::string_view objectName, + std::string_view fieldName) +{ + int idx = Curve::GetCurveIndex(state, curveName); + if (idx > 0) { + ErrorsFound |= Curve::CheckCurveDims(state, idx, validDims, routineName, objectType, objectName, fieldName); + } + return idx; +} + +// Helper: report "terminal unit not connected to condenser" error +static void showTUNotConnectedError(EnergyPlusData &state, + bool &ErrorsFound, + std::string const &objectType, + std::string const &tuName, + std::string const &coilType, + std::string const &coilName) +{ + ShowSevereError(state, objectType + " \"" + tuName + "\""); + ShowContinueError(state, "... when checking " + coilType + " \"" + coilName + "\""); + ShowContinueError(state, "... terminal unit not connected to condenser."); + ShowContinueError(state, "... check that terminal unit is specified in a terminal unit list object."); + ShowContinueError(state, + "... also check that the terminal unit list name is specified in an " + "AirConditioner:VariableRefrigerantFlow object."); + ErrorsFound = true; +} + +// Helper: set VRF condenser data on a cooling DX coil (cooling-mode parameters) +static void setVRFCoolingCoilData(EnergyPlusData &state, int coilIndex, bool &ErrorsFound, VRFCondenserEquipment const &vrfCond) +{ + using DXCoils::SetDXCoolingCoilData; + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, vrfCond.CondenserType); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, vrfCond.CondenserNodeNum); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, vrfCond.MaxOATCCHeater); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, vrfCond.MinOATCooling); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, vrfCond.MaxOATCooling); +} + +// Helper: set VRF condenser data on a heating DX coil (heating-mode + defrost parameters) +static void setVRFHeatingCoilData(EnergyPlusData &state, int coilIndex, bool &ErrorsFound, VRFCondenserEquipment const &vrfCond) +{ + using DXCoils::SetDXCoolingCoilData; + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, vrfCond.CondenserType); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, vrfCond.CondenserNodeNum); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, vrfCond.MaxOATCCHeater); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, _, vrfCond.MinOATHeating); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, _, _, vrfCond.MaxOATHeating); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, _, _, _, vrfCond.HeatingPerformanceOATType); + // Set defrost controls in child object to trip child object defrost calculations + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, _, _, _, _, vrfCond.DefrostStrategy); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, _, _, _, _, _, vrfCond.DefrostControl); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, _, _, _, _, _, _, vrfCond.DefrostEIRPtr); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, _, _, _, _, _, _, _, vrfCond.DefrostFraction); + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, _, _, _, _, _, _, _, _, _, vrfCond.MaxOATDefrost); + // If defrost is disabled in the VRF condenser, it must be disabled in the DX coil + // Defrost primarily handled in parent object, set defrost capacity to 1 to avoid autosizing. + // Defrost capacity is used for nothing more than setting defrost power/consumption report + // variables which are not reported. The coil's defrost algorithm IS used to derate the coil + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, _, _, _, _, _, _, _, _, 1.0); // DefrostCapacity=1.0 +} + +// Helper: set heating-to-cooling sizing ratio on a heating DX coil +static void setVRFHeatSizeRatio(EnergyPlusData &state, int coilIndex, bool &ErrorsFound, Real64 tuRatio, Real64 vrfRatio) +{ + using DXCoils::SetDXCoolingCoilData; + // Terminal unit heating to cooling sizing ratio has precedence over VRF system sizing ratio + if (tuRatio > 1.0) { + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, tuRatio); + } else if (vrfRatio > 1.0) { + SetDXCoolingCoilData(state, coilIndex, ErrorsFound, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, vrfRatio); + } +} + +// Helper: set FluidTCtrl-specific DXCoil member data (VRF pointers, fan, flow rate) +static void setFluidTCtrlCoilMembers(EnergyPlusData &state, int coilIndex, int vrfTUNum, int vrfSysNum, int fanIndex) +{ + auto &dxCoil = state.dataDXCoils->DXCoil(coilIndex); + dxCoil.VRFIUPtr = vrfTUNum; + dxCoil.VRFOUPtr = vrfSysNum; + dxCoil.SupplyFanIndex = fanIndex; + if (fanIndex > 0) { + dxCoil.RatedAirVolFlowRate(1) = state.dataFans->fans(fanIndex)->maxAirFlowRate; + } else { + dxCoil.RatedAirVolFlowRate(1) = DataSizing::AutoSize; + } +} + void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) { @@ -1608,27 +1820,6 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) } } - auto checkCurveMinMaxOutput = [&state](int CurveIndex) -> std::array { - Real64 MinCurveVal = 999.0; - Real64 MaxCurveVal = -999.0; - Real64 MinCurvePLR = 0.0; - Real64 MaxCurvePLR = 1.0; - - for (int i = 0; i <= 100; ++i) { // 0 to 1.0 with 0.01 increment - const Real64 CurveInput = i / 100.0; - Real64 CurveVal = CurveValue(state, CurveIndex, CurveInput); - if (CurveVal < MinCurveVal) { - MinCurveVal = CurveVal; - MinCurvePLR = CurveInput; - } - if (CurveVal > MaxCurveVal) { - MaxCurveVal = CurveVal; - MaxCurvePLR = CurveInput; - } - } - return {MinCurvePLR, MinCurveVal, MaxCurvePLR, MaxCurveVal}; - }; - // read all VRF condenser objects: Algorithm Type 1_system curve based model cCurrentModuleObject = "AirConditioner:VariableRefrigerantFlow"; for (int VRFNum = 1; VRFNum <= state.dataHVACVarRefFlow->NumVRFCond_SysCurve; ++VRFNum) { @@ -1666,157 +1857,41 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) thisVrfSys.MinOATCooling = rNumericArgs(3); thisVrfSys.MaxOATCooling = rNumericArgs(4); - thisVrfSys.CoolCapFT = GetCurveIndex(state, cAlphaArgs(3)); - if (thisVrfSys.CoolCapFT > 0) { - // Verify Curve Object, only legal type is biquadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.CoolCapFT, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(3)); // Field Name - - if (!ErrorsFound) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + cCurrentModuleObject, - thisVrfSys.Name, - thisVrfSys.CoolCapFT, - cAlphaFieldNames(3), - cAlphaArgs(3), - RatedInletWetBulbTemp, - RatedOutdoorAirTemp); - } - } - - thisVrfSys.CoolBoundaryCurvePtr = GetCurveIndex(state, cAlphaArgs(4)); - if (thisVrfSys.CoolBoundaryCurvePtr > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.CoolBoundaryCurvePtr, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(4)); // Field Name - } - - thisVrfSys.CoolCapFTHi = GetCurveIndex(state, cAlphaArgs(5)); - if (thisVrfSys.CoolCapFTHi > 0) { - // Verify Curve Object, only legal type is biquadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.CoolCapFTHi, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(5)); // Field Name - } - - thisVrfSys.CoolEIRFT = GetCurveIndex(state, cAlphaArgs(6)); - if (thisVrfSys.CoolEIRFT > 0) { - // Verify Curve Object, only legal type is biquadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.CoolEIRFT, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(6)); // Field Name - } - - thisVrfSys.EIRCoolBoundaryCurvePtr = GetCurveIndex(state, cAlphaArgs(7)); - if (thisVrfSys.EIRCoolBoundaryCurvePtr > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.EIRCoolBoundaryCurvePtr, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(7)); // Field Name - } - - thisVrfSys.CoolEIRFTHi = GetCurveIndex(state, cAlphaArgs(8)); - if (thisVrfSys.CoolEIRFTHi > 0) { - // Verify Curve Object, only legal type is biquadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.CoolEIRFTHi, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(8)); // Field Name - } - - thisVrfSys.CoolEIRFPLR1 = GetCurveIndex(state, cAlphaArgs(9)); - if (thisVrfSys.CoolEIRFPLR1 > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.CoolEIRFPLR1, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(9)); // Field Name - } - - thisVrfSys.CoolEIRFPLR2 = GetCurveIndex(state, cAlphaArgs(10)); - if (thisVrfSys.CoolEIRFPLR2 > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.CoolEIRFPLR2, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(10)); // Field Name - } - - thisVrfSys.CoolCombRatioPTR = GetCurveIndex(state, cAlphaArgs(11)); - if (thisVrfSys.CoolCombRatioPTR > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.CoolCombRatioPTR, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(11)); // Field Name - } - - thisVrfSys.CoolPLFFPLR = GetCurveIndex(state, cAlphaArgs(12)); - if (thisVrfSys.CoolPLFFPLR > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.CoolPLFFPLR, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(12)); // Field Name - if (!ErrorsFound) { - // Test PLF curve minimum and maximum. Cap if less than 0.7 or greater than 1.0. - auto [MinCurvePLR, MinCurveVal, MaxCurvePLR, MaxCurveVal] = checkCurveMinMaxOutput(thisVrfSys.CoolPLFFPLR); - - if (MinCurveVal < 0.7) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisVrfSys.Name)); - ShowContinueError(state, EnergyPlus::format("...{}=\"{}\" has out of range values.", cAlphaFieldNames(12), cAlphaArgs(12))); - ShowContinueError( - state, EnergyPlus::format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", MinCurvePLR, MinCurveVal)); - ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues."); - Curve::SetCurveOutputMinValue(state, thisVrfSys.CoolPLFFPLR, ErrorsFound, 0.7); - } - - if (MaxCurveVal > 1.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisVrfSys.Name)); - ShowContinueError(state, EnergyPlus::format("...{}=\"{}\" has out of range values.", cAlphaFieldNames(12), cAlphaArgs(12))); - ShowContinueError( - state, EnergyPlus::format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", MaxCurvePLR, MaxCurveVal)); - ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues."); - Curve::SetCurveOutputMaxValue(state, thisVrfSys.CoolPLFFPLR, ErrorsFound, 1.0); - } - } + thisVrfSys.CoolCapFT = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(3), {2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(3)); + if (thisVrfSys.CoolCapFT > 0 && !ErrorsFound) { + checkCurveIsNormalizedToOne(state, + std::string{RoutineName} + cCurrentModuleObject, + thisVrfSys.Name, + thisVrfSys.CoolCapFT, + cAlphaFieldNames(3), + cAlphaArgs(3), + RatedInletWetBulbTemp, + RatedOutdoorAirTemp); + } + + thisVrfSys.CoolBoundaryCurvePtr = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(4), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(4)); + thisVrfSys.CoolCapFTHi = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(5), {2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(5)); + thisVrfSys.CoolEIRFT = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(6), {2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(6)); + thisVrfSys.EIRCoolBoundaryCurvePtr = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(7), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(7)); + thisVrfSys.CoolEIRFTHi = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(8), {2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(8)); + thisVrfSys.CoolEIRFPLR1 = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(9), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(9)); + thisVrfSys.CoolEIRFPLR2 = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(10), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(10)); + thisVrfSys.CoolCombRatioPTR = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(11), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(11)); + + thisVrfSys.CoolPLFFPLR = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(12), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(12)); + if (thisVrfSys.CoolPLFFPLR > 0 && !ErrorsFound) { + checkAndCapPLFCurve( + state, ErrorsFound, thisVrfSys.CoolPLFFPLR, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(12), cAlphaArgs(12)); } thisVrfSys.HeatingCapacity = rNumericArgs(5); @@ -1837,100 +1912,41 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) ErrorsFound = true; } - thisVrfSys.HeatCapFT = GetCurveIndex(state, cAlphaArgs(13)); - if (thisVrfSys.HeatCapFT > 0) { - // Verify Curve Object, only legal type is biquadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HeatCapFT, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(13)); // Field Name - - if (!ErrorsFound) { - if (Util::SameString(cAlphaArgs(19), "WETBULBTEMPERATURE")) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + cCurrentModuleObject, - thisVrfSys.Name, - thisVrfSys.HeatCapFT, - cAlphaFieldNames(13), - cAlphaArgs(13), - RatedInletAirTempHeat, - RatedOutdoorWetBulbTempHeat); - } else if (Util::SameString(cAlphaArgs(19), "DRYBULBTEMPERATURE")) { - checkCurveIsNormalizedToOne(state, - std::string{RoutineName} + cCurrentModuleObject, - thisVrfSys.Name, - thisVrfSys.HeatCapFT, - cAlphaFieldNames(13), - cAlphaArgs(13), - RatedInletAirTempHeat, - RatedOutdoorAirTempHeat); - } - } - } - - thisVrfSys.HeatBoundaryCurvePtr = GetCurveIndex(state, cAlphaArgs(14)); - if (thisVrfSys.HeatBoundaryCurvePtr > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HeatBoundaryCurvePtr, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(14)); // Field Name - } - - thisVrfSys.HeatCapFTHi = GetCurveIndex(state, cAlphaArgs(15)); - if (thisVrfSys.HeatCapFTHi > 0) { - // Verify Curve Object, only legal type is biquadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HeatCapFTHi, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(15)); // Field Name - } - - thisVrfSys.HeatEIRFT = GetCurveIndex(state, cAlphaArgs(16)); - if (thisVrfSys.HeatEIRFT > 0) { - // Verify Curve Object, only legal type is biquadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HeatEIRFT, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(16)); // Field Name - } - - thisVrfSys.EIRHeatBoundaryCurvePtr = GetCurveIndex(state, cAlphaArgs(17)); - if (thisVrfSys.EIRHeatBoundaryCurvePtr > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.EIRHeatBoundaryCurvePtr, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(17)); // Field Name - } - - thisVrfSys.HeatEIRFTHi = GetCurveIndex(state, cAlphaArgs(18)); - if (thisVrfSys.HeatEIRFTHi > 0) { - // Verify Curve Object, only legal type is biquadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HeatEIRFTHi, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(18)); // Field Name + thisVrfSys.HeatCapFT = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(13), {2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(13)); + if (thisVrfSys.HeatCapFT > 0 && !ErrorsFound) { + if (Util::SameString(cAlphaArgs(19), "WETBULBTEMPERATURE")) { + checkCurveIsNormalizedToOne(state, + std::string{RoutineName} + cCurrentModuleObject, + thisVrfSys.Name, + thisVrfSys.HeatCapFT, + cAlphaFieldNames(13), + cAlphaArgs(13), + RatedInletAirTempHeat, + RatedOutdoorWetBulbTempHeat); + } else if (Util::SameString(cAlphaArgs(19), "DRYBULBTEMPERATURE")) { + checkCurveIsNormalizedToOne(state, + std::string{RoutineName} + cCurrentModuleObject, + thisVrfSys.Name, + thisVrfSys.HeatCapFT, + cAlphaFieldNames(13), + cAlphaArgs(13), + RatedInletAirTempHeat, + RatedOutdoorAirTempHeat); + } } + thisVrfSys.HeatBoundaryCurvePtr = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(14), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(14)); + thisVrfSys.HeatCapFTHi = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(15), {2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(15)); + thisVrfSys.HeatEIRFT = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(16), {2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(16)); + thisVrfSys.EIRHeatBoundaryCurvePtr = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(17), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(17)); + thisVrfSys.HeatEIRFTHi = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(18), {2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(18)); + if (Util::SameString(cAlphaArgs(19), "WETBULBTEMPERATURE")) { thisVrfSys.HeatingPerformanceOATType = HVAC::OATType::WetBulb; } else if (Util::SameString(cAlphaArgs(19), "DRYBULBTEMPERATURE")) { @@ -1944,120 +1960,42 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) ErrorsFound = true; } - thisVrfSys.HeatEIRFPLR1 = GetCurveIndex(state, cAlphaArgs(20)); - if (thisVrfSys.HeatEIRFPLR1 > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HeatEIRFPLR1, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(20)); // Field Name - } - - thisVrfSys.HeatEIRFPLR2 = GetCurveIndex(state, cAlphaArgs(21)); - if (thisVrfSys.HeatEIRFPLR2 > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HeatEIRFPLR2, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(21)); // Field Name - } - - thisVrfSys.HeatCombRatioPTR = GetCurveIndex(state, cAlphaArgs(22)); - if (thisVrfSys.HeatCombRatioPTR > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HeatCombRatioPTR, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(22)); // Field Name - } - thisVrfSys.HeatPLFFPLR = GetCurveIndex(state, cAlphaArgs(23)); - if (thisVrfSys.HeatPLFFPLR > 0) { - // Verify Curve Object, only legal type is linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HeatPLFFPLR, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(23)); // Field Name - - if (!ErrorsFound) { - auto [MinCurvePLR, MinCurveVal, MaxCurvePLR, MaxCurveVal] = checkCurveMinMaxOutput(thisVrfSys.HeatPLFFPLR); - - if (MinCurveVal < 0.7) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisVrfSys.Name)); - ShowContinueError(state, EnergyPlus::format("...{}=\"{}\" has out of range values.", cAlphaFieldNames(23), cAlphaArgs(23))); - ShowContinueError( - state, EnergyPlus::format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", MinCurvePLR, MinCurveVal)); - ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues."); - Curve::SetCurveOutputMinValue(state, thisVrfSys.HeatPLFFPLR, ErrorsFound, 0.7); - } - - if (MaxCurveVal > 1.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisVrfSys.Name)); - ShowContinueError(state, EnergyPlus::format("...{}=\"{}\" has out of range values.", cAlphaFieldNames(23), cAlphaArgs(23))); - ShowContinueError( - state, EnergyPlus::format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", MaxCurvePLR, MaxCurveVal)); - ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues."); - Curve::SetCurveOutputMaxValue(state, thisVrfSys.HeatPLFFPLR, ErrorsFound, 1.0); - } - } + thisVrfSys.HeatEIRFPLR1 = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(20), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(20)); + thisVrfSys.HeatEIRFPLR2 = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(21), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(21)); + thisVrfSys.HeatCombRatioPTR = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(22), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(22)); + thisVrfSys.HeatPLFFPLR = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(23), {1}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(23)); + if (thisVrfSys.HeatPLFFPLR > 0 && !ErrorsFound) { + checkAndCapPLFCurve( + state, ErrorsFound, thisVrfSys.HeatPLFFPLR, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(23), cAlphaArgs(23)); } thisVrfSys.MinPLR = rNumericArgs(10); - Real64 minEIRfLowPLRXInput = 0.0; - Real64 maxEIRfLowPLRXInput = 0.0; if (thisVrfSys.CoolEIRFPLR1 > 0) { - Curve::GetCurveMinMaxValues(state, thisVrfSys.CoolEIRFPLR1, minEIRfLowPLRXInput, maxEIRfLowPLRXInput); - if (minEIRfLowPLRXInput > thisVrfSys.MinPLR) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisVrfSys.Name)); - ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", cAlphaFieldNames(9), cAlphaArgs(9))); - ShowContinueError(state, - EnergyPlus::format("...Curve minimum value of X = {:.3T} must be <= Minimum Heat Pump Part-Load Ratio = {:.3T}.", - minEIRfLowPLRXInput, - thisVrfSys.MinPLR)); - ErrorsFound = true; - } - if (maxEIRfLowPLRXInput < 1.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", suspicious", RoutineName, cCurrentModuleObject, thisVrfSys.Name)); - ShowContinueError(state, EnergyPlus::format("...{} = {} has unexpected value.", cAlphaFieldNames(9), cAlphaArgs(9))); - ShowContinueError( - state, - EnergyPlus::format("...Curve maximum value of X = {:.3T} should be 1 and will result in lower energy use than expected.", - maxEIRfLowPLRXInput)); - } - minEIRfLowPLRXInput = 0.0; - maxEIRfLowPLRXInput = 0.0; + checkEIRFPLRCurveRange(state, + ErrorsFound, + thisVrfSys.CoolEIRFPLR1, + thisVrfSys.MinPLR, + RoutineName, + cCurrentModuleObject, + thisVrfSys.Name, + cAlphaFieldNames(9), + cAlphaArgs(9)); } if (thisVrfSys.HeatEIRFPLR1 > 0) { - Curve::GetCurveMinMaxValues(state, thisVrfSys.HeatEIRFPLR1, minEIRfLowPLRXInput, maxEIRfLowPLRXInput); - if (minEIRfLowPLRXInput > thisVrfSys.MinPLR) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisVrfSys.Name)); - ShowContinueError(state, EnergyPlus::format("...{} = {} has out of range value.", cAlphaFieldNames(20), cAlphaArgs(20))); - ShowContinueError(state, - EnergyPlus::format("...Curve minimum value of X = {:.3T} must be <= Minimum Heat Pump Part-Load Ratio = {:.3T}.", - minEIRfLowPLRXInput, - thisVrfSys.MinPLR)); - ErrorsFound = true; - } - if (maxEIRfLowPLRXInput < 1.0) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", suspicious", RoutineName, cCurrentModuleObject, thisVrfSys.Name)); - ShowContinueError(state, EnergyPlus::format("...{} = {} has unexpected value.", cAlphaFieldNames(20), cAlphaArgs(20))); - ShowContinueError( - state, - EnergyPlus::format("...Curve maximum value of X = {:.3T} should be 1 and will result in lower energy use than expected.", - maxEIRfLowPLRXInput)); - } + checkEIRFPLRCurveRange(state, + ErrorsFound, + thisVrfSys.HeatEIRFPLR1, + thisVrfSys.MinPLR, + RoutineName, + cCurrentModuleObject, + thisVrfSys.Name, + cAlphaFieldNames(20), + cAlphaArgs(20)); } thisVrfSys.MasterZonePtr = Util::FindItemInList(cAlphaArgs(24), state.dataHeatBal->Zone); @@ -2108,31 +2046,13 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) thisVrfSys.EquivPipeLngthCool = rNumericArgs(11); thisVrfSys.VertPipeLngth = rNumericArgs(12); - thisVrfSys.PCFLengthCoolPtr = GetCurveIndex(state, cAlphaArgs(29)); - if (thisVrfSys.PCFLengthCoolPtr > 0) { - // Verify Curve Object, only legal type is linear, quadratic, cubic, or biquadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.PCFLengthCoolPtr, // Curve index - {1, 2}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(29)); // Field Name - } + thisVrfSys.PCFLengthCoolPtr = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(29), {1, 2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(29)); thisVrfSys.PCFHeightCool = rNumericArgs(13); thisVrfSys.EquivPipeLngthHeat = rNumericArgs(14); - thisVrfSys.PCFLengthHeatPtr = GetCurveIndex(state, cAlphaArgs(30)); - if (thisVrfSys.PCFLengthHeatPtr > 0) { - // Verify Curve Object, only legal type is linear, quadratic, cubic, or biquadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.PCFLengthHeatPtr, // Curve index - {1, 2}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(30)); // Field Name - } + thisVrfSys.PCFLengthHeatPtr = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(30), {1, 2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(30)); thisVrfSys.PCFHeightHeat = rNumericArgs(15); @@ -2169,17 +2089,9 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) } if (!lAlphaFieldBlanks(33)) { - thisVrfSys.DefrostEIRPtr = GetCurveIndex(state, cAlphaArgs(33)); - if (thisVrfSys.DefrostEIRPtr > 0) { - // Verify Curve Object, expected type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.DefrostEIRPtr, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(33)); // Field Name - } else { + thisVrfSys.DefrostEIRPtr = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(33), {2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(33)); + if (thisVrfSys.DefrostEIRPtr == 0) { if (thisVrfSys.DefrostStrategy == StandardRatings::DefrostStrat::ReverseCycle) { ShowSevereError(state, EnergyPlus::format( @@ -2405,32 +2317,14 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) } } - thisVrfSys.HRCAPFTCool = GetCurveIndex(state, cAlphaArgs(40)); - if (thisVrfSys.HRCAPFTCool > 0) { - // Verify Curve Object, only legal type is bi-quadratic or linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HRCAPFTCool, // Curve index - {1, 2}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(40)); // Field Name - } + thisVrfSys.HRCAPFTCool = getAndCheckCurve( + state, ErrorsFound, cAlphaArgs(40), {1, 2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(40)); if (!lNumericFieldBlanks(31)) { thisVrfSys.HRInitialCoolCapFrac = rNumericArgs(31); } thisVrfSys.HRCoolCapTC = rNumericArgs(32); - thisVrfSys.HREIRFTCool = GetCurveIndex(state, cAlphaArgs(41)); - if (thisVrfSys.HREIRFTCool > 0) { - // Verify Curve Object, only legal type is bi-quadratic or linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HREIRFTCool, // Curve index - {1, 2}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(41)); // Field Name - } + thisVrfSys.HREIRFTCool = getAndCheckCurve( + state, ErrorsFound, cAlphaArgs(41), {1, 2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(41)); thisVrfSys.HRInitialCoolEIRFrac = rNumericArgs(33); thisVrfSys.HRCoolEIRTC = rNumericArgs(34); @@ -2438,17 +2332,8 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) // REAL(r64) :: HRInitialHeatCapFrac =0.0d0 ! Fractional heating degradation at the start of heat recovery from heating mode // REAL(r64) :: HRHeatCapTC =0.0d0 ! Time constant used to recover from initial degradation in heating heat // recovery - thisVrfSys.HRCAPFTHeat = GetCurveIndex(state, cAlphaArgs(42)); - if (thisVrfSys.HRCAPFTHeat > 0) { - // Verify Curve Object, only legal type is bi-quadratic or linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HRCAPFTHeat, // Curve index - {1, 2}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(42)); // Field Name - } + thisVrfSys.HRCAPFTHeat = getAndCheckCurve( + state, ErrorsFound, cAlphaArgs(42), {1, 2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(42)); thisVrfSys.HRInitialHeatCapFrac = rNumericArgs(35); thisVrfSys.HRHeatCapTC = rNumericArgs(36); @@ -2456,418 +2341,383 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) // REAL(r64) :: HRInitialHeatEIRFrac =0.0d0 ! Fractional EIR degradation at the start of heat recovery from heating mode // REAL(r64) :: HRHeatEIRTC =0.0d0 ! Time constant used to recover from initial degradation in heating heat // recovery - thisVrfSys.HREIRFTHeat = GetCurveIndex(state, cAlphaArgs(43)); - if (thisVrfSys.HREIRFTHeat > 0) { - // Verify Curve Object, only legal type is bi-quadratic or linear, quadratic, or cubic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfSys.HREIRFTHeat, // Curve index - {1, 2}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfSys.Name, // Object Name - cAlphaFieldNames(43)); // Field Name - } + thisVrfSys.HREIRFTHeat = getAndCheckCurve( + state, ErrorsFound, cAlphaArgs(43), {1, 2}, RoutineName, cCurrentModuleObject, thisVrfSys.Name, cAlphaFieldNames(43)); thisVrfSys.HRInitialHeatEIRFrac = rNumericArgs(37); thisVrfSys.HRHeatEIRTC = rNumericArgs(38); } } - // Read all VRF condenser objects: Algorithm Type 2_physics based model (VRF-FluidTCtrl-HP) - cCurrentModuleObject = "AirConditioner:VariableRefrigerantFlow:FluidTemperatureControl"; - for (int thisNum = 1; thisNum <= state.dataHVACVarRefFlow->NumVRFCond_FluidTCtrl_HP; ++thisNum) { + // Lambda: load compressor speed, evaporating capacity, and compressor power curves for + // FluidTCtrl HP and HR condenser objects. The two object types share identical loop logic; + // only the VRF struct reference and the starting index offsets differ. + auto readOUCompressorSpeedCurves = [&](VRFCondenserEquipment &thisVrf, const std::string &objName, int numericStartIndex, int alphaStartIndex) { + int NumOfCompSpd = rNumericArgs(numericStartIndex); + thisVrf.CompressorSpeed.dimension(NumOfCompSpd); + thisVrf.OUCoolingCAPFT.dimension(NumOfCompSpd); + thisVrf.OUCoolingPWRFT.dimension(NumOfCompSpd); + for (int NumCompSpd = 1; NumCompSpd <= NumOfCompSpd; NumCompSpd++) { + thisVrf.CompressorSpeed(NumCompSpd) = rNumericArgs(numericStartIndex + NumCompSpd); - state.dataInputProcessing->inputProcessor->getObjectItem(state, - cCurrentModuleObject, - thisNum, - cAlphaArgs, - NumAlphas, - rNumericArgs, - NumNums, - IOStat, - lNumericFieldBlanks, - lAlphaFieldBlanks, - cAlphaFieldNames, - cNumericFieldNames); + // Evaporating Capacity Curve + if (!lAlphaFieldBlanks(alphaStartIndex + 2 * NumCompSpd)) { + int indexOUEvapCapCurve = GetCurveIndex(state, cAlphaArgs(alphaStartIndex + 2 * NumCompSpd)); + if (indexOUEvapCapCurve == 0) { // Verify curve name and type + if (lAlphaFieldBlanks(alphaStartIndex + 2 * NumCompSpd)) { + ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + objName + "\", missing"); + ShowContinueError(state, "...required " + cAlphaFieldNames(alphaStartIndex + 2 * NumCompSpd) + " is blank."); + } else { + ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + objName + "\", invalid"); + ShowContinueError(state, + EnergyPlus::format("...not found {}=\"{}\".", + cAlphaFieldNames(alphaStartIndex + 2 * NumCompSpd), + cAlphaArgs(alphaStartIndex + 2 * NumCompSpd))); + } + ErrorsFound = true; + } else { + ErrorsFound |= Curve::CheckCurveDims(state, + indexOUEvapCapCurve, + {2}, + RoutineName, + cCurrentModuleObject, + objName, + cAlphaFieldNames(alphaStartIndex + 2 * NumCompSpd)); + if (!ErrorsFound) { + thisVrf.OUCoolingCAPFT(NumCompSpd) = indexOUEvapCapCurve; + } + } + } - ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)}; + // Compressor Power Curve + if (!lAlphaFieldBlanks(alphaStartIndex + 2 * NumCompSpd + 1)) { + int indexOUCompPwrCurve = GetCurveIndex(state, cAlphaArgs(alphaStartIndex + 2 * NumCompSpd + 1)); + if (indexOUCompPwrCurve == 0) { // Verify curve name and type + if (lAlphaFieldBlanks(alphaStartIndex + 2 * NumCompSpd + 1)) { + ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + objName + "\", missing"); + ShowContinueError(state, "...required " + cAlphaFieldNames(alphaStartIndex + 2 * NumCompSpd + 1) + " is blank."); + } else { + ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + objName + "\", invalid"); + ShowContinueError(state, + EnergyPlus::format("...not found {}=\"{}\".", + cAlphaFieldNames(alphaStartIndex + 2 * NumCompSpd + 1), + cAlphaArgs(alphaStartIndex + 2 * NumCompSpd + 1))); + } + ErrorsFound = true; + } else { + ErrorsFound |= Curve::CheckCurveDims(state, + indexOUCompPwrCurve, + {2}, + RoutineName, + cCurrentModuleObject, + objName, + cAlphaFieldNames(alphaStartIndex + 2 * NumCompSpd + 1)); + if (!ErrorsFound) { + thisVrf.OUCoolingPWRFT(NumCompSpd) = indexOUCompPwrCurve; + } + } + } + } + }; - GlobalNames::VerifyUniqueInterObjectName( - state, state.dataHVACVarRefFlow->VrfUniqueNames, cAlphaArgs(1), cCurrentModuleObject, cAlphaFieldNames(1), ErrorsFound); + // Lambda: parse defrost strategy, control, EIR curve, fraction/capacity/max-OAT fields for + // FluidTCtrl HP and HR objects. Alpha fields 8/9/10 are the same in both object types; + // the numeric field indices for DefrostFraction/Capacity/MaxOATDefrost differ and are passed + // in as fracIdx, capIdx, maxOATIdx. + auto readFluidCtrlDefrost = + [&](VRFCondenserEquipment &thisVrf, const std::string &objName, int fracIdx, int capIdx, int maxOATIdx, const std::string &capFieldName) { + // Defrost strategy + if (!lAlphaFieldBlanks(8)) { + if (Util::SameString(cAlphaArgs(8), "ReverseCycle")) { + thisVrf.DefrostStrategy = StandardRatings::DefrostStrat::ReverseCycle; + } + if (Util::SameString(cAlphaArgs(8), "Resistive")) { + thisVrf.DefrostStrategy = StandardRatings::DefrostStrat::Resistive; + } + if (thisVrf.DefrostStrategy == StandardRatings::DefrostStrat::Invalid) { + ShowSevereError(state, cCurrentModuleObject + ", \"" + objName + "\" " + cAlphaFieldNames(8) + " not found: " + cAlphaArgs(8)); + ErrorsFound = true; + } + } else { + thisVrf.DefrostStrategy = StandardRatings::DefrostStrat::ReverseCycle; + } - int VRFNum = state.dataHVACVarRefFlow->NumVRFCond_SysCurve + thisNum; - auto &thisVrfFluidCtrl = state.dataHVACVarRefFlow->VRF(VRFNum); - thisVrfFluidCtrl.Name = cAlphaArgs(1); - thisVrfFluidCtrl.VRFSystemTypeNum = VRF_HeatPump; - thisVrfFluidCtrl.VRFAlgorithmType = AlgorithmType::FluidTCtrl; - thisVrfFluidCtrl.fuel = Constant::eFuel::Electricity; + // Defrost control + if (!lAlphaFieldBlanks(9)) { + if (Util::SameString(cAlphaArgs(9), "Timed")) { + thisVrf.DefrostControl = StandardRatings::HPdefrostControl::Timed; + } + if (Util::SameString(cAlphaArgs(9), "OnDemand")) { + thisVrf.DefrostControl = StandardRatings::HPdefrostControl::OnDemand; + } + if (thisVrf.DefrostControl == StandardRatings::HPdefrostControl::Invalid) { + ShowSevereError(state, cCurrentModuleObject + ", \"" + objName + "\" " + cAlphaFieldNames(9) + " not found: " + cAlphaArgs(9)); + ErrorsFound = true; + } + } else { + thisVrf.DefrostControl = StandardRatings::HPdefrostControl::Timed; + } + + // Defrost EIR curve + if (!lAlphaFieldBlanks(10)) { + thisVrf.DefrostEIRPtr = + getAndCheckCurve(state, ErrorsFound, cAlphaArgs(10), {2}, RoutineName, cCurrentModuleObject, objName, cAlphaFieldNames(10)); + if (thisVrf.DefrostEIRPtr == 0) { + if (thisVrf.DefrostStrategy == StandardRatings::DefrostStrat::ReverseCycle && + thisVrf.DefrostControl == StandardRatings::HPdefrostControl::OnDemand) { + ShowSevereError(state, + cCurrentModuleObject + ", \"" + objName + "\" " + cAlphaFieldNames(10) + " not found:" + cAlphaArgs(10)); + ErrorsFound = true; + } + } + } else { + if (thisVrf.DefrostStrategy == StandardRatings::DefrostStrat::ReverseCycle && + thisVrf.DefrostControl == StandardRatings::HPdefrostControl::OnDemand) { + ShowSevereError(state, cCurrentModuleObject + ", \"" + objName + "\" " + cAlphaFieldNames(10) + " not found:" + cAlphaArgs(10)); + ErrorsFound = true; + } + } + + thisVrf.DefrostFraction = rNumericArgs(fracIdx); + thisVrf.DefrostCapacity = rNumericArgs(capIdx); + thisVrf.MaxOATDefrost = rNumericArgs(maxOATIdx); + if (thisVrf.DefrostCapacity == 0.0 && thisVrf.DefrostStrategy == StandardRatings::DefrostStrat::Resistive) { + ShowWarningError(state, cCurrentModuleObject + ", \"" + objName + "\" " + capFieldName + " = 0.0 for defrost strategy = RESISTIVE."); + } + }; + + // Lambda: emit a severe error when a minimum value is not less than its corresponding maximum. + // Used for OAT operating ranges and IU evap/cond temperature bounds. + auto checkMinLessThanMax = [&](const std::string &objName, Real64 minVal, Real64 maxVal, const std::string &minFieldName) { + if (minVal >= maxVal) { + ShowSevereError(state, cCurrentModuleObject + ", \"" + objName + "\""); + ShowContinueError(state, EnergyPlus::format("... {} ({:.3T}) must be less than maximum ({:.3T}).", minFieldName, minVal, maxVal)); + ErrorsFound = true; + } + }; + + // Lambda: read the IU control algorithm type (alpha field 5), fixed Te/Tc (numeric fields 9-10), + // and IU evap/cond temp bounds (numeric fields 11-14) — identical in FluidTCtrl-HP and HR objects. + auto readFluidCtrlIUConfig = [&](VRFCondenserEquipment &thisVrf) { + // IU Control Type + if (Util::SameString(cAlphaArgs(5), "VariableTemp")) { + thisVrf.AlgorithmIUCtrl = 1; + } else if (Util::SameString(cAlphaArgs(5), "ConstantTemp")) { + thisVrf.AlgorithmIUCtrl = 2; + } else { + thisVrf.AlgorithmIUCtrl = 1; + } + + // Reference IU Te/Tc for IU Control Algorithm: ConstantTemp + thisVrf.EvapTempFixed = rNumericArgs(9); + thisVrf.CondTempFixed = rNumericArgs(10); + // Bounds of Te/Tc for IU Control Algorithm: VariableTemp + thisVrf.IUEvapTempLow = rNumericArgs(11); + thisVrf.IUEvapTempHigh = rNumericArgs(12); + thisVrf.IUCondTempLow = rNumericArgs(13); + thisVrf.IUCondTempHigh = rNumericArgs(14); + checkMinLessThanMax(thisVrf.Name, thisVrf.IUEvapTempLow, thisVrf.IUEvapTempHigh, cNumericFieldNames(11)); + checkMinLessThanMax(thisVrf.Name, thisVrf.IUCondTempLow, thisVrf.IUCondTempHigh, cNumericFieldNames(13)); + }; + + // Lambda: read common FluidTCtrl fields shared by both HP and HR condenser objects. + // Handles availability schedule, zone TU list, refrigerant, rated capacity/COP, + // OA temperature ranges, SH/SC, IU config, OU fan data, OUEvap/OUCond temp curves, + // pipe parameters (with RefPipEquLen validation), and crank case parameters. + // Field indices that differ between HP and HR are passed as parameters. + auto readFluidCtrlCommonFields = [&](VRFCondenserEquipment &thisVrf, + ErrorObjectHeader const &eoh, + int shIdx, // numeric index for SH field + int scIdx, // numeric index for SC field + int ouFanPwrIdx, // numeric index for OU fan power per capacity + int ouAirFlowIdx, // numeric index for OU air flow per capacity + int pipDiaSucIdx, // numeric index for suction pipe diameter + int pipDiaDisIdx, // numeric index for discharge pipe diameter + int pipLenIdx, // numeric index for pipe length + int pipEquLenIdx, // numeric index for equivalent pipe length + int pipHeiIdx, // numeric index for pipe height + int pipInsThiIdx, // numeric index for pipe insulation thickness + int pipInsConIdx, // numeric index for pipe insulation conductivity + int ccHeatPwrIdx, // numeric index for crank case heater power + int numCompIdx, // numeric index for number of compressors + int compSzRatIdx, // numeric index for compressor size ratio + int maxOATccIdx) // numeric index for max OAT for crank case heater + { + // Availability schedule if (lAlphaFieldBlanks(2)) { - thisVrfFluidCtrl.availSched = Sched::GetScheduleAlwaysOn(state); - } else if ((thisVrfFluidCtrl.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) { + thisVrf.availSched = Sched::GetScheduleAlwaysOn(state); + } else if ((thisVrf.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) { ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2)); ErrorsFound = true; } - thisVrfFluidCtrl.ZoneTUListPtr = + // Zone terminal unit list + thisVrf.ZoneTUListPtr = Util::FindItemInList(cAlphaArgs(3), state.dataHVACVarRefFlow->TerminalUnitList, state.dataHVACVarRefFlow->NumVRFTULists); - if (thisVrfFluidCtrl.ZoneTUListPtr == 0) { - ShowSevereError(state, cCurrentModuleObject + " = \"" + thisVrfFluidCtrl.Name + "\""); + if (thisVrf.ZoneTUListPtr == 0) { + ShowSevereError(state, cCurrentModuleObject + " = \"" + thisVrf.Name + "\""); ShowContinueError(state, cAlphaFieldNames(3) + " = " + cAlphaArgs(3) + " not found."); ErrorsFound = true; } // Refrigerant type - thisVrfFluidCtrl.refrigName = cAlphaArgs(4); - thisVrfFluidCtrl.refrig = Fluid::GetRefrig(state, thisVrfFluidCtrl.refrigName); - if (thisVrfFluidCtrl.refrig == nullptr) { + thisVrf.refrigName = cAlphaArgs(4); + if ((thisVrf.refrig = Fluid::GetRefrig(state, thisVrf.refrigName)) == nullptr) { ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(4), cAlphaArgs(4)); ErrorsFound = true; } - thisVrfFluidCtrl.RatedEvapCapacity = rNumericArgs(1); - thisVrfFluidCtrl.RatedCompPowerPerCapcity = rNumericArgs(2); - thisVrfFluidCtrl.RatedCompPower = thisVrfFluidCtrl.RatedCompPowerPerCapcity * thisVrfFluidCtrl.RatedEvapCapacity; - thisVrfFluidCtrl.CoolingCapacity = thisVrfFluidCtrl.RatedEvapCapacity; - thisVrfFluidCtrl.RatedHeatCapacity = thisVrfFluidCtrl.RatedEvapCapacity * (1 + thisVrfFluidCtrl.RatedCompPowerPerCapcity); - thisVrfFluidCtrl.HeatingCapacity = thisVrfFluidCtrl.RatedHeatCapacity; - - // Reference system COP - thisVrfFluidCtrl.CoolingCOP = 1 / thisVrfFluidCtrl.RatedCompPowerPerCapcity; - thisVrfFluidCtrl.HeatingCOP = 1 / thisVrfFluidCtrl.RatedCompPowerPerCapcity + 1; - - // OA temperature range for VRF-HP operations - thisVrfFluidCtrl.MinOATCooling = rNumericArgs(3); - thisVrfFluidCtrl.MaxOATCooling = rNumericArgs(4); - thisVrfFluidCtrl.MinOATHeating = rNumericArgs(5); - thisVrfFluidCtrl.MaxOATHeating = rNumericArgs(6); - if (thisVrfFluidCtrl.MinOATCooling >= thisVrfFluidCtrl.MaxOATCooling) { - ShowSevereError(state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrl.Name + "\""); - ShowContinueError(state, - EnergyPlus::format("... {} ({:.3T}) must be less than maximum ({:.3T}).", - cNumericFieldNames(3), - thisVrfFluidCtrl.MinOATCooling, - thisVrfFluidCtrl.MaxOATCooling)); - ErrorsFound = true; - } - if (thisVrfFluidCtrl.MinOATHeating >= thisVrfFluidCtrl.MaxOATHeating) { - ShowSevereError(state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrl.Name + "\""); - ShowContinueError(state, - EnergyPlus::format("... {} ({:.3T}) must be less than maximum ({:.3T}).", - cNumericFieldNames(5), - thisVrfFluidCtrl.MinOATHeating, - thisVrfFluidCtrl.MaxOATHeating)); - ErrorsFound = true; - } + // Rated capacity and COP + thisVrf.RatedEvapCapacity = rNumericArgs(1); + thisVrf.RatedCompPowerPerCapcity = rNumericArgs(2); + thisVrf.RatedCompPower = thisVrf.RatedCompPowerPerCapcity * thisVrf.RatedEvapCapacity; + thisVrf.CoolingCapacity = thisVrf.RatedEvapCapacity; + thisVrf.RatedHeatCapacity = thisVrf.RatedEvapCapacity * (1 + thisVrf.RatedCompPowerPerCapcity); + thisVrf.HeatingCapacity = thisVrf.RatedHeatCapacity; + thisVrf.CoolingCOP = 1 / thisVrf.RatedCompPowerPerCapcity; + thisVrf.HeatingCOP = 1 / thisVrf.RatedCompPowerPerCapcity + 1; + + // OA temperature range (cooling and heating -- common to HP and HR) + thisVrf.MinOATCooling = rNumericArgs(3); + thisVrf.MaxOATCooling = rNumericArgs(4); + thisVrf.MinOATHeating = rNumericArgs(5); + thisVrf.MaxOATHeating = rNumericArgs(6); + checkMinLessThanMax(thisVrf.Name, thisVrf.MinOATCooling, thisVrf.MaxOATCooling, cNumericFieldNames(3)); + checkMinLessThanMax(thisVrf.Name, thisVrf.MinOATHeating, thisVrf.MaxOATHeating, cNumericFieldNames(5)); // Reference OU SH/SC - thisVrfFluidCtrl.SH = rNumericArgs(7); - thisVrfFluidCtrl.SC = rNumericArgs(8); + thisVrf.SH = rNumericArgs(shIdx); + thisVrf.SC = rNumericArgs(scIdx); - if (Util::SameString(cAlphaArgs(5), "VariableTemp")) { - thisVrfFluidCtrl.AlgorithmIUCtrl = 1; - } else if (Util::SameString(cAlphaArgs(5), "ConstantTemp")) { - thisVrfFluidCtrl.AlgorithmIUCtrl = 2; - } else { - thisVrfFluidCtrl.AlgorithmIUCtrl = 1; - } + // IU configuration (alpha field 5 + numeric fields 9-14) + readFluidCtrlIUConfig(thisVrf); - // Reference IU Te/Tc for IU Control Algorithm: ConstantTemp - thisVrfFluidCtrl.EvapTempFixed = rNumericArgs(9); - thisVrfFluidCtrl.CondTempFixed = rNumericArgs(10); - - // Bounds of Te/Tc for IU Control Algorithm: VariableTemp - thisVrfFluidCtrl.IUEvapTempLow = rNumericArgs(11); - thisVrfFluidCtrl.IUEvapTempHigh = rNumericArgs(12); - thisVrfFluidCtrl.IUCondTempLow = rNumericArgs(13); - thisVrfFluidCtrl.IUCondTempHigh = rNumericArgs(14); - if (thisVrfFluidCtrl.IUEvapTempLow >= thisVrfFluidCtrl.IUEvapTempHigh) { - ShowSevereError(state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrl.Name + "\""); - ShowContinueError(state, - EnergyPlus::format("... {} ({:.3T}) must be less than maximum ({:.3T}).", - cNumericFieldNames(11), - thisVrfFluidCtrl.IUEvapTempLow, - thisVrfFluidCtrl.IUEvapTempHigh)); - ErrorsFound = true; - } - if (thisVrfFluidCtrl.IUCondTempLow >= thisVrfFluidCtrl.IUCondTempHigh) { - ShowSevereError(state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrl.Name + "\""); - ShowContinueError(state, - EnergyPlus::format("... {} ({:.3T}) must be less than maximum ({:.3T}).", - cNumericFieldNames(13), - thisVrfFluidCtrl.IUCondTempLow, - thisVrfFluidCtrl.IUCondTempHigh)); - ErrorsFound = true; - } - - // Get OU fan data - thisVrfFluidCtrl.RatedOUFanPowerPerCapcity = rNumericArgs(15); - thisVrfFluidCtrl.OUAirFlowRatePerCapcity = rNumericArgs(16); - thisVrfFluidCtrl.RatedOUFanPower = thisVrfFluidCtrl.RatedOUFanPowerPerCapcity * thisVrfFluidCtrl.RatedEvapCapacity; - thisVrfFluidCtrl.OUAirFlowRate = thisVrfFluidCtrl.OUAirFlowRatePerCapcity * thisVrfFluidCtrl.RatedEvapCapacity; + // OU fan data + thisVrf.RatedOUFanPowerPerCapcity = rNumericArgs(ouFanPwrIdx); + thisVrf.OUAirFlowRatePerCapcity = rNumericArgs(ouAirFlowIdx); + thisVrf.RatedOUFanPower = thisVrf.RatedOUFanPowerPerCapcity * thisVrf.RatedEvapCapacity; + thisVrf.OUAirFlowRate = thisVrf.OUAirFlowRatePerCapcity * thisVrf.RatedEvapCapacity; // OUEvapTempCurve - int indexOUEvapTempCurve = GetCurveIndex(state, cAlphaArgs(6)); // convert curve name to index number - // Verify curve name and type - if (indexOUEvapTempCurve == 0) { - if (lAlphaFieldBlanks(6)) { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrl.Name + "\", missing"); - ShowContinueError(state, "...required " + cAlphaFieldNames(6) + " is blank."); - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrl.Name + "\", invalid"); - ShowContinueError(state, "...not found " + cAlphaFieldNames(6) + "=\"" + cAlphaArgs(6) + "\"."); - } - ErrorsFound = true; - } else { - { - if (state.dataCurveManager->curves(indexOUEvapTempCurve)->curveType == Curve::CurveType::Quadratic) { - thisVrfFluidCtrl.C1Te = state.dataCurveManager->curves(indexOUEvapTempCurve)->coeff[0]; - thisVrfFluidCtrl.C2Te = state.dataCurveManager->curves(indexOUEvapTempCurve)->coeff[1]; - thisVrfFluidCtrl.C3Te = state.dataCurveManager->curves(indexOUEvapTempCurve)->coeff[2]; - - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrl.Name + "\", invalid"); - ShowContinueError( - state, - EnergyPlus::format("...illegal {} type for this object = {}", - cAlphaFieldNames(6), - Curve::objectNames[static_cast(state.dataCurveManager->curves(indexOUEvapTempCurve)->curveType)])); - ShowContinueError(state, "... Curve type must be Quadratic."); - ErrorsFound = true; - } - } - } + getRequiredQuadraticCurveCoeffs(state, + ErrorsFound, + RoutineName, + cCurrentModuleObject, + thisVrf.Name, + cAlphaArgs(6), + cAlphaFieldNames(6), + lAlphaFieldBlanks(6), + thisVrf.C1Te, + thisVrf.C2Te, + thisVrf.C3Te); // OUCondTempCurve - int indexOUCondTempCurve = GetCurveIndex(state, cAlphaArgs(7)); // convert curve name to index number - // Verify curve name and type - if (indexOUCondTempCurve == 0) { - if (lAlphaFieldBlanks(7)) { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrl.Name + "\", missing"); - ShowContinueError(state, "...required " + cAlphaFieldNames(7) + " is blank."); - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrl.Name + "\", invalid"); - ShowContinueError(state, "...not found " + cAlphaFieldNames(7) + "=\"" + cAlphaArgs(7) + "\"."); - } - ErrorsFound = true; - } else { - { - if (state.dataCurveManager->curves(indexOUCondTempCurve)->curveType == Curve::CurveType::Quadratic) { - thisVrfFluidCtrl.C1Tc = state.dataCurveManager->curves(indexOUCondTempCurve)->coeff[0]; - thisVrfFluidCtrl.C2Tc = state.dataCurveManager->curves(indexOUCondTempCurve)->coeff[1]; - thisVrfFluidCtrl.C3Tc = state.dataCurveManager->curves(indexOUCondTempCurve)->coeff[2]; - - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrl.Name + "\", invalid"); - ShowContinueError( - state, - EnergyPlus::format("...illegal {} type for this object = {}", - cAlphaFieldNames(7), - Curve::objectNames[static_cast(state.dataCurveManager->curves(indexOUCondTempCurve)->curveType)])); - ShowContinueError(state, "... Curve type must be Quadratic."); - ErrorsFound = true; - } - } - } + getRequiredQuadraticCurveCoeffs(state, + ErrorsFound, + RoutineName, + cCurrentModuleObject, + thisVrf.Name, + cAlphaArgs(7), + cAlphaFieldNames(7), + lAlphaFieldBlanks(7), + thisVrf.C1Tc, + thisVrf.C2Tc, + thisVrf.C3Tc); // Pipe parameters - thisVrfFluidCtrl.RefPipDiaSuc = rNumericArgs(17); - thisVrfFluidCtrl.RefPipDiaDis = rNumericArgs(17); - thisVrfFluidCtrl.RefPipLen = rNumericArgs(18); - thisVrfFluidCtrl.RefPipEquLen = rNumericArgs(19); - thisVrfFluidCtrl.RefPipHei = rNumericArgs(20); - thisVrfFluidCtrl.RefPipInsThi = rNumericArgs(21); - thisVrfFluidCtrl.RefPipInsCon = rNumericArgs(22); + thisVrf.RefPipDiaSuc = rNumericArgs(pipDiaSucIdx); + thisVrf.RefPipDiaDis = rNumericArgs(pipDiaDisIdx); + thisVrf.RefPipLen = rNumericArgs(pipLenIdx); + thisVrf.RefPipEquLen = rNumericArgs(pipEquLenIdx); + thisVrf.RefPipHei = rNumericArgs(pipHeiIdx); + thisVrf.RefPipInsThi = rNumericArgs(pipInsThiIdx); + thisVrf.RefPipInsCon = rNumericArgs(pipInsConIdx); // Check the RefPipEquLen - if (lNumericFieldBlanks(19) && !lNumericFieldBlanks(18)) { - thisVrfFluidCtrl.RefPipEquLen = 1.2 * thisVrfFluidCtrl.RefPipLen; + if (lNumericFieldBlanks(pipEquLenIdx) && !lNumericFieldBlanks(pipLenIdx)) { + thisVrf.RefPipEquLen = 1.2 * thisVrf.RefPipLen; ShowWarningError( - state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrl.Name + "\", \" " + cNumericFieldNames(19) + "\" is calculated based on"); - ShowContinueError(state, "...the provided \"" + cNumericFieldNames(18) + "\" value."); + state, cCurrentModuleObject + ", \"" + thisVrf.Name + "\", \" " + cNumericFieldNames(pipEquLenIdx) + "\" is calculated based on"); + ShowContinueError(state, "...the provided \"" + cNumericFieldNames(pipLenIdx) + "\" value."); } - if (thisVrfFluidCtrl.RefPipEquLen < thisVrfFluidCtrl.RefPipLen) { - thisVrfFluidCtrl.RefPipEquLen = 1.2 * thisVrfFluidCtrl.RefPipLen; - ShowWarningError(state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrl.Name + "\", invalid \" " + cNumericFieldNames(19) + "\" value."); + if (thisVrf.RefPipEquLen < thisVrf.RefPipLen) { + thisVrf.RefPipEquLen = 1.2 * thisVrf.RefPipLen; + ShowWarningError(state, + cCurrentModuleObject + ", \"" + thisVrf.Name + "\", invalid \" " + cNumericFieldNames(pipEquLenIdx) + "\" value."); ShowContinueError(state, "...Equivalent length of main pipe should be greater than or equal to the actual length."); - ShowContinueError(state, EnergyPlus::format("...The value is recalculated based on the provided \"{}\" value.", cNumericFieldNames(18))); + ShowContinueError(state, + EnergyPlus::format("...The value is recalculated based on the provided \"{}\" value.", cNumericFieldNames(pipLenIdx))); } // Crank case - thisVrfFluidCtrl.CCHeaterPower = rNumericArgs(23); - thisVrfFluidCtrl.NumCompressors = rNumericArgs(24); - thisVrfFluidCtrl.CompressorSizeRatio = rNumericArgs(25); - thisVrfFluidCtrl.MaxOATCCHeater = rNumericArgs(26); - - // Defrost - if (!lAlphaFieldBlanks(8)) { - if (Util::SameString(cAlphaArgs(8), "ReverseCycle")) { - thisVrfFluidCtrl.DefrostStrategy = StandardRatings::DefrostStrat::ReverseCycle; - } - if (Util::SameString(cAlphaArgs(8), "Resistive")) { - thisVrfFluidCtrl.DefrostStrategy = StandardRatings::DefrostStrat::Resistive; - } - if (thisVrfFluidCtrl.DefrostStrategy == StandardRatings::DefrostStrat::Invalid) { - ShowSevereError(state, - cCurrentModuleObject + ", \"" + thisVrfFluidCtrl.Name + "\" " + cAlphaFieldNames(8) + " not found: " + cAlphaArgs(8)); - ErrorsFound = true; - } - } else { - thisVrfFluidCtrl.DefrostStrategy = StandardRatings::DefrostStrat::ReverseCycle; - } - - if (!lAlphaFieldBlanks(9)) { - if (Util::SameString(cAlphaArgs(9), "Timed")) { - thisVrfFluidCtrl.DefrostControl = StandardRatings::HPdefrostControl::Timed; - } - if (Util::SameString(cAlphaArgs(9), "OnDemand")) { - thisVrfFluidCtrl.DefrostControl = StandardRatings::HPdefrostControl::OnDemand; - } - if (thisVrfFluidCtrl.DefrostControl == StandardRatings::HPdefrostControl::Invalid) { - ShowSevereError(state, - cCurrentModuleObject + ", \"" + thisVrfFluidCtrl.Name + "\" " + cAlphaFieldNames(9) + " not found: " + cAlphaArgs(9)); - ErrorsFound = true; - } - } else { - thisVrfFluidCtrl.DefrostControl = StandardRatings::HPdefrostControl::Timed; - } - - if (!lAlphaFieldBlanks(10)) { - thisVrfFluidCtrl.DefrostEIRPtr = GetCurveIndex(state, cAlphaArgs(10)); - if (thisVrfFluidCtrl.DefrostEIRPtr > 0) { - // Verify Curve Object, expected type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfFluidCtrl.DefrostEIRPtr, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfFluidCtrl.Name, // Object Name - cAlphaFieldNames(10)); // Field Name - } else { - if (thisVrfFluidCtrl.DefrostStrategy == StandardRatings::DefrostStrat::ReverseCycle && - thisVrfFluidCtrl.DefrostControl == StandardRatings::HPdefrostControl::OnDemand) { - ShowSevereError( - state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrl.Name + "\" " + cAlphaFieldNames(10) + " not found:" + cAlphaArgs(10)); - ErrorsFound = true; - } - } - } else { - if (thisVrfFluidCtrl.DefrostStrategy == StandardRatings::DefrostStrat::ReverseCycle && - thisVrfFluidCtrl.DefrostControl == StandardRatings::HPdefrostControl::OnDemand) { - ShowSevereError( - state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrl.Name + "\" " + cAlphaFieldNames(10) + " not found:" + cAlphaArgs(10)); - ErrorsFound = true; - } - } - - thisVrfFluidCtrl.DefrostFraction = rNumericArgs(27); - thisVrfFluidCtrl.DefrostCapacity = rNumericArgs(28); - thisVrfFluidCtrl.MaxOATDefrost = rNumericArgs(29); - if (thisVrfFluidCtrl.DefrostCapacity == 0.0 && thisVrfFluidCtrl.DefrostStrategy == StandardRatings::DefrostStrat::Resistive) { - ShowWarningError(state, - cCurrentModuleObject + ", \"" + thisVrfFluidCtrl.Name + "\" " + cNumericFieldNames(28) + - " = 0.0 for defrost strategy = RESISTIVE."); - } + thisVrf.CCHeaterPower = rNumericArgs(ccHeatPwrIdx); + thisVrf.NumCompressors = rNumericArgs(numCompIdx); + thisVrf.CompressorSizeRatio = rNumericArgs(compSzRatIdx); + thisVrf.MaxOATCCHeater = rNumericArgs(maxOATccIdx); + + // The FluidTCtrl VRF model is Air cooled + thisVrf.CondenserType = DataHeatBalance::RefrigCondenserType::Air; + thisVrf.CondenserNodeNum = 0; + }; - thisVrfFluidCtrl.CompMaxDeltaP = rNumericArgs(30); + // Read all VRF condenser objects: Algorithm Type 2_physics based model (VRF-FluidTCtrl-HP) + cCurrentModuleObject = "AirConditioner:VariableRefrigerantFlow:FluidTemperatureControl"; + for (int thisNum = 1; thisNum <= state.dataHVACVarRefFlow->NumVRFCond_FluidTCtrl_HP; ++thisNum) { - //@@ The control type - std::string ThermostatPriorityType = "LoadPriority"; // cAlphaArgs( 25 ) - if (Util::SameString(ThermostatPriorityType, "LoadPriority")) { - thisVrfFluidCtrl.ThermostatPriority = ThermostatCtrlType::LoadPriority; - } else if (Util::SameString(ThermostatPriorityType, "ZonePriority")) { - thisVrfFluidCtrl.ThermostatPriority = ThermostatCtrlType::ZonePriority; - } else if (Util::SameString(ThermostatPriorityType, "ThermostatOffsetPriority")) { - thisVrfFluidCtrl.ThermostatPriority = ThermostatCtrlType::ThermostatOffsetPriority; - } else if (Util::SameString(ThermostatPriorityType, "Scheduled")) { - thisVrfFluidCtrl.ThermostatPriority = ThermostatCtrlType::ScheduledPriority; - } else if (Util::SameString(ThermostatPriorityType, "MasterThermostatPriority")) { - thisVrfFluidCtrl.ThermostatPriority = ThermostatCtrlType::MasterThermostatPriority; - if (thisVrfFluidCtrl.MasterZonePtr == 0) { - ShowSevereError(state, cCurrentModuleObject + " = \"" + thisVrfFluidCtrl.Name + "\""); - //** ShowContinueError(state, cAlphaFieldNames( 24 ) + " must be entered when " + cAlphaFieldNames( 25 ) + " = " + cAlphaArgs( 25 ) - //); - ErrorsFound = true; - } - } else { - ShowSevereError(state, cCurrentModuleObject + " = " + thisVrfFluidCtrl.Name); - // ShowContinueError(state, "Illegal " + cAlphaFieldNames( 25 ) + " = " + cAlphaArgs( 25 ) ); - ErrorsFound = true; - } + state.dataInputProcessing->inputProcessor->getObjectItem(state, + cCurrentModuleObject, + thisNum, + cAlphaArgs, + NumAlphas, + rNumericArgs, + NumNums, + IOStat, + lNumericFieldBlanks, + lAlphaFieldBlanks, + cAlphaFieldNames, + cNumericFieldNames); - // The new VRF model is Air cooled - thisVrfFluidCtrl.CondenserType = DataHeatBalance::RefrigCondenserType::Air; - thisVrfFluidCtrl.CondenserNodeNum = 0; + ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)}; - // Evaporative Capacity & Compressor Power Curves corresponding to each Loading Index / compressor speed - int NumOfCompSpd = rNumericArgs(31); - thisVrfFluidCtrl.CompressorSpeed.dimension(NumOfCompSpd); - thisVrfFluidCtrl.OUCoolingCAPFT.dimension(NumOfCompSpd); - thisVrfFluidCtrl.OUCoolingPWRFT.dimension(NumOfCompSpd); - int Count1Index = 31; // the index of the last numeric field before compressor speed entries - int Count2Index = 9; // the index of the last alpha field before capacity/power curves - for (int NumCompSpd = 1; NumCompSpd <= NumOfCompSpd; NumCompSpd++) { - thisVrfFluidCtrl.CompressorSpeed(NumCompSpd) = rNumericArgs(Count1Index + NumCompSpd); + GlobalNames::VerifyUniqueInterObjectName( + state, state.dataHVACVarRefFlow->VrfUniqueNames, cAlphaArgs(1), cCurrentModuleObject, cAlphaFieldNames(1), ErrorsFound); - // Evaporating Capacity Curve - if (!lAlphaFieldBlanks(Count2Index + 2 * NumCompSpd)) { - int indexOUEvapCapCurve = GetCurveIndex(state, cAlphaArgs(Count2Index + 2 * NumCompSpd)); // convert curve name to index number - if (indexOUEvapCapCurve == 0) { // Verify curve name and type - if (lAlphaFieldBlanks(Count2Index + 2 * NumCompSpd)) { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrl.Name + "\", missing"); - ShowContinueError(state, "...required " + cAlphaFieldNames(Count2Index + 2 * NumCompSpd) + " is blank."); - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrl.Name + "\", invalid"); - ShowContinueError(state, - EnergyPlus::format("...not found {}=\"{}\".", - cAlphaFieldNames(Count2Index + 2 * NumCompSpd), - cAlphaArgs(Count2Index + 2 * NumCompSpd))); - } - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - indexOUEvapCapCurve, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfFluidCtrl.Name, // Object Name - cAlphaFieldNames(Count2Index + 2 * NumCompSpd)); // Field Name + int VRFNum = state.dataHVACVarRefFlow->NumVRFCond_SysCurve + thisNum; + auto &thisVrfFluidCtrl = state.dataHVACVarRefFlow->VRF(VRFNum); + thisVrfFluidCtrl.Name = cAlphaArgs(1); + thisVrfFluidCtrl.VRFSystemTypeNum = VRF_HeatPump; + thisVrfFluidCtrl.VRFAlgorithmType = AlgorithmType::FluidTCtrl; + thisVrfFluidCtrl.fuel = Constant::eFuel::Electricity; + thisVrfFluidCtrl.ThermostatPriority = ThermostatCtrlType::LoadPriority; + + // Read common FluidTCtrl fields (avail sched, TU list, refrigerant, capacity/COP, + // OAT ranges, SH/SC, IU config, OU fan, curves, pipes, crank case, condenser type) + readFluidCtrlCommonFields(thisVrfFluidCtrl, + eoh, + /*shIdx=*/7, + /*scIdx=*/8, + /*ouFanPwrIdx=*/15, + /*ouAirFlowIdx=*/16, + /*pipDiaSucIdx=*/17, + /*pipDiaDisIdx=*/17, + /*pipLenIdx=*/18, + /*pipEquLenIdx=*/19, + /*pipHeiIdx=*/20, + /*pipInsThiIdx=*/21, + /*pipInsConIdx=*/22, + /*ccHeatPwrIdx=*/23, + /*numCompIdx=*/24, + /*compSzRatIdx=*/25, + /*maxOATccIdx=*/26); - if (!ErrorsFound) { - thisVrfFluidCtrl.OUCoolingCAPFT(NumCompSpd) = indexOUEvapCapCurve; - } - } - } + // Defrost + readFluidCtrlDefrost(thisVrfFluidCtrl, thisVrfFluidCtrl.Name, 27, 28, 29, cNumericFieldNames(28)); - // Compressor Power Curve - if (!lAlphaFieldBlanks(Count2Index + 2 * NumCompSpd + 1)) { - int indexOUCompPwrCurve = GetCurveIndex(state, cAlphaArgs(Count2Index + 2 * NumCompSpd + 1)); // convert curve name to index number - if (indexOUCompPwrCurve == 0) { // Verify curve name and type - if (lAlphaFieldBlanks(Count2Index + 2 * NumCompSpd + 1)) { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrl.Name + "\", missing"); - ShowContinueError(state, "...required " + cAlphaFieldNames(Count2Index + 2 * NumCompSpd + 1) + " is blank."); - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrl.Name + "\", invalid"); - ShowContinueError(state, - EnergyPlus::format("...not found {}=\"{}\".", - cAlphaFieldNames(Count2Index + 2 * NumCompSpd + 1), - cAlphaArgs(Count2Index + 2 * NumCompSpd + 1))); - } - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - indexOUCompPwrCurve, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfFluidCtrl.Name, // Object Name - cAlphaFieldNames(Count2Index + 2 * NumCompSpd + 1)); // Field Name + thisVrfFluidCtrl.CompMaxDeltaP = rNumericArgs(30); - if (!ErrorsFound) { - thisVrfFluidCtrl.OUCoolingPWRFT(NumCompSpd) = indexOUCompPwrCurve; - } - } - } - } + // Evaporative Capacity & Compressor Power Curves corresponding to each Loading Index / compressor speed + // numeric index 31 = last field before compressor speed entries; alpha index 9 = last field before cap/power curves + readOUCompressorSpeedCurves(thisVrfFluidCtrl, thisVrfFluidCtrl.Name, 31, 9); } // Read all VRF condenser objects: Algorithm Type 2_physics based model (VRF-FluidTCtrl-HR) @@ -2894,82 +2744,38 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) int VRFNum = state.dataHVACVarRefFlow->NumVRFCond_SysCurve + state.dataHVACVarRefFlow->NumVRFCond_FluidTCtrl_HP + thisNum; auto &thisVrfFluidCtrlHR = state.dataHVACVarRefFlow->VRF(VRFNum); - thisVrfFluidCtrlHR.Name = cAlphaArgs(1); - thisVrfFluidCtrlHR.ThermostatPriority = ThermostatCtrlType::LoadPriority; thisVrfFluidCtrlHR.HeatRecoveryUsed = true; thisVrfFluidCtrlHR.VRFSystemTypeNum = VRF_HeatPump; thisVrfFluidCtrlHR.VRFAlgorithmType = AlgorithmType::FluidTCtrl; thisVrfFluidCtrlHR.fuel = Constant::eFuel::Electricity; - if (lAlphaFieldBlanks(2)) { - thisVrfFluidCtrlHR.availSched = Sched::GetScheduleAlwaysOn(state); - } else if ((thisVrfFluidCtrlHR.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2)); - ErrorsFound = true; - } - - thisVrfFluidCtrlHR.ZoneTUListPtr = - Util::FindItemInList(cAlphaArgs(3), state.dataHVACVarRefFlow->TerminalUnitList, state.dataHVACVarRefFlow->NumVRFTULists); - if (thisVrfFluidCtrlHR.ZoneTUListPtr == 0) { - ShowSevereError(state, cCurrentModuleObject + " = \"" + thisVrfFluidCtrlHR.Name + "\""); - ShowContinueError(state, cAlphaFieldNames(3) + " = " + cAlphaArgs(3) + " not found."); - ErrorsFound = true; - } - - // Refrigerant type - thisVrfFluidCtrlHR.refrigName = cAlphaArgs(4); - if ((thisVrfFluidCtrlHR.refrig = Fluid::GetRefrig(state, thisVrfFluidCtrlHR.refrigName)) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(4), cAlphaArgs(4)); - ErrorsFound = true; - } - - thisVrfFluidCtrlHR.RatedEvapCapacity = rNumericArgs(1); - thisVrfFluidCtrlHR.RatedCompPowerPerCapcity = rNumericArgs(2); - thisVrfFluidCtrlHR.RatedCompPower = thisVrfFluidCtrlHR.RatedCompPowerPerCapcity * thisVrfFluidCtrlHR.RatedEvapCapacity; - thisVrfFluidCtrlHR.CoolingCapacity = thisVrfFluidCtrlHR.RatedEvapCapacity; - thisVrfFluidCtrlHR.HeatingCapacity = thisVrfFluidCtrlHR.RatedEvapCapacity * (1 + thisVrfFluidCtrlHR.RatedCompPowerPerCapcity); - thisVrfFluidCtrlHR.RatedHeatCapacity = thisVrfFluidCtrlHR.HeatingCapacity; - - // Reference system COP - thisVrfFluidCtrlHR.CoolingCOP = 1 / thisVrfFluidCtrlHR.RatedCompPowerPerCapcity; - thisVrfFluidCtrlHR.HeatingCOP = 1 / thisVrfFluidCtrlHR.RatedCompPowerPerCapcity + 1; - - // OA temperature range for VRF-HP operations - thisVrfFluidCtrlHR.MinOATCooling = rNumericArgs(3); - thisVrfFluidCtrlHR.MaxOATCooling = rNumericArgs(4); - thisVrfFluidCtrlHR.MinOATHeating = rNumericArgs(5); - thisVrfFluidCtrlHR.MaxOATHeating = rNumericArgs(6); + // Read common FluidTCtrl fields (avail sched, TU list, refrigerant, capacity/COP, + // OAT ranges, SH/SC, IU config, OU fan, curves, pipes, crank case, condenser type) + readFluidCtrlCommonFields(thisVrfFluidCtrlHR, + eoh, + /*shIdx=*/15, + /*scIdx=*/16, + /*ouFanPwrIdx=*/21, + /*ouAirFlowIdx=*/22, + /*pipDiaSucIdx=*/23, + /*pipDiaDisIdx=*/24, + /*pipLenIdx=*/25, + /*pipEquLenIdx=*/26, + /*pipHeiIdx=*/27, + /*pipInsThiIdx=*/28, + /*pipInsConIdx=*/29, + /*ccHeatPwrIdx=*/30, + /*numCompIdx=*/31, + /*compSzRatIdx=*/32, + /*maxOATccIdx=*/33); + + // HR-specific OA temperature range for heat recovery mode thisVrfFluidCtrlHR.MinOATHeatRecovery = rNumericArgs(7); thisVrfFluidCtrlHR.MaxOATHeatRecovery = rNumericArgs(8); - if (thisVrfFluidCtrlHR.MinOATCooling >= thisVrfFluidCtrlHR.MaxOATCooling) { - ShowSevereError(state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\""); - ShowContinueError(state, - EnergyPlus::format("... {} ({:.3T}) must be less than maximum ({:.3T}).", - cNumericFieldNames(3), - thisVrfFluidCtrlHR.MinOATCooling, - thisVrfFluidCtrlHR.MaxOATCooling)); - ErrorsFound = true; - } - if (thisVrfFluidCtrlHR.MinOATHeating >= thisVrfFluidCtrlHR.MaxOATHeating) { - ShowSevereError(state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\""); - ShowContinueError(state, - EnergyPlus::format("... {} ({:.3T}) must be less than maximum ({:.3T}).", - cNumericFieldNames(5), - thisVrfFluidCtrlHR.MinOATHeating, - thisVrfFluidCtrlHR.MaxOATHeating)); - ErrorsFound = true; - } - if (thisVrfFluidCtrlHR.MinOATHeatRecovery >= thisVrfFluidCtrlHR.MaxOATHeatRecovery) { - ShowSevereError(state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\""); - ShowContinueError(state, - EnergyPlus::format("... {} ({:.3T}) must be less than maximum ({:.3T}).", - cNumericFieldNames(7), - thisVrfFluidCtrlHR.MinOATHeating, - thisVrfFluidCtrlHR.MaxOATHeating)); - ErrorsFound = true; - } + checkMinLessThanMax( + thisVrfFluidCtrlHR.Name, thisVrfFluidCtrlHR.MinOATHeatRecovery, thisVrfFluidCtrlHR.MaxOATHeatRecovery, cNumericFieldNames(7)); if (thisVrfFluidCtrlHR.MinOATHeatRecovery < thisVrfFluidCtrlHR.MinOATCooling && thisVrfFluidCtrlHR.MinOATHeatRecovery < thisVrfFluidCtrlHR.MinOATHeating) { ShowWarningError(state, @@ -3003,46 +2809,7 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) ShowContinueError(state, EnergyPlus::format("... adjusted {} = {:.2T} C", cNumericFieldNames(8), thisVrfFluidCtrlHR.MaxOATHeatRecovery)); } - // IU Control Type - if (Util::SameString(cAlphaArgs(5), "VariableTemp")) { - thisVrfFluidCtrlHR.AlgorithmIUCtrl = 1; - } else if (Util::SameString(cAlphaArgs(5), "ConstantTemp")) { - thisVrfFluidCtrlHR.AlgorithmIUCtrl = 2; - } else { - thisVrfFluidCtrlHR.AlgorithmIUCtrl = 1; - } - - // Reference IU Te/Tc for IU Control Algorithm: ConstantTemp - thisVrfFluidCtrlHR.EvapTempFixed = rNumericArgs(9); - thisVrfFluidCtrlHR.CondTempFixed = rNumericArgs(10); - - // Bounds of Te/Tc for IU Control Algorithm: VariableTemp - thisVrfFluidCtrlHR.IUEvapTempLow = rNumericArgs(11); - thisVrfFluidCtrlHR.IUEvapTempHigh = rNumericArgs(12); - thisVrfFluidCtrlHR.IUCondTempLow = rNumericArgs(13); - thisVrfFluidCtrlHR.IUCondTempHigh = rNumericArgs(14); - if (thisVrfFluidCtrlHR.IUEvapTempLow >= thisVrfFluidCtrlHR.IUEvapTempHigh) { - ShowSevereError(state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\""); - ShowContinueError(state, - EnergyPlus::format("... {} ({:.3T}) must be less than maximum ({:.3T}).", - cNumericFieldNames(11), - thisVrfFluidCtrlHR.IUEvapTempLow, - thisVrfFluidCtrlHR.IUEvapTempHigh)); - ErrorsFound = true; - } - if (thisVrfFluidCtrlHR.IUCondTempLow >= thisVrfFluidCtrlHR.IUCondTempHigh) { - ShowSevereError(state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\""); - ShowContinueError(state, - EnergyPlus::format("... {} ({:.3T}) must be less than maximum ({:.3T}).", - cNumericFieldNames(13), - thisVrfFluidCtrlHR.IUCondTempLow, - thisVrfFluidCtrlHR.IUCondTempHigh)); - ErrorsFound = true; - } - - // Reference OU SH/SC - thisVrfFluidCtrlHR.SH = rNumericArgs(15); - thisVrfFluidCtrlHR.SC = rNumericArgs(16); + // HR-specific SH/SC warnings if (thisVrfFluidCtrlHR.SH > 20) { ShowWarningError(state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\", \" " + cNumericFieldNames(15)); ShowContinueError(state, "...is higher than 20C, which is usually the maximum of normal range."); @@ -3052,7 +2819,7 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) ShowContinueError(state, "...is higher than 20C, which is usually the maximum of normal range."); } - // OU Heat Exchanger Rated Bypass Factor + // HR-specific OU Heat Exchanger Rated Bypass Factor thisVrfFluidCtrlHR.RateBFOUEvap = rNumericArgs(17); thisVrfFluidCtrlHR.RateBFOUCond = rNumericArgs(18); @@ -3062,170 +2829,8 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) // HR OU Heat Exchanger Capacity Ratio thisVrfFluidCtrlHR.HROUHexRatio = rNumericArgs(20); - // Get OU fan data - thisVrfFluidCtrlHR.RatedOUFanPowerPerCapcity = rNumericArgs(21); - thisVrfFluidCtrlHR.OUAirFlowRatePerCapcity = rNumericArgs(22); - thisVrfFluidCtrlHR.RatedOUFanPower = thisVrfFluidCtrlHR.RatedOUFanPowerPerCapcity * thisVrfFluidCtrlHR.RatedEvapCapacity; - thisVrfFluidCtrlHR.OUAirFlowRate = thisVrfFluidCtrlHR.OUAirFlowRatePerCapcity * thisVrfFluidCtrlHR.RatedEvapCapacity; - - // OUEvapTempCurve - int indexOUEvapTempCurve = GetCurveIndex(state, cAlphaArgs(6)); // convert curve name to index number - // Verify curve name and type - if (indexOUEvapTempCurve == 0) { - if (lAlphaFieldBlanks(6)) { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrlHR.Name + "\", missing"); - ShowContinueError(state, "...required " + cAlphaFieldNames(6) + " is blank."); - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrlHR.Name + "\", invalid"); - ShowContinueError(state, "...not found " + cAlphaFieldNames(6) + "=\"" + cAlphaArgs(6) + "\"."); - } - ErrorsFound = true; - } else { - if (state.dataCurveManager->curves(indexOUEvapTempCurve)->curveType == Curve::CurveType::Quadratic) { - thisVrfFluidCtrlHR.C1Te = state.dataCurveManager->curves(indexOUEvapTempCurve)->coeff[0]; - thisVrfFluidCtrlHR.C2Te = state.dataCurveManager->curves(indexOUEvapTempCurve)->coeff[1]; - thisVrfFluidCtrlHR.C3Te = state.dataCurveManager->curves(indexOUEvapTempCurve)->coeff[2]; - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrlHR.Name + "\", invalid"); - ShowContinueError( - state, - EnergyPlus::format("...illegal {} type for this object = {}", - cAlphaFieldNames(6), - Curve::objectNames[static_cast(state.dataCurveManager->curves(indexOUEvapTempCurve)->curveType)])); - ShowContinueError(state, "... Curve type must be Quadratic."); - ErrorsFound = true; - } - } - - // OUCondTempCurve - int indexOUCondTempCurve = GetCurveIndex(state, cAlphaArgs(7)); // convert curve name to index number - // Verify curve name and type - if (indexOUCondTempCurve == 0) { - if (lAlphaFieldBlanks(7)) { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrlHR.Name + "\", missing"); - ShowContinueError(state, "...required " + cAlphaFieldNames(7) + " is blank."); - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrlHR.Name + "\", invalid"); - ShowContinueError(state, "...not found " + cAlphaFieldNames(7) + "=\"" + cAlphaArgs(7) + "\"."); - } - ErrorsFound = true; - } else { - if (state.dataCurveManager->curves(indexOUCondTempCurve)->curveType == Curve::CurveType::Quadratic) { - thisVrfFluidCtrlHR.C1Tc = state.dataCurveManager->curves(indexOUCondTempCurve)->coeff[0]; - thisVrfFluidCtrlHR.C2Tc = state.dataCurveManager->curves(indexOUCondTempCurve)->coeff[1]; - thisVrfFluidCtrlHR.C3Tc = state.dataCurveManager->curves(indexOUCondTempCurve)->coeff[2]; - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrlHR.Name + "\", invalid"); - ShowContinueError( - state, - EnergyPlus::format("...illegal {} type for this object = {}", - cAlphaFieldNames(7), - Curve::objectNames[static_cast(state.dataCurveManager->curves(indexOUCondTempCurve)->curveType)])); - ShowContinueError(state, "... Curve type must be Quadratic."); - ErrorsFound = true; - } - } - - // Pipe parameters - thisVrfFluidCtrlHR.RefPipDiaSuc = rNumericArgs(23); - thisVrfFluidCtrlHR.RefPipDiaDis = rNumericArgs(24); - thisVrfFluidCtrlHR.RefPipLen = rNumericArgs(25); - thisVrfFluidCtrlHR.RefPipEquLen = rNumericArgs(26); - thisVrfFluidCtrlHR.RefPipHei = rNumericArgs(27); - thisVrfFluidCtrlHR.RefPipInsThi = rNumericArgs(28); - thisVrfFluidCtrlHR.RefPipInsCon = rNumericArgs(29); - - // Check the RefPipEquLen - if (lNumericFieldBlanks(26) && !lNumericFieldBlanks(25)) { - thisVrfFluidCtrlHR.RefPipEquLen = 1.2 * thisVrfFluidCtrlHR.RefPipLen; - ShowWarningError( - state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\", \" " + cNumericFieldNames(26) + "\" is calculated based on"); - ShowContinueError(state, "...the provided \"" + cNumericFieldNames(25) + "\" value."); - } - if (thisVrfFluidCtrlHR.RefPipEquLen < thisVrfFluidCtrlHR.RefPipLen) { - thisVrfFluidCtrlHR.RefPipEquLen = 1.2 * thisVrfFluidCtrlHR.RefPipLen; - ShowWarningError(state, - cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\", invalid \" " + cNumericFieldNames(26) + "\" value."); - ShowContinueError(state, "...Equivalent length of main pipe should be greater than or equal to the actual length."); - ShowContinueError(state, EnergyPlus::format("...The value is recalculated based on the provided \"{}\" value.", cNumericFieldNames(25))); - } - - // Crank case - thisVrfFluidCtrlHR.CCHeaterPower = rNumericArgs(30); - thisVrfFluidCtrlHR.NumCompressors = rNumericArgs(31); - thisVrfFluidCtrlHR.CompressorSizeRatio = rNumericArgs(32); - thisVrfFluidCtrlHR.MaxOATCCHeater = rNumericArgs(33); - // Defrost - if (!lAlphaFieldBlanks(8)) { - if (Util::SameString(cAlphaArgs(8), "ReverseCycle")) { - thisVrfFluidCtrlHR.DefrostStrategy = StandardRatings::DefrostStrat::ReverseCycle; - } - if (Util::SameString(cAlphaArgs(8), "Resistive")) { - thisVrfFluidCtrlHR.DefrostStrategy = StandardRatings::DefrostStrat::Resistive; - } - if (thisVrfFluidCtrlHR.DefrostStrategy == StandardRatings::DefrostStrat::Invalid) { - ShowSevereError( - state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\" " + cAlphaFieldNames(8) + " not found: " + cAlphaArgs(8)); - ErrorsFound = true; - } - } else { - thisVrfFluidCtrlHR.DefrostStrategy = StandardRatings::DefrostStrat::ReverseCycle; - } - - if (!lAlphaFieldBlanks(9)) { - if (Util::SameString(cAlphaArgs(9), "Timed")) { - thisVrfFluidCtrlHR.DefrostControl = StandardRatings::HPdefrostControl::Timed; - } - if (Util::SameString(cAlphaArgs(9), "OnDemand")) { - thisVrfFluidCtrlHR.DefrostControl = StandardRatings::HPdefrostControl::OnDemand; - } - if (thisVrfFluidCtrlHR.DefrostControl == StandardRatings::HPdefrostControl::Invalid) { - ShowSevereError( - state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\" " + cAlphaFieldNames(9) + " not found: " + cAlphaArgs(9)); - ErrorsFound = true; - } - } else { - thisVrfFluidCtrlHR.DefrostControl = StandardRatings::HPdefrostControl::Timed; - } - - if (!lAlphaFieldBlanks(10)) { - thisVrfFluidCtrlHR.DefrostEIRPtr = GetCurveIndex(state, cAlphaArgs(10)); - if (thisVrfFluidCtrlHR.DefrostEIRPtr > 0) { - // Verify Curve Object, expected type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - thisVrfFluidCtrlHR.DefrostEIRPtr, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfFluidCtrlHR.Name, // Object Name - cAlphaFieldNames(10)); // Field Name - } else { - if (thisVrfFluidCtrlHR.DefrostStrategy == StandardRatings::DefrostStrat::ReverseCycle && - thisVrfFluidCtrlHR.DefrostControl == StandardRatings::HPdefrostControl::OnDemand) { - ShowSevereError(state, - cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\" " + cAlphaFieldNames(10) + - " not found:" + cAlphaArgs(10)); - ErrorsFound = true; - } - } - } else { - if (thisVrfFluidCtrlHR.DefrostStrategy == StandardRatings::DefrostStrat::ReverseCycle && - thisVrfFluidCtrlHR.DefrostControl == StandardRatings::HPdefrostControl::OnDemand) { - ShowSevereError( - state, cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\" " + cAlphaFieldNames(10) + " not found:" + cAlphaArgs(10)); - ErrorsFound = true; - } - } - - thisVrfFluidCtrlHR.DefrostFraction = rNumericArgs(34); - thisVrfFluidCtrlHR.DefrostCapacity = rNumericArgs(35); - thisVrfFluidCtrlHR.MaxOATDefrost = rNumericArgs(36); - if (thisVrfFluidCtrlHR.DefrostCapacity == 0.0 && thisVrfFluidCtrlHR.DefrostStrategy == StandardRatings::DefrostStrat::Resistive) { - ShowWarningError(state, - cCurrentModuleObject + ", \"" + thisVrfFluidCtrlHR.Name + "\" " + cNumericFieldNames(35) + - " = 0.0 for defrost strategy = RESISTIVE."); - } + readFluidCtrlDefrost(thisVrfFluidCtrlHR, thisVrfFluidCtrlHR.Name, 34, 35, 36, cNumericFieldNames(35)); // HR mode transition thisVrfFluidCtrlHR.HRInitialCoolCapFrac = rNumericArgs(37); @@ -3242,80 +2847,9 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) thisVrfFluidCtrlHR.EffCompInverter = rNumericArgs(46); thisVrfFluidCtrlHR.CoffEvapCap = rNumericArgs(47); - // The new VRF model is Air cooled - thisVrfFluidCtrlHR.CondenserType = DataHeatBalance::RefrigCondenserType::Air; - thisVrfFluidCtrlHR.CondenserNodeNum = 0; - // Evaporative Capacity & Compressor Power Curves corresponding to each Loading Index / compressor speed - int NumOfCompSpd = rNumericArgs(48); - thisVrfFluidCtrlHR.CompressorSpeed.dimension(NumOfCompSpd); - thisVrfFluidCtrlHR.OUCoolingCAPFT.dimension(NumOfCompSpd); - thisVrfFluidCtrlHR.OUCoolingPWRFT.dimension(NumOfCompSpd); - int Count1Index = 48; // the index of the last numeric field before compressor speed entries - int Count2Index = 9; // the index of the last alpha field before capacity/power curves - for (int NumCompSpd = 1; NumCompSpd <= NumOfCompSpd; NumCompSpd++) { - thisVrfFluidCtrlHR.CompressorSpeed(NumCompSpd) = rNumericArgs(Count1Index + NumCompSpd); - - // Evaporating Capacity Curve - if (!lAlphaFieldBlanks(Count2Index + 2 * NumCompSpd)) { - int indexOUEvapCapCurve = GetCurveIndex(state, cAlphaArgs(Count2Index + 2 * NumCompSpd)); // convert curve name to index number - if (indexOUEvapCapCurve == 0) { // Verify curve name and type - if (lAlphaFieldBlanks(Count2Index + 2 * NumCompSpd)) { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrlHR.Name + "\", missing"); - ShowContinueError(state, "...required " + cAlphaFieldNames(Count2Index + 2 * NumCompSpd) + " is blank."); - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrlHR.Name + "\", invalid"); - ShowContinueError(state, - EnergyPlus::format("...not found {}=\"{}\".", - cAlphaFieldNames(Count2Index + 2 * NumCompSpd), - cAlphaArgs(Count2Index + 2 * NumCompSpd))); - } - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - indexOUEvapCapCurve, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfFluidCtrlHR.Name, // Object Name - cAlphaFieldNames(Count2Index + 2 * NumCompSpd)); // Field Name - - if (!ErrorsFound) { - thisVrfFluidCtrlHR.OUCoolingCAPFT(NumCompSpd) = indexOUEvapCapCurve; - } - } - } - - // Compressor Power Curve - if (!lAlphaFieldBlanks(Count2Index + 2 * NumCompSpd + 1)) { - int indexOUCompPwrCurve = GetCurveIndex(state, cAlphaArgs(Count2Index + 2 * NumCompSpd + 1)); // convert curve name to index number - if (indexOUCompPwrCurve == 0) { // Verify curve name and type - if (lAlphaFieldBlanks(Count2Index + 2 * NumCompSpd + 1)) { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrlHR.Name + "\", missing"); - ShowContinueError(state, "...required " + cAlphaFieldNames(Count2Index + 2 * NumCompSpd + 1) + " is blank."); - } else { - ShowSevereError(state, std::string{RoutineName} + cCurrentModuleObject + "=\"" + thisVrfFluidCtrlHR.Name + "\", invalid"); - ShowContinueError(state, - EnergyPlus::format("...not found {}=\"{}\".", - cAlphaFieldNames(Count2Index + 2 * NumCompSpd + 1), - cAlphaArgs(Count2Index + 2 * NumCompSpd + 1))); - } - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - indexOUCompPwrCurve, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisVrfFluidCtrlHR.Name, // Object Name - cAlphaFieldNames(Count2Index + 2 * NumCompSpd + 1)); // Field Name - - if (!ErrorsFound) { - thisVrfFluidCtrlHR.OUCoolingPWRFT(NumCompSpd) = indexOUCompPwrCurve; - } - } - } - } + // numeric index 48 = last field before compressor speed entries; alpha index 9 = last field before cap/power curves + readOUCompressorSpeedCurves(thisVrfFluidCtrlHR, thisVrfFluidCtrlHR.Name, 48, 9); } cCurrentModuleObject = "ZoneHVAC:TerminalUnit:VariableRefrigerantFlow"; @@ -3574,60 +3108,16 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) } if (thisVrfTU.VRFSysNum > 0) { - SetDXCoolingCoilData( - state, thisVrfTU.CoolCoilIndex, ErrorsFound, _, state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).CondenserType); - SetDXCoolingCoilData(state, - thisVrfTU.CoolCoilIndex, - ErrorsFound, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).CondenserNodeNum); - SetDXCoolingCoilData(state, - thisVrfTU.CoolCoilIndex, - ErrorsFound, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MaxOATCCHeater); - SetDXCoolingCoilData(state, - thisVrfTU.CoolCoilIndex, - ErrorsFound, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MinOATCooling); - SetDXCoolingCoilData(state, - thisVrfTU.CoolCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MaxOATCooling); - - state.dataDXCoils->DXCoil(thisVrfTU.CoolCoilIndex).VRFIUPtr = VRFTUNum; - state.dataDXCoils->DXCoil(thisVrfTU.CoolCoilIndex).VRFOUPtr = thisVrfTU.VRFSysNum; - state.dataDXCoils->DXCoil(thisVrfTU.CoolCoilIndex).SupplyFanIndex = thisVrfTU.FanIndex; - - if (thisVrfTU.FanIndex > 0) { - state.dataDXCoils->DXCoil(thisVrfTU.CoolCoilIndex).RatedAirVolFlowRate(1) = - state.dataFans->fans(thisVrfTU.FanIndex)->maxAirFlowRate; - } else { - state.dataDXCoils->DXCoil(thisVrfTU.CoolCoilIndex).RatedAirVolFlowRate(1) = AutoSize; - } - + auto const &vrfCond = state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum); + setVRFCoolingCoilData(state, thisVrfTU.CoolCoilIndex, ErrorsFound, vrfCond); + setFluidTCtrlCoilMembers(state, thisVrfTU.CoolCoilIndex, VRFTUNum, thisVrfTU.VRFSysNum, thisVrfTU.FanIndex); } else { - ShowSevereError(state, cCurrentModuleObject + " \"" + thisVrfTU.Name + "\""); - ShowContinueError( - state, "... when checking " + HVAC::cAllCoilTypes(thisVrfTU.DXCoolCoilType_Num) + " \"" + cAlphaArgs(12) + "\""); - ShowContinueError(state, "... terminal unit not connected to condenser."); - ShowContinueError(state, "... check that terminal unit is specified in a terminal unit list object."); - ShowContinueError(state, - "... also check that the terminal unit list name is specified in an " - "AirConditioner:VariableRefrigerantFlow object."); - ErrorsFound = true; + showTUNotConnectedError(state, + ErrorsFound, + cCurrentModuleObject, + thisVrfTU.Name, + HVAC::cAllCoilTypes(thisVrfTU.DXCoolCoilType_Num), + cAlphaArgs(12)); } } else { ShowSevereError(state, cCurrentModuleObject + " \"" + thisVrfTU.Name + "\""); @@ -3656,29 +3146,7 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) ShowContinueError(state, "...occurs in " + cCurrentModuleObject + " \"" + thisVrfTU.Name + "\""); } - SetDXCoolingCoilData( - state, thisVrfTU.CoolCoilIndex, ErrorsFound, _, state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).CondenserType); - SetDXCoolingCoilData( - state, thisVrfTU.CoolCoilIndex, ErrorsFound, _, _, state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).CondenserNodeNum); - SetDXCoolingCoilData( - state, thisVrfTU.CoolCoilIndex, ErrorsFound, _, _, _, state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MaxOATCCHeater); - SetDXCoolingCoilData(state, - thisVrfTU.CoolCoilIndex, - ErrorsFound, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MinOATCooling); - SetDXCoolingCoilData(state, - thisVrfTU.CoolCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MaxOATCooling); + setVRFCoolingCoilData(state, thisVrfTU.CoolCoilIndex, ErrorsFound, state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum)); } else { ShowSevereError(state, cCurrentModuleObject + " \"" + thisVrfTU.Name + "\""); @@ -3687,13 +3155,8 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) } } } else { - ShowSevereError(state, cCurrentModuleObject + " \"" + thisVrfTU.Name + "\""); - ShowContinueError(state, "... when checking " + HVAC::cAllCoilTypes(thisVrfTU.DXCoolCoilType_Num) + " \"" + cAlphaArgs(12) + "\""); - ShowContinueError(state, "... terminal unit not connected to condenser."); - ShowContinueError(state, "... check that terminal unit is specified in a terminal unit list object."); - ShowContinueError( - state, "... also check that the terminal unit list name is specified in an AirConditioner:VariableRefrigerantFlow object."); - ErrorsFound = true; + showTUNotConnectedError( + state, ErrorsFound, cCurrentModuleObject, thisVrfTU.Name, HVAC::cAllCoilTypes(thisVrfTU.DXCoolCoilType_Num), cAlphaArgs(12)); } } @@ -3737,220 +3200,18 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) } if (thisVrfTU.VRFSysNum > 0) { - SetDXCoolingCoilData( - state, thisVrfTU.HeatCoilIndex, ErrorsFound, _, state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).CondenserType); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).CondenserNodeNum); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MaxOATCCHeater); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MinOATHeating); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MaxOATHeating); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).HeatingPerformanceOATType); - // Set defrost controls in child object to trip child object defrost calculations - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).DefrostStrategy); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).DefrostControl); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).DefrostEIRPtr); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).DefrostFraction); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MaxOATDefrost); - // If defrost is disabled in the VRF condenser, it must be disabled in the DX coil - // Defrost primarily handled in parent object, set defrost capacity to 1 to avoid autosizing. - // Defrost capacity is used for nothing more than setting defrost power/consumption report - // variables which are not reported. The coil's defrost algorithm IS used to derate the coil - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - 1.0); // DefrostCapacity=1.0 - - state.dataDXCoils->DXCoil(thisVrfTU.HeatCoilIndex).VRFIUPtr = VRFTUNum; - state.dataDXCoils->DXCoil(thisVrfTU.HeatCoilIndex).VRFOUPtr = thisVrfTU.VRFSysNum; - state.dataDXCoils->DXCoil(thisVrfTU.HeatCoilIndex).SupplyFanIndex = thisVrfTU.FanIndex; - - if (thisVrfTU.FanIndex > 0) { - state.dataDXCoils->DXCoil(thisVrfTU.HeatCoilIndex).RatedAirVolFlowRate(1) = - state.dataFans->fans(thisVrfTU.FanIndex)->maxAirFlowRate; - } else { - state.dataDXCoils->DXCoil(thisVrfTU.HeatCoilIndex).RatedAirVolFlowRate(1) = AutoSize; - } - - // Terminal unit heating to cooling sizing ratio has precedence over VRF system sizing ratio - if (thisVrfTU.HeatingCapacitySizeRatio > 1.0) { - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - thisVrfTU.HeatingCapacitySizeRatio); - } else if (state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).HeatingCapacitySizeRatio > 1.0) { - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).HeatingCapacitySizeRatio); - } + auto const &vrfCond = state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum); + setVRFHeatingCoilData(state, thisVrfTU.HeatCoilIndex, ErrorsFound, vrfCond); + setFluidTCtrlCoilMembers(state, thisVrfTU.HeatCoilIndex, VRFTUNum, thisVrfTU.VRFSysNum, thisVrfTU.FanIndex); + setVRFHeatSizeRatio( + state, thisVrfTU.HeatCoilIndex, ErrorsFound, thisVrfTU.HeatingCapacitySizeRatio, vrfCond.HeatingCapacitySizeRatio); } else { - ShowSevereError(state, cCurrentModuleObject + " \"" + thisVrfTU.Name + "\""); - ShowContinueError( - state, "... when checking " + HVAC::cAllCoilTypes(thisVrfTU.DXHeatCoilType_Num) + " \"" + cAlphaArgs(14) + "\""); - ShowContinueError(state, "... terminal unit not connected to condenser."); - ShowContinueError(state, "... check that terminal unit is specified in a terminal unit list object."); - ShowContinueError(state, - "... also check that the terminal unit list name is specified in an " - "AirConditioner:VariableRefrigerantFlow object."); - ErrorsFound = true; + showTUNotConnectedError(state, + ErrorsFound, + cCurrentModuleObject, + thisVrfTU.Name, + HVAC::cAllCoilTypes(thisVrfTU.DXHeatCoilType_Num), + cAlphaArgs(14)); } } else { ShowSevereError(state, cCurrentModuleObject + " \"" + thisVrfTU.Name + "\""); @@ -3978,177 +3239,11 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) ShowContinueError(state, "...occurs in " + cCurrentModuleObject + " \"" + thisVrfTU.Name + "\""); } - SetDXCoolingCoilData( - state, thisVrfTU.HeatCoilIndex, ErrorsFound, _, state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).CondenserType); - SetDXCoolingCoilData( - state, thisVrfTU.HeatCoilIndex, ErrorsFound, _, _, state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).CondenserNodeNum); - SetDXCoolingCoilData( - state, thisVrfTU.HeatCoilIndex, ErrorsFound, _, _, _, state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MaxOATCCHeater); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MinOATHeating); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).HeatingPerformanceOATType); - // Set defrost controls in child object to trip child object defrost calculations - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).DefrostStrategy); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).DefrostControl); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).DefrostEIRPtr); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).DefrostFraction); - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).MaxOATDefrost); - // If defrost is disabled in the VRF condenser, it must be disabled in the DX coil - // Defrost primarily handled in parent object, set defrost capacity to 1 to avoid autosizing. - // Defrost capacity is used for nothing more than setting defrost power/consumption report - // variables which are not reported. The coil's defrost algorithm IS used to derate the coil - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - 1.0); // DefrostCapacity=1.0 - // Terminal unit heating to cooling sizing ratio has precedence over VRF system sizing ratio - if (thisVrfTU.HeatingCapacitySizeRatio > 1.0) { - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - thisVrfTU.HeatingCapacitySizeRatio); - } else if (state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).HeatingCapacitySizeRatio > 1.0) { - SetDXCoolingCoilData(state, - thisVrfTU.HeatCoilIndex, - ErrorsFound, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - _, - state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum).HeatingCapacitySizeRatio); + { + auto const &vrfCond = state.dataHVACVarRefFlow->VRF(thisVrfTU.VRFSysNum); + setVRFHeatingCoilData(state, thisVrfTU.HeatCoilIndex, ErrorsFound, vrfCond); + setVRFHeatSizeRatio( + state, thisVrfTU.HeatCoilIndex, ErrorsFound, thisVrfTU.HeatingCapacitySizeRatio, vrfCond.HeatingCapacitySizeRatio); } // Check VRF DX heating coil heating capacity as a function of temperature performance curve. Only report here for // biquadratic curve type. @@ -4186,13 +3281,8 @@ void GetVRFInputData(EnergyPlusData &state, bool &ErrorsFound) } } } else { - ShowSevereError(state, cCurrentModuleObject + " \"" + thisVrfTU.Name + "\""); - ShowContinueError(state, "... when checking " + HVAC::cAllCoilTypes(thisVrfTU.DXHeatCoilType_Num) + " \"" + cAlphaArgs(14) + "\""); - ShowContinueError(state, "... terminal unit not connected to condenser."); - ShowContinueError(state, "... check that terminal unit is specified in a terminal unit list object."); - ShowContinueError( - state, "... also check that the terminal unit list name is specified in an AirConditioner:VariableRefrigerantFlow object."); - ErrorsFound = true; + showTUNotConnectedError( + state, ErrorsFound, cCurrentModuleObject, thisVrfTU.Name, HVAC::cAllCoilTypes(thisVrfTU.DXHeatCoilType_Num), cAlphaArgs(14)); } } @@ -5562,6 +4652,289 @@ void CheckVRFTUNodeConnections(EnergyPlusData &state, int const VRFTUNum, bool & } } +// Helper: warn and reset OA flow to zero when VRF TU connected to DOAS +static void warnAndResetDOASOutdoorAirFlow( + EnergyPlusData &state, std::string_view cCurrentModuleObject, std::string_view tuName, Real64 &flowRate, std::string_view flowLabel) +{ + if (flowRate != 0) { + ShowWarningError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, tuName)); + ShowContinueError(state, EnergyPlus::format(".. {} must be zero when {}", flowLabel, cCurrentModuleObject)); + ShowContinueError(state, "..object is connected to central dedicated outdoor air system via AirTerminal:SingleDuct:Mixer"); + ShowContinueError(state, EnergyPlus::format(".. {} is set to 0 and simulation continues.", flowLabel)); + flowRate = 0; + } +} + +// Helper: warn when OAT exceeds VRF cooling/heating mode limits +static void warnOATLimitExceeded(EnergyPlusData &state, + int const VRFCond, + Real64 const OutsideDryBulbTemp, + std::string_view modeLabel, + Real64 const minOAT, + Real64 const maxOAT, + int &tempLimitIndex, + Array1D_bool const &coilAvailable) +{ + if (!any(coilAvailable)) { + return; + } + + if (tempLimitIndex == 0) { + ShowWarningMessage(state, + EnergyPlus::format("{} \"{}\".", + cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), + state.dataHVACVarRefFlow->VRF(VRFCond).Name)); + ShowContinueError(state, + EnergyPlus::format("...InitVRF: VRF Heat Pump Min/Max Operating Temperature in {} Mode Limits have been exceeded " + "and VRF system is disabled.", + modeLabel)); + if (state.dataHVACVarRefFlow->VRF(VRFCond).CondenserType == DataHeatBalance::RefrigCondenserType::Water) { + ShowContinueError(state, EnergyPlus::format("... Outdoor Unit Inlet Water Temperature = {:.3T}", OutsideDryBulbTemp)); + } else { + ShowContinueError(state, EnergyPlus::format("... Outdoor Unit Inlet Air Temperature = {:.3T}", OutsideDryBulbTemp)); + } + ShowContinueError(state, EnergyPlus::format("... {} Minimum Outdoor Unit Inlet Temperature = {:.3T}", modeLabel, minOAT)); + ShowContinueError(state, EnergyPlus::format("... {} Maximum Outdoor Unit Inlet Temperature = {:.3T}", modeLabel, maxOAT)); + ShowContinueErrorTimeStamp(state, EnergyPlus::format("... Check VRF Heat Pump Min/Max Outdoor Temperature in {} Mode limits.", modeLabel)); + } + ShowRecurringWarningErrorAtEnd(state, + std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)) + " \"" + + state.dataHVACVarRefFlow->VRF(VRFCond).Name + "\" -- Exceeded VRF Heat Pump min/max " + + std::string(modeLabel) + " temperature limit error continues...", + tempLimitIndex, + OutsideDryBulbTemp, + OutsideDryBulbTemp); +} + +// Helper: set VRF terminal unit node mass flow rates based on OA mixer presence. +// When an OA mixer is used, sets the return node and outside air node flow rates. +// Otherwise, sets the inlet node flow rate (unless the TU is in an OA system). +static void setVRFTUNodeMassFlowRate( + EnergyPlusData &state, int const VRFTUNum, int const InNode, int const OutsideAirNode, Real64 const mainAirMassFlow, Real64 const oaMassFlow) +{ + if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerUsed) { + state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerRetNodeNum).MassFlowRate = mainAirMassFlow; + state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = oaMassFlow; + } else { + if (!state.dataHVACVarRefFlow->VRFTU(VRFTUNum).isInOASys) { + state.dataLoopNodes->Node(InNode).MassFlowRate = mainAirMassFlow; + } + } +} + +// Helper: search zone equipment configs for a zone node matching the given TU node. +// Searches exhaust nodes when isExhaustSearch is true, inlet nodes otherwise. +// Returns the zone air node number if found, or 0 if not found. +static int findMatchingZoneAirNode(EnergyPlusData &state, int const tuNodeNum, bool const isExhaustSearch) +{ + for (int CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { + if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) { + continue; + } + int const numNodes = isExhaustSearch ? state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumExhaustNodes + : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; + for (int NodeNum = 1; NodeNum <= numNodes; ++NodeNum) { + int const zoneNode = isExhaustSearch ? state.dataZoneEquip->ZoneEquipConfig(CtrlZone).ExhaustNode(NodeNum) + : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(NodeNum); + if (tuNodeNum == zoneNode) { + return state.dataZoneEquip->ZoneEquipConfig(CtrlZone).ZoneNode; + } + } + } + return 0; +} + +// Helper: check OAT limits for a given VRF operating mode and optionally switch to the opposite mode. +// When the current mode's OAT is out of range, it disables the current mode and checks whether +// the opposite mode can be enabled based on thermostat priority and OAT limits. +static void checkOATLimitAndSwitchMode(EnergyPlusData &state, + int const VRFCond, + int const TUListIndex, + Real64 const OutsideDryBulbTemp, + bool const isCoolingMode) // true = current mode is cooling, false = heating +{ + auto &vrf = state.dataHVACVarRefFlow->VRF(VRFCond); + auto &tuList = state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex); + + // Current mode parameters + Real64 const curMinOAT = isCoolingMode ? vrf.MinOATCooling : vrf.MinOATHeating; + Real64 const curMaxOAT = isCoolingMode ? vrf.MaxOATCooling : vrf.MaxOATHeating; + auto const &curCoilPresent = isCoolingMode ? tuList.CoolingCoilPresent : tuList.HeatingCoilPresent; + bool &curLoad = isCoolingMode ? state.dataHVACVarRefFlow->CoolingLoad(VRFCond) : state.dataHVACVarRefFlow->HeatingLoad(VRFCond); + + // Opposite mode parameters + Real64 const oppMinOAT = isCoolingMode ? vrf.MinOATHeating : vrf.MinOATCooling; + Real64 const oppMaxOAT = isCoolingMode ? vrf.MaxOATHeating : vrf.MaxOATCooling; + auto const &oppCoilPresent = isCoolingMode ? tuList.HeatingCoilPresent : tuList.CoolingCoilPresent; + bool &oppLoad = isCoolingMode ? state.dataHVACVarRefFlow->HeatingLoad(VRFCond) : state.dataHVACVarRefFlow->CoolingLoad(VRFCond); + + // Warning parameters for current mode + std::string_view modeLabel = isCoolingMode ? "Cooling" : "Heating"; + int &tempLimitIndex = isCoolingMode ? vrf.CoolingMaxTempLimitIndex : vrf.HeatingMaxTempLimitIndex; + auto const &coilAvailable = isCoolingMode ? tuList.CoolingCoilAvailable : tuList.HeatingCoilAvailable; + + if ((OutsideDryBulbTemp < curMinOAT || OutsideDryBulbTemp > curMaxOAT) && any(curCoilPresent)) { + curLoad = false; + // Test if opposite load exists, account for thermostat control type + bool EnableSystem = false; + switch (vrf.ThermostatPriority) { + case ThermostatCtrlType::LoadPriority: + case ThermostatCtrlType::ZonePriority: { + if (isCoolingMode) { + if (state.dataHVACVarRefFlow->SumHeatingLoads(VRFCond) > 0.0) { + EnableSystem = true; + } + } else { + if (state.dataHVACVarRefFlow->SumCoolingLoads(VRFCond) < 0.0) { + EnableSystem = true; + } + } + } break; + case ThermostatCtrlType::ThermostatOffsetPriority: { + if (isCoolingMode) { + if (state.dataHVACVarRefFlow->MinDeltaT(VRFCond) < 0.0) { + EnableSystem = true; + } + } else { + if (state.dataHVACVarRefFlow->MaxDeltaT(VRFCond) > 0.0) { + EnableSystem = true; + } + } + } break; + case ThermostatCtrlType::ScheduledPriority: + case ThermostatCtrlType::MasterThermostatPriority: { + // can't switch modes if scheduled or master TSTAT used + } break; + default: + break; + } + if (EnableSystem) { + if ((OutsideDryBulbTemp >= oppMinOAT && OutsideDryBulbTemp <= oppMaxOAT) && any(oppCoilPresent)) { + oppLoad = true; + } else { + warnOATLimitExceeded(state, VRFCond, OutsideDryBulbTemp, modeLabel, curMinOAT, curMaxOAT, tempLimitIndex, coilAvailable); + } + } else { + warnOATLimitExceeded(state, VRFCond, OutsideDryBulbTemp, modeLabel, curMinOAT, curMaxOAT, tempLimitIndex, coilAvailable); + } + } +} + +// Helper: dispatch CalcVRF or CalcVRF_FluidTCtrl with zero load (coil-off capacity test) +static void calcVRFCoilOff(EnergyPlusData &state, + int const VRFTUNum, + int const VRFCond, + bool const FirstHVACIteration, + Real64 &TempOutput, + Real64 &OnOffAirFlowRatio, + Real64 &SuppHeatCoilLoad) +{ + if (state.dataHVACVarRefFlow->VRF(VRFCond).VRFAlgorithmType == AlgorithmType::FluidTCtrl) { + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF_FluidTCtrl( + state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); + } else { + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF(state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); + } +} + +// Helper: warn and cap when a VRF TU flow rate exceeds its limit +static void warnAndCapFlowRate(EnergyPlusData &state, + std::string_view tuType, + std::string_view tuName, + Real64 &flowRate, + Real64 const limitRate, + std::string_view comparisonMsg, + std::string_view flowLabel, + Real64 const flowVal, + std::string_view limitLabel, + Real64 const limitVal, + std::string_view reductionMsg) +{ + if (flowRate > limitRate) { + ShowWarningError(state, EnergyPlus::format("InitVRF: VRF Terminal Unit = [{}, \"{}\"]", tuType, tuName)); + ShowContinueError(state, std::string(comparisonMsg)); + ShowContinueError(state, EnergyPlus::format("... {} = {:.4R} m3/s", flowLabel, flowVal)); + ShowContinueError(state, EnergyPlus::format("... {} = {:.4R} m3/s", limitLabel, limitVal)); + ShowContinueError(state, std::string(reductionMsg)); + flowRate = limitRate; + } +} + +// Helper: When a VRF TU coil-off output overshoots the zone setpoint, +// switch air flow rates to the target mode, re-evaluate coil-off output, +// and set the zone load request and heat-recovery flags accordingly. + +// Helper: Set the 6 global VRF compressor flow-rate variables for cooling mode. +static void setVRFCompFlowsCooling(EnergyPlusData &state, int const VRFTUNum) +{ + auto &vrfTU = state.dataHVACVarRefFlow->VRFTU(VRFTUNum); + state.dataHVACVarRefFlow->CompOnMassFlow = vrfTU.MaxCoolAirMassFlow; + state.dataHVACVarRefFlow->CompOffMassFlow = vrfTU.MaxNoCoolAirMassFlow; + state.dataHVACVarRefFlow->OACompOnMassFlow = vrfTU.CoolOutAirMassFlow; + state.dataHVACVarRefFlow->OACompOffMassFlow = vrfTU.NoCoolHeatOutAirMassFlow; + state.dataHVACVarRefFlow->CompOnFlowRatio = vrfTU.CoolingSpeedRatio; + state.dataHVACVarRefFlow->CompOffFlowRatio = vrfTU.NoCoolingSpeedRatio; +} + +// Helper: Set the 6 global VRF compressor flow-rate variables for heating mode. +static void setVRFCompFlowsHeating(EnergyPlusData &state, int const VRFTUNum) +{ + auto &vrfTU = state.dataHVACVarRefFlow->VRFTU(VRFTUNum); + state.dataHVACVarRefFlow->CompOnMassFlow = vrfTU.MaxHeatAirMassFlow; + state.dataHVACVarRefFlow->CompOffMassFlow = vrfTU.MaxNoHeatAirMassFlow; + state.dataHVACVarRefFlow->OACompOnMassFlow = vrfTU.HeatOutAirMassFlow; + state.dataHVACVarRefFlow->OACompOffMassFlow = vrfTU.NoCoolHeatOutAirMassFlow; + state.dataHVACVarRefFlow->CompOnFlowRatio = vrfTU.HeatingSpeedRatio; + state.dataHVACVarRefFlow->CompOffFlowRatio = vrfTU.NoHeatingSpeedRatio; +} + +static void adjustVRFOvershootFlowAndLoad(EnergyPlusData &state, + int const VRFTUNum, + int const VRFCond, + int const InNode, + int const TUListIndex, + int const IndexToTUInTUList, + bool const FirstHVACIteration, + bool const overshootIsHeating, + Real64 const LoadSP, + Real64 &TempOutput, + Real64 &OnOffAirFlowRatio, + Real64 &QZnReq) +{ + auto &vrfTU = state.dataHVACVarRefFlow->VRFTU(VRFTUNum); + auto &tuList = state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex); + + Real64 targetRetFlow = overshootIsHeating ? vrfTU.MaxHeatAirMassFlow : vrfTU.MaxCoolAirMassFlow; + Real64 targetOAFlow = overshootIsHeating ? vrfTU.HeatOutAirMassFlow : vrfTU.CoolOutAirMassFlow; + bool lastModeWasTarget = + overshootIsHeating ? state.dataHVACVarRefFlow->LastModeHeating(VRFCond) : state.dataHVACVarRefFlow->LastModeCooling(VRFCond); + + Real64 SuppHeatCoilLoad = 0.0; + + if (!lastModeWasTarget) { + if (vrfTU.OAMixerUsed) { + state.dataLoopNodes->Node(vrfTU.VRFTUOAMixerRetNodeNum).MassFlowRate = targetRetFlow; + state.dataLoopNodes->Node(vrfTU.VRFTUOAMixerOANodeNum).MassFlowRate = targetOAFlow; + MixedAir::SimOAMixer(state, vrfTU.OAMixerName, vrfTU.OAMixerIndex); + } else { + state.dataLoopNodes->Node(InNode).MassFlowRate = targetRetFlow; + } + + calcVRFCoilOff(state, VRFTUNum, VRFCond, FirstHVACIteration, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); + + bool stillOvershoots = overshootIsHeating ? (TempOutput < LoadSP) : (TempOutput > LoadSP); + if (stillOvershoots) { + QZnReq = LoadSP; + tuList.HRHeatRequest(IndexToTUInTUList) = overshootIsHeating; + tuList.HRCoolRequest(IndexToTUInTUList) = !overshootIsHeating; + } + } else { + QZnReq = LoadSP; + tuList.HRHeatRequest(IndexToTUInTUList) = overshootIsHeating; + tuList.HRCoolRequest(IndexToTUInTUList) = !overshootIsHeating; + } +} + void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool const FirstHVACIteration, Real64 &OnOffAirFlowRatio, Real64 &QZnReq) { @@ -5602,7 +4975,6 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool Real64 TempOutput; // Sensible output of TU Real64 LoadToCoolingSP; // thermostat load to cooling setpoint (W) Real64 LoadToHeatingSP; // thermostat load to heating setpoint (W) - bool EnableSystem; // use to turn on secondary operating mode if OA temp limits exceeded bool ErrorsFound; // flag returned from mining call Real64 rho; // density of water (kg/m3) Real64 OutsideDryBulbTemp; // Outdoor air temperature at external node height @@ -6209,24 +5581,10 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).isInZone && (!state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ATMixerExists || state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ATMixerType == HVAC::MixerType::SupplySide)) { - bool ZoneNodeNotFound = true; - for (int CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) { - continue; - } - for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumExhaustNodes; ++NodeNum) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUInletNodeNum == - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).ExhaustNode(NodeNum)) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneAirNode = state.dataZoneEquip->ZoneEquipConfig(CtrlZone).ZoneNode; - ZoneNodeNotFound = false; - break; - } - } - if (!ZoneNodeNotFound) { - break; - } - } - if (ZoneNodeNotFound && !state.dataHVACVarRefFlow->VRFTU(VRFTUNum).isInAirLoop) { + int zoneAirNode = findMatchingZoneAirNode(state, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUInletNodeNum, true); + if (zoneAirNode > 0) { + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneAirNode = zoneAirNode; + } else if (!state.dataHVACVarRefFlow->VRFTU(VRFTUNum).isInAirLoop) { ShowSevereError(state, EnergyPlus::format("{} \"{}\" Zone terminal unit air inlet node name must be the same as a zone exhaust node name.", cCurrentModuleObject, @@ -6260,24 +5618,10 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool if ((state.dataHVACVarRefFlow->VRFTU(VRFTUNum).isInZone && (!state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ATMixerExists || state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ATMixerType == HVAC::MixerType::InletSide))) { - bool ZoneNodeNotFound = true; - for (int CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) { - continue; - } - for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++NodeNum) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOutletNodeNum == - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(NodeNum)) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneAirNode = state.dataZoneEquip->ZoneEquipConfig(CtrlZone).ZoneNode; - ZoneNodeNotFound = false; - break; - } - } - if (!ZoneNodeNotFound) { - break; - } - } - if (ZoneNodeNotFound) { + int zoneAirNode = findMatchingZoneAirNode(state, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOutletNodeNum, false); + if (zoneAirNode > 0) { + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneAirNode = zoneAirNode; + } else { ShowSevereError(state, EnergyPlus::format("{} \"{}\" Zone terminal unit air outlet node name must be the same as a zone inlet node name.", cCurrentModuleObject, @@ -6291,30 +5635,21 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool } if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).isInZone && state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ATMixerExists) { - // check that OA flow in cooling must be set to zero when connected to DOAS - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow != 0) { - ShowWarningError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError(state, EnergyPlus::format(".. Cooling Outdoor Air Flow Rate must be zero when {}", cCurrentModuleObject)); - ShowContinueError(state, "..object is connected to central dedicated outdoor air system via AirTerminal:SingleDuct:Mixer"); - ShowContinueError(state, ".. Cooling Outdoor Air Flow Rate is set to 0 and simulation continues."); - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow = 0; - } - // check that OA flow in heating must be set to zero when connected to DOAS - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow != 0) { - ShowWarningError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError(state, EnergyPlus::format(".. Heating Outdoor Air Flow Rate must be zero when {}", cCurrentModuleObject)); - ShowContinueError(state, "..object is connected to central dedicated outdoor air system via AirTerminal:SingleDuct:Mixer"); - ShowContinueError(state, ".. Heating Outdoor Air Flow Rate is set to 0 and simulation continues."); - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow = 0; - } - // check that OA flow in no cooling and no heating must be set to zero when connected to DOAS - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow != 0) { - ShowWarningError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError(state, EnergyPlus::format(".. No Load Outdoor Air Flow Rate must be zero when {}", cCurrentModuleObject)); - ShowContinueError(state, "..object is connected to central dedicated outdoor air system via AirTerminal:SingleDuct:Mixer"); - ShowContinueError(state, ".. No Load Outdoor Air Flow Rate is set to 0 and simulation continues."); - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow = 0; - } + warnAndResetDOASOutdoorAirFlow(state, + cCurrentModuleObject, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow, + "Cooling Outdoor Air Flow Rate"); + warnAndResetDOASOutdoorAirFlow(state, + cCurrentModuleObject, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow, + "Heating Outdoor Air Flow Rate"); + warnAndResetDOASOutdoorAirFlow(state, + cCurrentModuleObject, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow, + "No Load Outdoor Air Flow Rate"); } } // IF(ZoneEquipmentListNotChecked)THEN @@ -6548,136 +5883,98 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool } } - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow > - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate) { - ShowWarningError(state, - EnergyPlus::format("InitVRF: VRF Terminal Unit = [{}, \"{}\"]", - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError(state, "... has Supply Air Flow Rate During Cooling Operation > Max Fan Volume Flow Rate, should be <="); - ShowContinueError(state, - EnergyPlus::format("... Supply Air Flow Rate During Cooling Operation = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow)); - ShowContinueError(state, - EnergyPlus::format("... Max Fan Volume Flow Rate = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate)); - ShowContinueError( - state, "...the supply air flow rate during cooling operation will be reduced to match and the simulation continues."); - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate; - } - - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirVolFlow > - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate) { - ShowWarningError(state, - EnergyPlus::format("InitVRF: VRF Terminal Unit = [{}, \"{}\"]", - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError(state, "... has Supply Air Flow Rate When No Cooling is Needed > Max Fan Volume Flow Rate, should be <="); - ShowContinueError(state, - EnergyPlus::format("... Supply Air Flow Rate When No Cooling is Needed = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirVolFlow)); - ShowContinueError(state, - EnergyPlus::format("... Max Fan Volume Flow Rate = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate)); - ShowContinueError( - state, "...the supply air flow rate when no cooling is needed will be reduced to match and the simulation continues."); - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirVolFlow = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate; - } - - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow > state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow) { - ShowWarningError(state, - EnergyPlus::format("InitVRF: VRF Terminal Unit = [{}, \"{}\"]", - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError( - state, - "...The Outdoor Air Flow Rate During Cooling Operation exceeds the Supply Air Flow Rate During Cooling Operation."); - ShowContinueError(state, - EnergyPlus::format("...Outdoor Air Flow Rate During Cooling Operation = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow)); - ShowContinueError(state, - EnergyPlus::format("... Supply Air Flow Rate During Cooling Operation = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow)); - ShowContinueError(state, "...the outdoor air flow rate will be reduced to match and the simulation continues."); - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow; - } - - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow > - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate) { - ShowWarningError(state, - EnergyPlus::format("InitVRF: VRF Terminal Unit = [{}, \"{}\"]", - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError(state, "... has Supply Air Flow Rate During Heating Operation > Max Fan Volume Flow Rate, should be <="); - ShowContinueError(state, - EnergyPlus::format("... Supply Air Flow Rate During Heating Operation = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow)); - ShowContinueError(state, - EnergyPlus::format("... Max Fan Volume Flow Rate = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate)); - ShowContinueError( - state, "...the supply air flow rate during cooling operation will be reduced to match and the simulation continues."); - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate; - } + auto const &tuTypeName = tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type]; + auto const &tuName = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name; + Real64 const fanFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate; - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirVolFlow > - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate) { - ShowWarningError(state, - EnergyPlus::format("InitVRF: VRF Terminal Unit = [{}, \"{}\"]", - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError(state, "... has Supply Air Flow Rate When No Heating is Needed > Max Fan Volume Flow Rate, should be <="); - ShowContinueError(state, - EnergyPlus::format("... Supply Air Flow Rate When No Heating is Needed = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirVolFlow)); - ShowContinueError(state, - EnergyPlus::format("... Max Fan Volume Flow Rate = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate)); - ShowContinueError( - state, "...the supply air flow rate when no cooling is needed will be reduced to match and the simulation continues."); - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirVolFlow = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate; - } + warnAndCapFlowRate(state, + tuTypeName, + tuName, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow, + fanFlow, + "... has Supply Air Flow Rate During Cooling Operation > Max Fan Volume Flow Rate, should be <=", + "Supply Air Flow Rate During Cooling Operation", + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow, + "Max Fan Volume Flow Rate ", + fanFlow, + "...the supply air flow rate during cooling operation will be reduced to match and the simulation continues."); - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow > state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow) { - ShowWarningError(state, - EnergyPlus::format("InitVRF: VRF Terminal Unit = [{}, \"{}\"]", - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError( - state, - "...The Outdoor Air Flow Rate During Heating Operation exceeds the Supply Air Flow Rate During Heating Operation."); - ShowContinueError(state, - EnergyPlus::format("...Outdoor Air Flow Rate During Heating Operation = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow)); - ShowContinueError(state, - EnergyPlus::format("... Supply Air Flow Rate During Heating Operation = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow)); - ShowContinueError(state, "...the outdoor air flow rate will be reduced to match and the simulation continues."); - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow; - } + warnAndCapFlowRate( + state, + tuTypeName, + tuName, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirVolFlow, + fanFlow, + "... has Supply Air Flow Rate When No Cooling is Needed > Max Fan Volume Flow Rate, should be <=", + "Supply Air Flow Rate When No Cooling is Needed", + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirVolFlow, + "Max Fan Volume Flow Rate ", + fanFlow, + "...the supply air flow rate when no cooling is needed will be reduced to match and the simulation continues."); + + warnAndCapFlowRate( + state, + tuTypeName, + tuName, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow, + "...The Outdoor Air Flow Rate During Cooling Operation exceeds the Supply Air Flow Rate During Cooling Operation.", + "Outdoor Air Flow Rate During Cooling Operation", + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow, + "Supply Air Flow Rate During Cooling Operation ", + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow, + "...the outdoor air flow rate will be reduced to match and the simulation continues."); + + warnAndCapFlowRate(state, + tuTypeName, + tuName, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow, + fanFlow, + "... has Supply Air Flow Rate During Heating Operation > Max Fan Volume Flow Rate, should be <=", + "Supply Air Flow Rate During Heating Operation", + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow, + "Max Fan Volume Flow Rate ", + fanFlow, + "...the supply air flow rate during cooling operation will be reduced to match and the simulation continues."); - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow > - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate) { - ShowWarningError(state, - EnergyPlus::format("InitVRF: VRF Terminal Unit = [{}, \"{}\"]", - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError( - state, "... has a Outdoor Air Flow Rate When No Cooling or Heating is Needed > Max Fan Volume Flow Rate, should be <="); - ShowContinueError(state, - EnergyPlus::format("... Outdoor Air Flow Rate When No Cooling or Heating is Needed = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow)); - ShowContinueError(state, - EnergyPlus::format("... Max Fan Volume Flow Rate = {:.4R} m3/s", - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate)); - ShowContinueError(state, - "...the outdoor air flow rate when no cooling or heating is needed will be reduced to match and the " - "simulation continues."); - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate; - } + warnAndCapFlowRate( + state, + tuTypeName, + tuName, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirVolFlow, + fanFlow, + "... has Supply Air Flow Rate When No Heating is Needed > Max Fan Volume Flow Rate, should be <=", + "Supply Air Flow Rate When No Heating is Needed", + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirVolFlow, + "Max Fan Volume Flow Rate ", + fanFlow, + "...the supply air flow rate when no cooling is needed will be reduced to match and the simulation continues."); + + warnAndCapFlowRate( + state, + tuTypeName, + tuName, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow, + "...The Outdoor Air Flow Rate During Heating Operation exceeds the Supply Air Flow Rate During Heating Operation.", + "Outdoor Air Flow Rate During Heating Operation", + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow, + "Supply Air Flow Rate During Heating Operation ", + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow, + "...the outdoor air flow rate will be reduced to match and the simulation continues."); + + warnAndCapFlowRate( + state, + tuTypeName, + tuName, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow, + fanFlow, + "... has a Outdoor Air Flow Rate When No Cooling or Heating is Needed > Max Fan Volume Flow Rate, should be <=", + "Outdoor Air Flow Rate When No Cooling or Heating is Needed", + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow, + "Max Fan Volume Flow Rate ", + fanFlow, + "...the outdoor air flow rate when no cooling or heating is needed will be reduced to match and the simulation continues."); if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ActualFanVolFlowRate > 0.0) { state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatingSpeedRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow / @@ -6754,206 +6051,10 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool //*** End of Operating Mode Initialization done at beginning of each iteration ***! // disable VRF system when outside limits of operation based on OAT - EnableSystem = false; // flag used to switch operating modes when OAT is outside operating limits if (state.dataHVACVarRefFlow->CoolingLoad(VRFCond)) { - if ((OutsideDryBulbTemp < state.dataHVACVarRefFlow->VRF(VRFCond).MinOATCooling || - OutsideDryBulbTemp > state.dataHVACVarRefFlow->VRF(VRFCond).MaxOATCooling) && - any(state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).CoolingCoilPresent)) { - state.dataHVACVarRefFlow->CoolingLoad(VRFCond) = false; - // test if heating load exists, account for thermostat control type - switch (state.dataHVACVarRefFlow->VRF(VRFCond).ThermostatPriority) { - case ThermostatCtrlType::LoadPriority: - case ThermostatCtrlType::ZonePriority: { - if (state.dataHVACVarRefFlow->SumHeatingLoads(VRFCond) > 0.0) { - EnableSystem = true; - } - } break; - case ThermostatCtrlType::ThermostatOffsetPriority: { - if (state.dataHVACVarRefFlow->MinDeltaT(VRFCond) < 0.0) { - EnableSystem = true; - } - } break; - case ThermostatCtrlType::ScheduledPriority: - case ThermostatCtrlType::MasterThermostatPriority: { - // can't switch modes if scheduled (i.e., would be switching to unscheduled mode) - // or master TSTAT used (i.e., master zone only has a specific load - can't switch) - } break; - default: - break; - } - if (EnableSystem) { - if ((OutsideDryBulbTemp >= state.dataHVACVarRefFlow->VRF(VRFCond).MinOATHeating && - OutsideDryBulbTemp <= state.dataHVACVarRefFlow->VRF(VRFCond).MaxOATHeating) && - any(state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HeatingCoilPresent)) { - state.dataHVACVarRefFlow->HeatingLoad(VRFCond) = true; - } else { - if (any(state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).CoolingCoilAvailable)) { - if (state.dataHVACVarRefFlow->VRF(VRFCond).CoolingMaxTempLimitIndex == 0) { - ShowWarningMessage(state, - EnergyPlus::format("{} \"{}\".", - cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), - state.dataHVACVarRefFlow->VRF(VRFCond).Name)); - ShowContinueError(state, - "...InitVRF: VRF Heat Pump Min/Max Operating Temperature in Cooling Mode Limits have been " - "exceeded and VRF system is disabled."); - if (state.dataHVACVarRefFlow->VRF(VRFCond).CondenserType == DataHeatBalance::RefrigCondenserType::Water) { - ShowContinueError( - state, EnergyPlus::format("... Outdoor Unit Inlet Water Temperature = {:.3T}", OutsideDryBulbTemp)); - } else { - ShowContinueError( - state, - EnergyPlus::format("... Outdoor Unit Inlet Air Temperature = {:.3T}", OutsideDryBulbTemp)); - } - ShowContinueError(state, - EnergyPlus::format("... Cooling Minimum Outdoor Unit Inlet Temperature = {:.3T}", - state.dataHVACVarRefFlow->VRF(VRFCond).MinOATCooling)); - ShowContinueError(state, - EnergyPlus::format("... Cooling Maximum Outdoor Unit Inlet Temperature = {:.3T}", - state.dataHVACVarRefFlow->VRF(VRFCond).MaxOATCooling)); - ShowContinueErrorTimeStamp(state, "... Check VRF Heat Pump Min/Max Outdoor Temperature in Cooling Mode limits."); - } - ShowRecurringWarningErrorAtEnd(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)) + " \"" + - state.dataHVACVarRefFlow->VRF(VRFCond).Name + - "\" -- Exceeded VRF Heat Pump min/max cooling temperature limit error continues...", - state.dataHVACVarRefFlow->VRF(VRFCond).CoolingMaxTempLimitIndex, - OutsideDryBulbTemp, - OutsideDryBulbTemp); - } - } - } else { - if (any(state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).CoolingCoilAvailable)) { - if (state.dataHVACVarRefFlow->VRF(VRFCond).CoolingMaxTempLimitIndex == 0) { - ShowWarningMessage(state, - EnergyPlus::format("{} \"{}\".", - cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), - state.dataHVACVarRefFlow->VRF(VRFCond).Name)); - ShowContinueError(state, - "...InitVRF: VRF Heat Pump Min/Max Operating Temperature in Cooling Mode Limits have been exceeded " - "and VRF system is disabled."); - if (state.dataHVACVarRefFlow->VRF(VRFCond).CondenserType == DataHeatBalance::RefrigCondenserType::Water) { - ShowContinueError( - state, EnergyPlus::format("... Outdoor Unit Inlet Water Temperature = {:.3T}", OutsideDryBulbTemp)); - } else { - ShowContinueError( - state, EnergyPlus::format("... Outdoor Unit Inlet Air Temperature = {:.3T}", OutsideDryBulbTemp)); - } - ShowContinueError(state, - EnergyPlus::format("... Cooling Minimum Outdoor Unit Inlet Temperature = {:.3T}", - state.dataHVACVarRefFlow->VRF(VRFCond).MinOATCooling)); - ShowContinueError(state, - EnergyPlus::format("... Cooling Maximum Outdoor Unit Inlet Temperature = {:.3T}", - state.dataHVACVarRefFlow->VRF(VRFCond).MaxOATCooling)); - ShowContinueErrorTimeStamp(state, "... Check VRF Heat Pump Min/Max Outdoor Temperature in Cooling Mode limits."); - } - ShowRecurringWarningErrorAtEnd(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)) + " \"" + - state.dataHVACVarRefFlow->VRF(VRFCond).Name + - "\" -- Exceeded VRF Heat Pump min/max cooling temperature limit error continues...", - state.dataHVACVarRefFlow->VRF(VRFCond).CoolingMaxTempLimitIndex, - OutsideDryBulbTemp, - OutsideDryBulbTemp); - } - } - } + checkOATLimitAndSwitchMode(state, VRFCond, TUListIndex, OutsideDryBulbTemp, true); } else if (state.dataHVACVarRefFlow->HeatingLoad(VRFCond)) { - if ((OutsideDryBulbTemp < state.dataHVACVarRefFlow->VRF(VRFCond).MinOATHeating || - OutsideDryBulbTemp > state.dataHVACVarRefFlow->VRF(VRFCond).MaxOATHeating) && - any(state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HeatingCoilPresent)) { - state.dataHVACVarRefFlow->HeatingLoad(VRFCond) = false; - // test if cooling load exists, account for thermostat control type - switch (state.dataHVACVarRefFlow->VRF(VRFCond).ThermostatPriority) { - case ThermostatCtrlType::LoadPriority: - case ThermostatCtrlType::ZonePriority: { - if (state.dataHVACVarRefFlow->SumCoolingLoads(VRFCond) < 0.0) { - EnableSystem = true; - } - } break; - case ThermostatCtrlType::ThermostatOffsetPriority: { - if (state.dataHVACVarRefFlow->MaxDeltaT(VRFCond) > 0.0) { - EnableSystem = true; - } - } break; - case ThermostatCtrlType::ScheduledPriority: - case ThermostatCtrlType::MasterThermostatPriority: { - } break; - default: - break; - } - if (EnableSystem) { - if ((OutsideDryBulbTemp >= state.dataHVACVarRefFlow->VRF(VRFCond).MinOATCooling && - OutsideDryBulbTemp <= state.dataHVACVarRefFlow->VRF(VRFCond).MaxOATCooling) && - any(state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).CoolingCoilPresent)) { - state.dataHVACVarRefFlow->CoolingLoad(VRFCond) = true; - } else { - if (any(state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HeatingCoilAvailable)) { - if (state.dataHVACVarRefFlow->VRF(VRFCond).HeatingMaxTempLimitIndex == 0) { - ShowWarningMessage(state, - EnergyPlus::format("{} \"{}\".", - cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), - state.dataHVACVarRefFlow->VRF(VRFCond).Name)); - ShowContinueError(state, - "...InitVRF: VRF Heat Pump Min/Max Operating Temperature in Heating Mode Limits have been " - "exceeded and VRF system is disabled."); - if (state.dataHVACVarRefFlow->VRF(VRFCond).CondenserType == DataHeatBalance::RefrigCondenserType::Water) { - ShowContinueError( - state, EnergyPlus::format("... Outdoor Unit Inlet Water Temperature = {:.3T}", OutsideDryBulbTemp)); - } else { - ShowContinueError( - state, EnergyPlus::format("... Outdoor Unit Inlet Air Temperature = {:.3T}", OutsideDryBulbTemp)); - } - ShowContinueError(state, - EnergyPlus::format("... Heating Minimum Outdoor Unit Inlet Temperature = {:.3T}", - state.dataHVACVarRefFlow->VRF(VRFCond).MinOATHeating)); - ShowContinueError(state, - EnergyPlus::format("... Heating Maximum Outdoor Unit Inlet Temperature = {:.3T}", - state.dataHVACVarRefFlow->VRF(VRFCond).MaxOATHeating)); - ShowContinueErrorTimeStamp(state, "... Check VRF Heat Pump Min/Max Outdoor Temperature in Heating Mode limits."); - } - ShowRecurringWarningErrorAtEnd(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)) + " \"" + - state.dataHVACVarRefFlow->VRF(VRFCond).Name + - "\" -- Exceeded VRF Heat Pump min/max heating temperature limit error continues...", - state.dataHVACVarRefFlow->VRF(VRFCond).HeatingMaxTempLimitIndex, - OutsideDryBulbTemp, - OutsideDryBulbTemp); - } - } - } else { - if (any(state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HeatingCoilAvailable)) { - if (state.dataHVACVarRefFlow->VRF(VRFCond).HeatingMaxTempLimitIndex == 0) { - ShowWarningMessage(state, - EnergyPlus::format("{} \"{}\".", - cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), - state.dataHVACVarRefFlow->VRF(VRFCond).Name)); - ShowContinueError(state, - "...InitVRF: VRF Heat Pump Min/Max Operating Temperature in Heating Mode Limits have been exceeded " - "and VRF system is disabled."); - if (state.dataHVACVarRefFlow->VRF(VRFCond).CondenserType == DataHeatBalance::RefrigCondenserType::Water) { - ShowContinueError( - state, EnergyPlus::format("... Outdoor Unit Inlet Water Temperature = {:.3T}", OutsideDryBulbTemp)); - } else { - ShowContinueError( - state, EnergyPlus::format("... Outdoor Unit Inlet Air Temperature = {:.3T}", OutsideDryBulbTemp)); - } - ShowContinueError(state, - EnergyPlus::format("... Heating Minimum Outdoor Unit Inlet Temperature = {:.3T}", - state.dataHVACVarRefFlow->VRF(VRFCond).MinOATHeating)); - ShowContinueError(state, - EnergyPlus::format("... Heating Maximum Outdoor Unit Inlet Temperature = {:.3T}", - state.dataHVACVarRefFlow->VRF(VRFCond).MaxOATHeating)); - ShowContinueErrorTimeStamp(state, "... Check VRF Heat Pump Min/Max Outdoor Temperature in Heating Mode limits."); - } - ShowRecurringWarningErrorAtEnd(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)) + " \"" + - state.dataHVACVarRefFlow->VRF(VRFCond).Name + - "\" -- Exceeded VRF Heat Pump min/max heating temperature limit error continues...", - state.dataHVACVarRefFlow->VRF(VRFCond).HeatingMaxTempLimitIndex, - OutsideDryBulbTemp, - OutsideDryBulbTemp); - } - } - } + checkOATLimitAndSwitchMode(state, VRFCond, TUListIndex, OutsideDryBulbTemp, false); } } // IF (GetCurrentScheduleValue(state, VRF(VRFCond)%SchedPtr) .EQ. 0.0) THEN @@ -6962,48 +6063,36 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool if (state.dataHVACVarRefFlow->HeatingLoad(VRFCond) || (state.dataHVACVarRefFlow->VRF(VRFCond).HeatRecoveryUsed && state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList))) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerUsed) { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerRetNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirMassFlow; - } else { - if (!state.dataHVACVarRefFlow->VRFTU(VRFTUNum).isInOASys) { - state.dataLoopNodes->Node(InNode).MassFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - } - } + setVRFTUNodeMassFlowRate(state, + VRFTUNum, + InNode, + OutsideAirNode, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirMassFlow); } else if (state.dataHVACVarRefFlow->CoolingLoad(VRFCond) || (state.dataHVACVarRefFlow->VRF(VRFCond).HeatRecoveryUsed && state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList))) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerUsed) { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerRetNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow; - } else { - if (!state.dataHVACVarRefFlow->VRFTU(VRFTUNum).isInOASys) { - state.dataLoopNodes->Node(InNode).MassFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - } - } + setVRFTUNodeMassFlowRate(state, + VRFTUNum, + InNode, + OutsideAirNode, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow); } else { if (state.dataHVACVarRefFlow->LastModeCooling(VRFCond)) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerUsed) { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerRetNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow; - state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - } else { - if (!state.dataHVACVarRefFlow->VRFTU(VRFTUNum).isInOASys) { - state.dataLoopNodes->Node(InNode).MassFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow; - } - } + setVRFTUNodeMassFlowRate(state, + VRFTUNum, + InNode, + OutsideAirNode, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow); } else if (state.dataHVACVarRefFlow->LastModeHeating(VRFCond)) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerUsed) { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerRetNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirMassFlow; - state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - } else { - if (!state.dataHVACVarRefFlow->VRFTU(VRFTUNum).isInOASys) { - state.dataLoopNodes->Node(InNode).MassFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirMassFlow; - } - } + setVRFTUNodeMassFlowRate(state, + VRFTUNum, + InNode, + OutsideAirNode, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirMassFlow, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow); } } @@ -7071,15 +6160,7 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool !state.dataHVACVarRefFlow->VRFTU(VRFTUNum).isSetPointControlled) { SetCompFlowRate(state, VRFTUNum, VRFCond, true); - if (state.dataHVACVarRefFlow->VRF(VRFCond).VRFAlgorithmType == AlgorithmType::FluidTCtrl) { - // Algorithm Type: VRF model based on physics, applicable for Fluid Temperature Control - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF_FluidTCtrl( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } else { - // Algorithm Type: VRF model based on system curve - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } + calcVRFCoilOff(state, VRFTUNum, VRFCond, FirstHVACIteration, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); // If the Terminal Unit has a net cooling capacity (TempOutput < 0) and // the zone temp is above the Tstat heating setpoint (QToHeatSetPt < 0) @@ -7094,44 +6175,20 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool if (TempOutput < 0.0 && LoadToHeatingSP < 0.0) { // If the net cooling capacity overshoots the heating setpoint count as heating load if (TempOutput < LoadToHeatingSP) { - // Don't count as heating load unless mode is allowed. Also check for floating zone. if (state.dataHeatBalFanSys->TempControlType(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneNum) != HVAC::SetptType::SingleCool && state.dataHeatBalFanSys->TempControlType(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneNum) != HVAC::SetptType::Uncontrolled) { - if (!state.dataHVACVarRefFlow->LastModeHeating(VRFCond)) { - // system last operated in cooling mode, change air flows and repeat coil off capacity test - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerUsed) { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerRetNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerOANodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirMassFlow; - MixedAir::SimOAMixer( - state, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerName, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerIndex); - } else { - state.dataLoopNodes->Node(InNode).MassFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - } - - if (state.dataHVACVarRefFlow->VRF(VRFCond).VRFAlgorithmType == AlgorithmType::FluidTCtrl) { - // Algorithm Type: VRF model based on physics, applicable for Fluid Temperature Control - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF_FluidTCtrl( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } else { - // Algorithm Type: VRF model based on system curve - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } - - // if zone temp will overshoot, pass the LoadToHeatingSP as the load to meet - if (TempOutput < LoadToHeatingSP) { - QZnReq = LoadToHeatingSP; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList) = true; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList) = false; - } - } else { - // last mode was heating, zone temp will overshoot heating setpoint, reset QznReq to LoadtoHeatingSP - QZnReq = LoadToHeatingSP; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList) = true; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList) = false; - } + adjustVRFOvershootFlowAndLoad(state, + VRFTUNum, + VRFCond, + InNode, + TUListIndex, + IndexToTUInTUList, + FirstHVACIteration, + true, + LoadToHeatingSP, + TempOutput, + OnOffAirFlowRatio, + QZnReq); } } else if (TempOutput > LoadToCoolingSP && LoadToCoolingSP < 0.0) { // If the net cooling capacity does not meet the zone cooling load enable cooling @@ -7149,82 +6206,36 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool } else if (TempOutput > 0.0 && LoadToCoolingSP > 0.0) { // If the net heating capacity overshoots the cooling setpoint count as cooling load if (TempOutput > LoadToCoolingSP) { - // Don't count as cooling load unless mode is allowed. Also check for floating zone. if (state.dataHeatBalFanSys->TempControlType(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneNum) != HVAC::SetptType::SingleHeat && state.dataHeatBalFanSys->TempControlType(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneNum) != HVAC::SetptType::Uncontrolled) { - if (!state.dataHVACVarRefFlow->LastModeCooling(VRFCond)) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerUsed) { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerRetNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerOANodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow; - MixedAir::SimOAMixer( - state, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerName, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerIndex); - } else { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUInletNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - } - - if (state.dataHVACVarRefFlow->VRF(VRFCond).VRFAlgorithmType == AlgorithmType::FluidTCtrl) { - // Algorithm Type: VRF model based on physics, applicable for Fluid Temperature Control - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF_FluidTCtrl( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } else { - // Algorithm Type: VRF model based on system curve - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } - - // if zone temp will overshoot, pass the LoadToCoolingSP as the load to meet - if (TempOutput > LoadToCoolingSP) { - QZnReq = LoadToCoolingSP; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList) = true; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList) = false; - } - } else { - QZnReq = LoadToCoolingSP; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList) = true; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList) = false; - } + adjustVRFOvershootFlowAndLoad(state, + VRFTUNum, + VRFCond, + InNode, + TUListIndex, + IndexToTUInTUList, + FirstHVACIteration, + false, + LoadToCoolingSP, + TempOutput, + OnOffAirFlowRatio, + QZnReq); } } else if (TempOutput < LoadToHeatingSP) { - // Don't count as heating load unless mode is allowed. Also check for floating zone. if (state.dataHeatBalFanSys->TempControlType(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneNum) != HVAC::SetptType::SingleCool && state.dataHeatBalFanSys->TempControlType(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneNum) != HVAC::SetptType::Uncontrolled) { - if (!state.dataHVACVarRefFlow->LastModeHeating(VRFCond)) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerUsed) { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerRetNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerOANodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirMassFlow; - MixedAir::SimOAMixer( - state, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerName, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerIndex); - } else { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUInletNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - } - - if (state.dataHVACVarRefFlow->VRF(VRFCond).VRFAlgorithmType == AlgorithmType::FluidTCtrl) { - // Algorithm Type: VRF model based on physics, applicable for Fluid Temperature Control - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF_FluidTCtrl( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } else { - // Algorithm Type: VRF model based on system curve - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } - - // if zone temp will overshoot, pass the LoadToHeatingSP as the load to meet - if (TempOutput < LoadToHeatingSP) { - QZnReq = LoadToHeatingSP; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList) = true; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList) = false; - } - } else { - QZnReq = LoadToHeatingSP; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList) = true; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList) = false; - } + adjustVRFOvershootFlowAndLoad(state, + VRFTUNum, + VRFCond, + InNode, + TUListIndex, + IndexToTUInTUList, + FirstHVACIteration, + true, + LoadToHeatingSP, + TempOutput, + OnOffAirFlowRatio, + QZnReq); } } else if (TempOutput > LoadToHeatingSP && TempOutput < LoadToCoolingSP) { // If the net capacity does not overshoot either setpoint @@ -7244,41 +6255,18 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool // Don't count as cooling load unless mode is allowed. Also check for floating zone. if (state.dataHeatBalFanSys->TempControlType(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneNum) != HVAC::SetptType::SingleHeat && state.dataHeatBalFanSys->TempControlType(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneNum) != HVAC::SetptType::Uncontrolled) { - if (!state.dataHVACVarRefFlow->LastModeCooling(VRFCond)) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerUsed) { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerRetNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerOANodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow; - MixedAir::SimOAMixer( - state, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerName, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerIndex); - } else { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUInletNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - } - - if (state.dataHVACVarRefFlow->VRF(VRFCond).VRFAlgorithmType == AlgorithmType::FluidTCtrl) { - // Algorithm Type: VRF model based on physics, applicable for Fluid Temperature Control - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF_FluidTCtrl( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } else { - // Algorithm Type: VRF model based on system curve - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } - - // if zone temp will overshoot, pass the LoadToCoolingSP as the load to meet - if (TempOutput > LoadToCoolingSP) { - QZnReq = LoadToCoolingSP; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList) = true; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList) = false; - } - // last mode was cooling, zone temp will overshoot cooling setpoint, reset QznReq to LoadtoCoolingSP - } else { - QZnReq = LoadToCoolingSP; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList) = true; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList) = false; - } + adjustVRFOvershootFlowAndLoad(state, + VRFTUNum, + VRFCond, + InNode, + TUListIndex, + IndexToTUInTUList, + FirstHVACIteration, + false, + LoadToCoolingSP, + TempOutput, + OnOffAirFlowRatio, + QZnReq); } // If the Terminal Unit has a net cooling capacity (TempOutput < 0) and // the zone temp is below the Tstat heating setpoint (QToHeatSetPt > 0) @@ -7287,41 +6275,18 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool // Don't count as heating load unless mode is allowed. Also check for floating zone. if (state.dataHeatBalFanSys->TempControlType(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneNum) != HVAC::SetptType::SingleCool && state.dataHeatBalFanSys->TempControlType(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).ZoneNum) != HVAC::SetptType::Uncontrolled) { - if (!state.dataHVACVarRefFlow->LastModeHeating(VRFCond)) { - // system last operated in cooling mode, change air flows and repeat coil off capacity test - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerUsed) { - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerRetNodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - state.dataLoopNodes->Node(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).VRFTUOAMixerOANodeNum).MassFlowRate = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirMassFlow; - MixedAir::SimOAMixer( - state, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerName, state.dataHVACVarRefFlow->VRFTU(VRFTUNum).OAMixerIndex); - } else { - state.dataLoopNodes->Node(InNode).MassFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - } - - if (state.dataHVACVarRefFlow->VRF(VRFCond).VRFAlgorithmType == AlgorithmType::FluidTCtrl) { - // Algorithm Type: VRF model based on physics, applicable for Fluid Temperature Control - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF_FluidTCtrl( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } else { - // Algorithm Type: VRF model based on system curve - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CalcVRF( - state, VRFTUNum, FirstHVACIteration, 0.0, TempOutput, OnOffAirFlowRatio, SuppHeatCoilLoad); - } - - // if zone temp will overshoot, pass the LoadToHeatingSP as the load to meet - if (TempOutput < LoadToHeatingSP) { - QZnReq = LoadToHeatingSP; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList) = true; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList) = false; - } - } else { - // last mode was heating, zone temp will overshoot heating setpoint, reset QznReq to LoadtoHeatingSP - QZnReq = LoadToHeatingSP; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList) = true; - state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList) = false; - } + adjustVRFOvershootFlowAndLoad(state, + VRFTUNum, + VRFCond, + InNode, + TUListIndex, + IndexToTUInTUList, + FirstHVACIteration, + true, + LoadToHeatingSP, + TempOutput, + OnOffAirFlowRatio, + QZnReq); } } // test that the system is active if constant fan logic enables system when thermostat control logic did not @@ -7433,33 +6398,13 @@ void InitVRF(EnergyPlusData &state, int const VRFTUNum, int const ZoneNum, bool // set the TU flow rate. Check for heat recovery operation first, these will be FALSE if HR is not used. if (state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList)) { - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolingSpeedRatio; + setVRFCompFlowsCooling(state, VRFTUNum); } else if (state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList)) { - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoHeatingSpeedRatio; + setVRFCompFlowsHeating(state, VRFTUNum); } else if (state.dataHVACVarRefFlow->CoolingLoad(VRFCond) && QZnReq != 0.0) { - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolingSpeedRatio; + setVRFCompFlowsCooling(state, VRFTUNum); } else if (state.dataHVACVarRefFlow->HeatingLoad(VRFCond) && QZnReq != 0.0) { - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoHeatingSpeedRatio; + setVRFCompFlowsHeating(state, VRFTUNum); } else { if (state.dataHVACVarRefFlow->LastModeCooling(VRFCond)) { state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow; @@ -7527,85 +6472,153 @@ void SetCompFlowRate(EnergyPlusData &state, int const VRFTUNum, int const VRFCon // uses current operating mode to set flow rate (after mode is set) if (state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRCoolRequest(IndexToTUInTUList)) { - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolingSpeedRatio; + setVRFCompFlowsCooling(state, VRFTUNum); } else if (state.dataHVACVarRefFlow->TerminalUnitList(TUListIndex).HRHeatRequest(IndexToTUInTUList)) { - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoHeatingSpeedRatio; + setVRFCompFlowsHeating(state, VRFTUNum); } else if (UseCurrentMode) { // uses current operating mode to set flow rate (after mode is set) if (state.dataHVACVarRefFlow->CoolingLoad(VRFCond)) { - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolingSpeedRatio; + setVRFCompFlowsCooling(state, VRFTUNum); } else if (state.dataHVACVarRefFlow->HeatingLoad(VRFCond)) { - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoHeatingSpeedRatio; + setVRFCompFlowsHeating(state, VRFTUNum); } else if (state.dataHVACVarRefFlow->LastModeCooling(VRFCond)) { // if NOT cooling or heating then use last mode - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolingSpeedRatio; + setVRFCompFlowsCooling(state, VRFTUNum); } else if (state.dataHVACVarRefFlow->LastModeHeating(VRFCond)) { // if NOT cooling or heating then use last mode - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoHeatingSpeedRatio; + setVRFCompFlowsHeating(state, VRFTUNum); } else { // should not happen so just set to cooling flow rate - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolingSpeedRatio; + setVRFCompFlowsCooling(state, VRFTUNum); } } else { // uses previous operating mode to set flow rate (used for looping through each TU in Init before mode is set) if (state.dataHVACVarRefFlow->LastModeCooling(VRFCond)) { - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolingSpeedRatio; + setVRFCompFlowsCooling(state, VRFTUNum); } else if (state.dataHVACVarRefFlow->LastModeHeating(VRFCond)) { - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoHeatAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoHeatingSpeedRatio; + setVRFCompFlowsHeating(state, VRFTUNum); } else { // should not happen so just set to cooling flow rate - state.dataHVACVarRefFlow->CompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirMassFlow; - state.dataHVACVarRefFlow->CompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxNoCoolAirMassFlow; - state.dataHVACVarRefFlow->OACompOnMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirMassFlow; - state.dataHVACVarRefFlow->OACompOffMassFlow = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirMassFlow; - state.dataHVACVarRefFlow->CompOnFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolingSpeedRatio; - state.dataHVACVarRefFlow->CompOffFlowRatio = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolingSpeedRatio; + setVRFCompFlowsCooling(state, VRFTUNum); + } + } + + if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).fanOp == HVAC::FanOp::Cycling) { + state.dataHVACVarRefFlow->CompOffMassFlow = 0.0; + state.dataHVACVarRefFlow->OACompOffMassFlow = 0.0; + state.dataHVACVarRefFlow->CompOffFlowRatio = 0.0; + } +} + +// Helper: size multispeed fan flow rates for one mode (cooling or heating). +// volumeFlowRates and massFlowRates are the per-speed vectors to populate. +// flowRatios contains the design-spec per-speed ratios (may be AutoSize). +// numSpeeds is the total number of speeds; maxAirVolFlow is the rated flow. +static void sizeMultispeedFanFlowRates(EnergyPlusData &state, + int VRFTUNum, + int numSpeeds, + Real64 maxAirVolFlow, + std::vector const &flowRatios, + std::vector &volumeFlowRates, + std::vector &massFlowRates) +{ + auto &vrfTU = state.dataHVACVarRefFlow->VRFTU(VRFTUNum); + for (int i = 1; i <= numSpeeds; ++i) { + if (vrfTU.DesignSpecMSHPIndex > -1) { + if (flowRatios[i] == DataSizing::AutoSize) { + volumeFlowRates[i] = double(i) / double(numSpeeds) * maxAirVolFlow; + } else { + volumeFlowRates[i] = flowRatios[i] * maxAirVolFlow; + } + massFlowRates[i] = volumeFlowRates[i] * state.dataEnvrn->StdRhoAir; + } else { + auto *fanSystem = dynamic_cast(state.dataFans->fans(vrfTU.FanIndex)); + assert(fanSystem != nullptr); + if (massFlowRates[i] == 0.0 && !fanSystem->massFlowAtSpeed.empty()) { + massFlowRates[i] = fanSystem->massFlowAtSpeed[i - 1]; + volumeFlowRates[i] = massFlowRates[i] / state.dataEnvrn->StdRhoAir; + } } } +} - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).fanOp == HVAC::FanOp::Cycling) { - state.dataHVACVarRefFlow->CompOffMassFlow = 0.0; - state.dataHVACVarRefFlow->OACompOffMassFlow = 0.0; - state.dataHVACVarRefFlow->CompOffFlowRatio = 0.0; +// Helper: emit sizing-mismatch warning for a VRF field (used when the standard reportVRFCondFieldSize +// pattern does not apply because reportSizerOutput was already called separately). +static void warnVRFSizingMismatch(EnergyPlusData &state, + Real64 desValue, + Real64 userValue, + std::string_view compType, + std::string_view warningCompName, + std::string_view desLabel, + std::string_view userLabel, + int fmtPrecision = 2) +{ + if (!state.dataGlobal->DisplayExtraWarnings) { + return; + } + if ((std::abs(desValue - userValue) / userValue) <= state.dataSize->AutoVsHardSizingThreshold) { + return; + } + ShowMessage(state, EnergyPlus::format("SizeVRF: Potential issue with equipment sizing for {} {}", compType, warningCompName)); + // Extract unit suffix (e.g. " [W]") from labels so it appears after the value, + // matching the original format: "{label} of {value} [{unit}]" + auto extractUnit = [](std::string_view label) -> std::pair { + auto pos = label.rfind('['); + if (pos != std::string_view::npos && pos > 0 && label.back() == ']') { + // Include the space before '[' + size_t unitStart = (pos > 0 && label[pos - 1] == ' ') ? pos - 1 : pos; + return {label.substr(0, unitStart), label.substr(unitStart)}; + } + return {label, {}}; + }; + auto [userBase, userUnit] = extractUnit(userLabel); + auto [desBase, desUnit] = extractUnit(desLabel); + if (fmtPrecision == 5) { + ShowContinueError(state, EnergyPlus::format("{} of {:.5R}{}", userBase, userValue, userUnit)); + ShowContinueError(state, EnergyPlus::format("differs from {} of {:.5R}{}", desBase, desValue, desUnit)); + } else { + ShowContinueError(state, EnergyPlus::format("{} of {:.2R}{}", userBase, userValue, userUnit)); + ShowContinueError(state, EnergyPlus::format("differs from {} of {:.2R}{}", desBase, desValue, desUnit)); + } + ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); + ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); +} + +// Helper: compute piping correction factor for cooling or heating. +static Real64 calcVRFPipingCorrectionFactor( + EnergyPlusData &state, int pcfLengthCurvePtr, Real64 equivPipeLngth, Real64 combinationRatio, Real64 vertPipeLngth, Real64 pcfHeight) +{ + using Curve::CurveValue; + if (pcfLengthCurvePtr > 0) { + Real64 curveVal; + if (state.dataCurveManager->curves(pcfLengthCurvePtr)->numDims == 2) { + curveVal = CurveValue(state, pcfLengthCurvePtr, equivPipeLngth, combinationRatio); + } else { + curveVal = CurveValue(state, pcfLengthCurvePtr, equivPipeLngth); + } + return min(1.0, max(0.5, curveVal + vertPipeLngth * pcfHeight)); + } else { + return min(1.0, max(0.5, 1.0 + vertPipeLngth * pcfHeight)); + } +} + +// Helper: report autosize-vs-hardsize for a VRF condenser field, with optional sizing-mismatch warning. +// fieldRef is updated to desSizeValue when autosized; desLabel / userLabel are the report strings. +// fmtPrecision selects the format width for warnings (2 => {:.2R}, 5 => {:.5R}). +static void reportVRFCondFieldSize(EnergyPlusData &state, + Real64 &fieldRef, + Real64 desSizeValue, + std::string_view compType, + std::string_view compName, + std::string_view warningCompName, + std::string_view desLabel, + std::string_view userLabel, + int fmtPrecision = 2) +{ + bool const isAutoSize = (fieldRef == DataSizing::AutoSize); + if (isAutoSize) { + fieldRef = desSizeValue; + BaseSizer::reportSizerOutput(state, compType, compName, desLabel, desSizeValue); + } else { + if (fieldRef > 0.0 && desSizeValue > 0.0) { + Real64 const userValue = fieldRef; + BaseSizer::reportSizerOutput(state, compType, compName, desLabel, desSizeValue, userLabel, userValue); + warnVRFSizingMismatch(state, desSizeValue, userValue, compType, warningCompName, desLabel, userLabel, fmtPrecision); + } } } @@ -7855,31 +6868,12 @@ void SizeVRF(EnergyPlusData &state, int const VRFTUNum) } // Multispeed Fan cooling flow sizing if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedCooling > 0) { - Real64 AirFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow; - for (int i = 1; i <= state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedCooling; ++i) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex > -1) { - if (state.dataUnitarySystems->designSpecMSHP[state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex] - .coolingVolFlowRatio[i] == DataSizing::AutoSize) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolVolumeFlowRate[i] = - double(i) / double(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedCooling) * AirFlowRate; - } else { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolVolumeFlowRate[i] = - state.dataUnitarySystems->designSpecMSHP[state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex] - .coolingVolFlowRatio[i] * - AirFlowRate; - } - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolMassFlowRate[i] = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolVolumeFlowRate[i] * state.dataEnvrn->StdRhoAir; - } else { - auto *fanSystem = dynamic_cast(state.dataFans->fans(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).FanIndex)); - assert(fanSystem != nullptr); - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolMassFlowRate[i] == 0.0 && !fanSystem->massFlowAtSpeed.empty()) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolMassFlowRate[i] = fanSystem->massFlowAtSpeed[i - 1]; - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolVolumeFlowRate[i] = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolMassFlowRate[i] / state.dataEnvrn->StdRhoAir; - } - } - } + auto &vrfTU = state.dataHVACVarRefFlow->VRFTU(VRFTUNum); + auto const &flowRatios = (vrfTU.DesignSpecMSHPIndex > -1) + ? state.dataUnitarySystems->designSpecMSHP[vrfTU.DesignSpecMSHPIndex].coolingVolFlowRatio + : vrfTU.CoolVolumeFlowRate; // dummy, won't be read when DesignSpecMSHPIndex == -1 + sizeMultispeedFanFlowRates( + state, VRFTUNum, vrfTU.NumOfSpeedCooling, vrfTU.MaxCoolAirVolFlow, flowRatios, vrfTU.CoolVolumeFlowRate, vrfTU.CoolMassFlowRate); } SizingMethod = HeatingAirflowSizing; @@ -7940,31 +6934,12 @@ void SizeVRF(EnergyPlusData &state, int const VRFTUNum) } // Multispeed Fan heating flow sizing if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedHeating > 0) { - Real64 AirFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow; - for (int i = 1; i <= state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedHeating; ++i) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex > -1) { - if (state.dataUnitarySystems->designSpecMSHP[state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex] - .heatingVolFlowRatio[i] == DataSizing::AutoSize) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatVolumeFlowRate[i] = - double(i) / double(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedHeating) * AirFlowRate; - } else { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatVolumeFlowRate[i] = - state.dataUnitarySystems->designSpecMSHP[state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex] - .heatingVolFlowRatio[i] * - AirFlowRate; - } - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatMassFlowRate[i] = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatVolumeFlowRate[i] * state.dataEnvrn->StdRhoAir; - } else { - auto *fanSystem = dynamic_cast(state.dataFans->fans(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).FanIndex)); - assert(fanSystem != nullptr); - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatMassFlowRate[i] == 0.0 && !fanSystem->massFlowAtSpeed.empty()) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatMassFlowRate[i] = fanSystem->massFlowAtSpeed[i - 1]; - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatVolumeFlowRate[i] = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatMassFlowRate[i] / state.dataEnvrn->StdRhoAir; - } - } - } + auto &vrfTU = state.dataHVACVarRefFlow->VRFTU(VRFTUNum); + auto const &flowRatios = (vrfTU.DesignSpecMSHPIndex > -1) + ? state.dataUnitarySystems->designSpecMSHP[vrfTU.DesignSpecMSHPIndex].heatingVolFlowRatio + : vrfTU.HeatVolumeFlowRate; + sizeMultispeedFanFlowRates( + state, VRFTUNum, vrfTU.NumOfSpeedHeating, vrfTU.MaxHeatAirVolFlow, flowRatios, vrfTU.HeatVolumeFlowRate, vrfTU.HeatMassFlowRate); } PrintFlag = true; @@ -8108,31 +7083,12 @@ void SizeVRF(EnergyPlusData &state, int const VRFTUNum) state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow = sizingCoolingAirFlow.size(state, TempSize, errorsFound); // Multispeed Fan cooling flow sizing if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedCooling > 0) { - Real64 AirFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxCoolAirVolFlow; - for (int i = 1; i <= state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedCooling; ++i) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex > -1) { - if (state.dataUnitarySystems->designSpecMSHP[state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex] - .coolingVolFlowRatio[i] == DataSizing::AutoSize) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolVolumeFlowRate[i] = - double(i) / double(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedCooling) * AirFlowRate; - } else { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolVolumeFlowRate[i] = - state.dataUnitarySystems->designSpecMSHP[state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex] - .coolingVolFlowRatio[i] * - AirFlowRate; - } - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolMassFlowRate[i] = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolVolumeFlowRate[i] * state.dataEnvrn->StdRhoAir; - } else { - auto *fanSystem = dynamic_cast(state.dataFans->fans(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).FanIndex)); - assert(fanSystem != nullptr); - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolMassFlowRate[i] == 0.0 && !fanSystem->massFlowAtSpeed.empty()) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolMassFlowRate[i] = fanSystem->massFlowAtSpeed[i - 1]; - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolVolumeFlowRate[i] = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolMassFlowRate[i] / state.dataEnvrn->StdRhoAir; - } - } - } + auto &vrfTU = state.dataHVACVarRefFlow->VRFTU(VRFTUNum); + auto const &flowRatios = (vrfTU.DesignSpecMSHPIndex > -1) + ? state.dataUnitarySystems->designSpecMSHP[vrfTU.DesignSpecMSHPIndex].coolingVolFlowRatio + : vrfTU.CoolVolumeFlowRate; + sizeMultispeedFanFlowRates( + state, VRFTUNum, vrfTU.NumOfSpeedCooling, vrfTU.MaxCoolAirVolFlow, flowRatios, vrfTU.CoolVolumeFlowRate, vrfTU.CoolMassFlowRate); } FieldNum = 3; // N3, \field Supply Air Flow Rate During Heating Operation @@ -8146,31 +7102,12 @@ void SizeVRF(EnergyPlusData &state, int const VRFTUNum) state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow = sizingHeatingAirFlow.size(state, TempSize, errorsFound); // Multispeed Fan heating flow sizing if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedHeating > 0) { - Real64 AirFlowRate = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).MaxHeatAirVolFlow; - for (int i = 1; i <= state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedHeating; ++i) { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex > -1) { - if (state.dataUnitarySystems->designSpecMSHP[state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex] - .heatingVolFlowRatio[i] == DataSizing::AutoSize) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatVolumeFlowRate[i] = - double(i) / double(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NumOfSpeedHeating) * AirFlowRate; - } else { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatVolumeFlowRate[i] = - state.dataUnitarySystems->designSpecMSHP[state.dataHVACVarRefFlow->VRFTU(VRFTUNum).DesignSpecMSHPIndex] - .heatingVolFlowRatio[i] * - AirFlowRate; - } - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatMassFlowRate[i] = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatVolumeFlowRate[i] * state.dataEnvrn->StdRhoAir; - } else { - auto *fanSystem = dynamic_cast(state.dataFans->fans(state.dataHVACVarRefFlow->VRFTU(VRFTUNum).FanIndex)); - assert(fanSystem != nullptr); - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatMassFlowRate[i] == 0.0 && !fanSystem->massFlowAtSpeed.empty()) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatMassFlowRate[i] = fanSystem->massFlowAtSpeed[i - 1]; - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatVolumeFlowRate[i] = - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatMassFlowRate[i] / state.dataEnvrn->StdRhoAir; - } - } - } + auto &vrfTU = state.dataHVACVarRefFlow->VRFTU(VRFTUNum); + auto const &flowRatios = (vrfTU.DesignSpecMSHPIndex > -1) + ? state.dataUnitarySystems->designSpecMSHP[vrfTU.DesignSpecMSHPIndex].heatingVolFlowRatio + : vrfTU.HeatVolumeFlowRate; + sizeMultispeedFanFlowRates( + state, VRFTUNum, vrfTU.NumOfSpeedHeating, vrfTU.MaxHeatAirVolFlow, flowRatios, vrfTU.HeatVolumeFlowRate, vrfTU.HeatMassFlowRate); } errorsFound = false; @@ -8227,43 +7164,15 @@ void SizeVRF(EnergyPlusData &state, int const VRFTUNum) CoolOutAirVolFlowDes = 0.0; } - if (IsAutoSize) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow = CoolOutAirVolFlowDes; - BaseSizer::reportSizerOutput(state, - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, - "Design Size Outdoor Air Flow Rate During Cooling Operation [m3/s]", - CoolOutAirVolFlowDes); - } else { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow > 0.0 && CoolOutAirVolFlowDes > 0.0) { - CoolOutAirVolFlowUser = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow; - BaseSizer::reportSizerOutput(state, - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, - "Design Size Outdoor Air Flow Rate During Cooling Operation [m3/s]", - CoolOutAirVolFlowDes, - "User-Specified Outdoor Air Flow Rate During Cooling Operation [m3/s]", - CoolOutAirVolFlowUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(CoolOutAirVolFlowDes - CoolOutAirVolFlowUser) / CoolOutAirVolFlowUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVRF: Potential issue with equipment sizing for {} {}", - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Outdoor Air Flow Rate During Cooling Operation of {:.5R} [m3/s]", - CoolOutAirVolFlowUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Outdoor Air Flow Rate During Cooling Operation of {:.5R} [m3/s]", - CoolOutAirVolFlowDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } + reportVRFCondFieldSize(state, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow, + CoolOutAirVolFlowDes, + tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, + "Design Size Outdoor Air Flow Rate During Cooling Operation [m3/s]", + "User-Specified Outdoor Air Flow Rate During Cooling Operation [m3/s]", + 5); } } else { if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).CoolOutAirVolFlow == DataSizing::AutoSize) { @@ -8303,43 +7212,15 @@ void SizeVRF(EnergyPlusData &state, int const VRFTUNum) HeatOutAirVolFlowDes = 0.0; } - if (IsAutoSize) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow = HeatOutAirVolFlowDes; - BaseSizer::reportSizerOutput(state, - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, - "Design Size Outdoor Air Flow Rate During Heating Operation [m3/s]", - HeatOutAirVolFlowDes); - } else { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow > 0.0 && HeatOutAirVolFlowDes > 0.0) { - HeatOutAirVolFlowUser = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow; - BaseSizer::reportSizerOutput(state, - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, - "Design Size Outdoor Air Flow Rate During Heating Operation [m3/s]", - HeatOutAirVolFlowDes, - "User-Specified Outdoor Air Flow Rate During Heating Operation [m3/s]", - HeatOutAirVolFlowUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(HeatOutAirVolFlowDes - HeatOutAirVolFlowUser) / HeatOutAirVolFlowUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVRF: Potential issue with equipment sizing for {} {}", - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Outdoor Air Flow Rate During Heating Operation of {:.5R} [m3/s]", - HeatOutAirVolFlowUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Outdoor Air Flow Rate During Heating Operation of {:.5R} [m3/s]", - HeatOutAirVolFlowDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } + reportVRFCondFieldSize(state, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow, + HeatOutAirVolFlowDes, + tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, + "Design Size Outdoor Air Flow Rate During Heating Operation [m3/s]", + "User-Specified Outdoor Air Flow Rate During Heating Operation [m3/s]", + 5); } } else { if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).HeatOutAirVolFlow == DataSizing::AutoSize) { @@ -8391,45 +7272,15 @@ void SizeVRF(EnergyPlusData &state, int const VRFTUNum) NoCoolHeatOutAirVolFlowDes = 0.0; } - if (IsAutoSize) { - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow = NoCoolHeatOutAirVolFlowDes; - BaseSizer::reportSizerOutput(state, - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, - "Design Size Outdoor Air Flow Rate When No Cooling or Heating is Needed [m3/s]", - NoCoolHeatOutAirVolFlowDes); - } else { - if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow > 0.0 && NoCoolHeatOutAirVolFlowDes > 0.0) { - NoCoolHeatOutAirVolFlowUser = state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow; - BaseSizer::reportSizerOutput(state, - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, - "Design Size Outdoor Air Flow Rate When No Cooling or Heating is Needed [m3/s]", - NoCoolHeatOutAirVolFlowDes, - "User-Specified Outdoor Air Flow Rate When No Cooling or Heating is Needed [m3/s]", - NoCoolHeatOutAirVolFlowUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(NoCoolHeatOutAirVolFlowDes - NoCoolHeatOutAirVolFlowUser) / NoCoolHeatOutAirVolFlowUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVRF: Potential issue with equipment sizing for {} {}", - tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], - state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name)); - ShowContinueError( - state, - EnergyPlus::format("User-Specified Outdoor Air Flow Rate When No Cooling or Heating is Needed of {:.5R} [m3/s]", - NoCoolHeatOutAirVolFlowUser)); - ShowContinueError( - state, - EnergyPlus::format( - "differs from Design Size Outdoor Air Flow Rate When No Cooling or Heating is Needed of {:.5R} [m3/s]", - NoCoolHeatOutAirVolFlowDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } + reportVRFCondFieldSize(state, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow, + NoCoolHeatOutAirVolFlowDes, + tuTypeNames[(int)state.dataHVACVarRefFlow->VRFTU(VRFTUNum).type], + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, + state.dataHVACVarRefFlow->VRFTU(VRFTUNum).Name, + "Design Size Outdoor Air Flow Rate When No Cooling or Heating is Needed [m3/s]", + "User-Specified Outdoor Air Flow Rate When No Cooling or Heating is Needed [m3/s]", + 5); } } else { if (state.dataHVACVarRefFlow->VRFTU(VRFTUNum).NoCoolHeatOutAirVolFlow == DataSizing::AutoSize) { @@ -8578,45 +7429,15 @@ void SizeVRF(EnergyPlusData &state, int const VRFTUNum) // Size VRF rated cooling/heating capacity (VRF-SysCurve Model) // Size VRF( VRFCond ).CoolingCapacity - IsAutoSize = false; - if (state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCapacity == AutoSize) { - IsAutoSize = true; - } CoolingCapacityDes = TUCoolingCapacity; - if (IsAutoSize) { - state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCapacity = CoolingCapacityDes; - BaseSizer::reportSizerOutput(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), - state.dataHVACVarRefFlow->VRF(VRFCond).Name, - "Design Size Rated Total Cooling Capacity (gross) [W]", - CoolingCapacityDes); - } else { - if (state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCapacity > 0.0 && CoolingCapacityDes > 0.0) { - CoolingCapacityUser = state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCapacity; - BaseSizer::reportSizerOutput(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), - state.dataHVACVarRefFlow->VRF(VRFCond).Name, - "Design Size Rated Total Cooling Capacity (gross) [W]", - CoolingCapacityDes, - "User-Specified Rated Total Cooling Capacity (gross) [W]", - CoolingCapacityUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(CoolingCapacityDes - CoolingCapacityUser) / CoolingCapacityUser) > state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVRF: Potential issue with equipment sizing for {} {}", - cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), - state.dataHVACVarRefFlow->VRFTU(VRFCond).Name)); - ShowContinueError( - state, EnergyPlus::format("User-Specified Rated Total Cooling Capacity (gross) of {:.2R} [W]", CoolingCapacityUser)); - ShowContinueError(state, - EnergyPlus::format("differs from Design Size Rated Total Cooling Capacity (gross) of {:.2R} [W]", - CoolingCapacityDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } + reportVRFCondFieldSize(state, + state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCapacity, + CoolingCapacityDes, + std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), + state.dataHVACVarRefFlow->VRF(VRFCond).Name, + state.dataHVACVarRefFlow->VRFTU(VRFCond).Name, + "Design Size Rated Total Cooling Capacity (gross) [W]", + "User-Specified Rated Total Cooling Capacity (gross) [W]"); if (state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCapacity > 0.0) { state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCombinationRatio = @@ -8624,49 +7445,20 @@ void SizeVRF(EnergyPlusData &state, int const VRFTUNum) } // Size VRF( VRFCond ).HeatingCapacity - IsAutoSize = false; - if (state.dataHVACVarRefFlow->VRF(VRFCond).HeatingCapacity == AutoSize) { - IsAutoSize = true; - } if (state.dataHVACVarRefFlow->VRF(VRFCond).LockHeatingCapacity) { HeatingCapacityDes = state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCapacity * state.dataHVACVarRefFlow->VRF(VRFCond).HeatingCapacitySizeRatio; } else { HeatingCapacityDes = TUHeatingCapacity; } - if (IsAutoSize) { - state.dataHVACVarRefFlow->VRF(VRFCond).HeatingCapacity = HeatingCapacityDes; - BaseSizer::reportSizerOutput(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), - state.dataHVACVarRefFlow->VRF(VRFCond).Name, - "Design Size Rated Total Heating Capacity [W]", - HeatingCapacityDes); - } else { - if (state.dataHVACVarRefFlow->VRF(VRFCond).HeatingCapacity > 0.0 && HeatingCapacityDes > 0.0) { - HeatingCapacityUser = state.dataHVACVarRefFlow->VRF(VRFCond).HeatingCapacity; - BaseSizer::reportSizerOutput(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), - state.dataHVACVarRefFlow->VRF(VRFCond).Name, - "Design Size Rated Total Heating Capacity [W]", - HeatingCapacityDes, - "User-Specified Rated Total Heating Capacity [W]", - HeatingCapacityUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(HeatingCapacityDes - HeatingCapacityUser) / HeatingCapacityUser) > state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVRF: Potential issue with equipment sizing for {} {}", - cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), - state.dataHVACVarRefFlow->VRFTU(VRFCond).Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Rated Total Heating Capacity of {:.2R} [W]", HeatingCapacityUser)); - ShowContinueError( - state, EnergyPlus::format("differs from Design Size Rated Total Heating Capacity of {:.2R} [W]", HeatingCapacityDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } + reportVRFCondFieldSize(state, + state.dataHVACVarRefFlow->VRF(VRFCond).HeatingCapacity, + HeatingCapacityDes, + std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), + state.dataHVACVarRefFlow->VRF(VRFCond).Name, + state.dataHVACVarRefFlow->VRFTU(VRFCond).Name, + "Design Size Rated Total Heating Capacity [W]", + "User-Specified Rated Total Heating Capacity [W]"); if (state.dataHVACVarRefFlow->VRF(VRFCond).HeatingCapacity > 0.0) { state.dataHVACVarRefFlow->VRF(VRFCond).HeatingCombinationRatio = @@ -8674,59 +7466,21 @@ void SizeVRF(EnergyPlusData &state, int const VRFTUNum) } // calculate the piping correction factors only once - if (state.dataHVACVarRefFlow->VRF(VRFCond).PCFLengthCoolPtr > 0) { - { - if (state.dataCurveManager->curves(state.dataHVACVarRefFlow->VRF(VRFCond).PCFLengthCoolPtr)->numDims == 2) { - state.dataHVACVarRefFlow->VRF(VRFCond).PipingCorrectionCooling = - min(1.0, - max(0.5, - CurveValue(state, - state.dataHVACVarRefFlow->VRF(VRFCond).PCFLengthCoolPtr, - state.dataHVACVarRefFlow->VRF(VRFCond).EquivPipeLngthCool, - state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCombinationRatio) + - state.dataHVACVarRefFlow->VRF(VRFCond).VertPipeLngth * state.dataHVACVarRefFlow->VRF(VRFCond).PCFHeightCool)); - } else { - state.dataHVACVarRefFlow->VRF(VRFCond).PipingCorrectionCooling = - min(1.0, - max(0.5, - CurveValue(state, - state.dataHVACVarRefFlow->VRF(VRFCond).PCFLengthCoolPtr, - state.dataHVACVarRefFlow->VRF(VRFCond).EquivPipeLngthCool) + - state.dataHVACVarRefFlow->VRF(VRFCond).VertPipeLngth * state.dataHVACVarRefFlow->VRF(VRFCond).PCFHeightCool)); - } - } - } else { - state.dataHVACVarRefFlow->VRF(VRFCond).PipingCorrectionCooling = min( - 1.0, - max(0.5, (1.0 + state.dataHVACVarRefFlow->VRF(VRFCond).VertPipeLngth * state.dataHVACVarRefFlow->VRF(VRFCond).PCFHeightCool))); - } - - if (state.dataHVACVarRefFlow->VRF(VRFCond).PCFLengthHeatPtr > 0) { - { - if (state.dataCurveManager->curves(state.dataHVACVarRefFlow->VRF(VRFCond).PCFLengthHeatPtr)->numDims == 2) { - state.dataHVACVarRefFlow->VRF(VRFCond).PipingCorrectionHeating = - min(1.0, - max(0.5, - CurveValue(state, - state.dataHVACVarRefFlow->VRF(VRFCond).PCFLengthHeatPtr, - state.dataHVACVarRefFlow->VRF(VRFCond).EquivPipeLngthHeat, - state.dataHVACVarRefFlow->VRF(VRFCond).HeatingCombinationRatio) + - state.dataHVACVarRefFlow->VRF(VRFCond).VertPipeLngth * state.dataHVACVarRefFlow->VRF(VRFCond).PCFHeightHeat)); - } else { - state.dataHVACVarRefFlow->VRF(VRFCond).PipingCorrectionHeating = - min(1.0, - max(0.5, - CurveValue(state, - state.dataHVACVarRefFlow->VRF(VRFCond).PCFLengthHeatPtr, - state.dataHVACVarRefFlow->VRF(VRFCond).EquivPipeLngthHeat) + - state.dataHVACVarRefFlow->VRF(VRFCond).VertPipeLngth * state.dataHVACVarRefFlow->VRF(VRFCond).PCFHeightHeat)); - } - } - } else { - state.dataHVACVarRefFlow->VRF(VRFCond).PipingCorrectionHeating = min( - 1.0, - max(0.5, (1.0 + state.dataHVACVarRefFlow->VRF(VRFCond).VertPipeLngth * state.dataHVACVarRefFlow->VRF(VRFCond).PCFHeightHeat))); - } + state.dataHVACVarRefFlow->VRF(VRFCond).PipingCorrectionCooling = + calcVRFPipingCorrectionFactor(state, + state.dataHVACVarRefFlow->VRF(VRFCond).PCFLengthCoolPtr, + state.dataHVACVarRefFlow->VRF(VRFCond).EquivPipeLngthCool, + state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCombinationRatio, + state.dataHVACVarRefFlow->VRF(VRFCond).VertPipeLngth, + state.dataHVACVarRefFlow->VRF(VRFCond).PCFHeightCool); + + state.dataHVACVarRefFlow->VRF(VRFCond).PipingCorrectionHeating = + calcVRFPipingCorrectionFactor(state, + state.dataHVACVarRefFlow->VRF(VRFCond).PCFLengthHeatPtr, + state.dataHVACVarRefFlow->VRF(VRFCond).EquivPipeLngthHeat, + state.dataHVACVarRefFlow->VRF(VRFCond).HeatingCombinationRatio, + state.dataHVACVarRefFlow->VRF(VRFCond).VertPipeLngth, + state.dataHVACVarRefFlow->VRF(VRFCond).PCFHeightHeat); state.dataHVACVarRefFlow->VRF(VRFCond).RatedCoolingPower = state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCapacity / state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCOP; @@ -8810,170 +7564,61 @@ void SizeVRF(EnergyPlusData &state, int const VRFTUNum) "User-Specified Rated Total Heating Capacity [W]", HeatingCapacityUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(CoolingCapacityDes - CoolingCapacityUser) / CoolingCapacityUser) > state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVRF: Potential issue with equipment sizing for {} {}", - cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), - state.dataHVACVarRefFlow->VRFTU(VRFCond).Name)); - ShowContinueError( - state, EnergyPlus::format("User-Specified Rated Total Cooling Capacity (gross) of {:.2R} [W]", CoolingCapacityUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Rated Total Cooling Capacity (gross) of {:.2R} [W]", CoolingCapacityDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - - if ((std::abs(HeatingCapacityDes - HeatingCapacityUser) / HeatingCapacityUser) > state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVRF: Potential issue with equipment sizing for {} {}", - cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), - state.dataHVACVarRefFlow->VRFTU(VRFCond).Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Rated Total Heating Capacity of {:.2R} [W]", HeatingCapacityUser)); - ShowContinueError( - state, EnergyPlus::format("differs from Design Size Rated Total Heating Capacity of {:.2R} [W]", HeatingCapacityDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + warnVRFSizingMismatch(state, + CoolingCapacityDes, + CoolingCapacityUser, + cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), + state.dataHVACVarRefFlow->VRFTU(VRFCond).Name, + "Design Size Rated Total Cooling Capacity (gross) [W]", + "User-Specified Rated Total Cooling Capacity (gross) [W]"); + warnVRFSizingMismatch(state, + HeatingCapacityDes, + HeatingCapacityUser, + cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), + state.dataHVACVarRefFlow->VRFTU(VRFCond).Name, + "Design Size Rated Total Heating Capacity [W]", + "User-Specified Rated Total Heating Capacity [W]"); } } if (FoundAll) { // autosize resistive defrost heater capacity - IsAutoSize = false; - if (state.dataHVACVarRefFlow->VRF(VRFCond).DefrostCapacity == AutoSize) { - IsAutoSize = true; - } if (state.dataHVACVarRefFlow->VRF(VRFCond).DefrostStrategy == StandardRatings::DefrostStrat::Resistive) { DefrostCapacityDes = state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCapacity; } else { DefrostCapacityDes = 0.0; } - if (IsAutoSize) { - state.dataHVACVarRefFlow->VRF(VRFCond).DefrostCapacity = DefrostCapacityDes; - BaseSizer::reportSizerOutput(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), - state.dataHVACVarRefFlow->VRF(VRFCond).Name, - "Design Size Resistive Defrost Heater Capacity [W]", - DefrostCapacityDes); - } else { - if (state.dataHVACVarRefFlow->VRF(VRFCond).DefrostCapacity > 0.0 && DefrostCapacityDes > 0.0) { - DefrostCapacityUser = state.dataHVACVarRefFlow->VRF(VRFCond).DefrostCapacity; - BaseSizer::reportSizerOutput(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), - state.dataHVACVarRefFlow->VRF(VRFCond).Name, - "Design Size Resistive Defrost Heater Capacity [W]", - DefrostCapacityDes, - "User-Specified Resistive Defrost Heater Capacity", - DefrostCapacityUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(DefrostCapacityDes - DefrostCapacityUser) / DefrostCapacityUser) > state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVRF: Potential issue with equipment sizing for {} {}", - cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), - state.dataHVACVarRefFlow->VRFTU(VRFCond).Name)); - ShowContinueError( - state, EnergyPlus::format("User-Specified Resistive Defrost Heater Capacity of {:.2R} [W]", DefrostCapacityUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Resistive Defrost Heater Capacity of {:.2R} [W]", DefrostCapacityDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } + reportVRFCondFieldSize(state, + state.dataHVACVarRefFlow->VRF(VRFCond).DefrostCapacity, + DefrostCapacityDes, + std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), + state.dataHVACVarRefFlow->VRF(VRFCond).Name, + state.dataHVACVarRefFlow->VRFTU(VRFCond).Name, + "Design Size Resistive Defrost Heater Capacity [W]", + "User-Specified Resistive Defrost Heater Capacity"); - IsAutoSize = false; - if (state.dataHVACVarRefFlow->VRF(VRFCond).EvapCondAirVolFlowRate == AutoSize) { - IsAutoSize = true; - } // Auto-size condenser air flow to Total Capacity * 0.000114 m3/s/w (850 cfm/ton) EvapCondAirVolFlowRateDes = state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCapacity * 0.000114; - if (IsAutoSize) { - state.dataHVACVarRefFlow->VRF(VRFCond).EvapCondAirVolFlowRate = EvapCondAirVolFlowRateDes; - BaseSizer::reportSizerOutput(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), - state.dataHVACVarRefFlow->VRF(VRFCond).Name, - "Design Size Evaporative Condenser Air Flow Rate [m3/s]", - EvapCondAirVolFlowRateDes); - } else { - if (state.dataHVACVarRefFlow->VRF(VRFCond).EvapCondAirVolFlowRate > 0.0 && EvapCondAirVolFlowRateDes > 0.0) { - EvapCondAirVolFlowRateUser = state.dataHVACVarRefFlow->VRF(VRFCond).EvapCondAirVolFlowRate; - BaseSizer::reportSizerOutput(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), - state.dataHVACVarRefFlow->VRF(VRFCond).Name, - "Design Size Evaporative Condenser Air Flow Rate [m3/s]", - EvapCondAirVolFlowRateDes, - "User-Specified Evaporative Condenser Air Flow Rate [m3/s]", - EvapCondAirVolFlowRateUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(EvapCondAirVolFlowRateDes - EvapCondAirVolFlowRateUser) / EvapCondAirVolFlowRateUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVRF: Potential issue with equipment sizing for {} {}", - cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), - state.dataHVACVarRefFlow->VRFTU(VRFCond).Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Evaporative Condenser Air Flow Rate of {:.5R} [m3/s]", - EvapCondAirVolFlowRateUser)); - ShowContinueError(state, - EnergyPlus::format("differs from Design Size Evaporative Condenser Air Flow Rate of {:.5R} [m3/s]", - EvapCondAirVolFlowRateDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } + reportVRFCondFieldSize(state, + state.dataHVACVarRefFlow->VRF(VRFCond).EvapCondAirVolFlowRate, + EvapCondAirVolFlowRateDes, + std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), + state.dataHVACVarRefFlow->VRF(VRFCond).Name, + state.dataHVACVarRefFlow->VRFTU(VRFCond).Name, + "Design Size Evaporative Condenser Air Flow Rate [m3/s]", + "User-Specified Evaporative Condenser Air Flow Rate [m3/s]", + 5); - IsAutoSize = false; - if (state.dataHVACVarRefFlow->VRF(VRFCond).EvapCondPumpPower == AutoSize) { - IsAutoSize = true; - } // Auto-size evap condenser pump power to Total Capacity * 0.004266 w/w (15 w/ton) EvapCondPumpPowerDes = state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCapacity * 0.004266; - if (IsAutoSize) { - state.dataHVACVarRefFlow->VRF(VRFCond).EvapCondPumpPower = EvapCondPumpPowerDes; - BaseSizer::reportSizerOutput(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), - state.dataHVACVarRefFlow->VRF(VRFCond).Name, - "Design Size Evaporative Condenser Pump Rated Power Consumption [W]", - EvapCondPumpPowerDes); - - } else { - if (state.dataHVACVarRefFlow->VRF(VRFCond).EvapCondPumpPower > 0.0 && EvapCondPumpPowerDes > 0.0) { - EvapCondPumpPowerUser = state.dataHVACVarRefFlow->VRF(VRFCond).EvapCondPumpPower; - BaseSizer::reportSizerOutput(state, - std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), - state.dataHVACVarRefFlow->VRF(VRFCond).Name, - "Design Size Evaporative Condenser Pump Rated Power Consumption [W]", - EvapCondPumpPowerDes, - "User-Specified Evaporative Condenser Pump Rated Power Consumption [W]", - EvapCondPumpPowerUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(EvapCondPumpPowerDes - EvapCondPumpPowerUser) / EvapCondPumpPowerUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVRF: Potential issue with equipment sizing for {} {}", - cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum), - state.dataHVACVarRefFlow->VRFTU(VRFCond).Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Evaporative Condenser Pump Rated Power Consumption of {:.2R} [W]", - EvapCondPumpPowerUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Evaporative Condenser Pump Rated Power Consumption of {:.2R} [W]", - EvapCondPumpPowerDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } + reportVRFCondFieldSize(state, + state.dataHVACVarRefFlow->VRF(VRFCond).EvapCondPumpPower, + EvapCondPumpPowerDes, + std::string(cVRFTypes(state.dataHVACVarRefFlow->VRF(VRFCond).VRFSystemTypeNum)), + state.dataHVACVarRefFlow->VRF(VRFCond).Name, + state.dataHVACVarRefFlow->VRFTU(VRFCond).Name, + "Design Size Evaporative Condenser Pump Rated Power Consumption [W]", + "User-Specified Evaporative Condenser Pump Rated Power Consumption [W]"); // Report to eio other information not related to autosizing if (state.dataHVACVarRefFlow->MyOneTimeEIOFlag) { @@ -11187,6 +9832,112 @@ void VRFTerminalUnitEquipment::CalcVRFIUVariableTeTc(EnergyPlusData &state, } } +// Calculate total IU evaporator refrigerant flow rate and weighted superheat (SH_IU_merged) +// by iterating through terminal units with cooling load. Returns m_ref_IU_evap, h_IU_evap_out, SH_IU_merged. +static void calcIUEvapRefFlowAndSH(EnergyPlusData &state, + Fluid::RefrigProps *refrig, + Real64 IUEvaporatingTemp, + int TUListNum, + int NumTUInList, + Real64 Pevap, + Real64 RefPHigh, + Real64 RefPLow, + Real64 TU_CoolingLoad, + Real64 h_IU_evap_in, + Real64 &m_ref_IU_evap, + Real64 &h_IU_evap_out, + Real64 &SH_IU_merged) +{ + static constexpr std::string_view RoutineName("CalcVRFCondenser_FluidTCtrl"); + + m_ref_IU_evap = 0; + h_IU_evap_out = 0; + SH_IU_merged = 0; + + Real64 const clampedPevap = max(min(Pevap, RefPHigh), RefPLow); + + for (int NumTU = 1; NumTU <= NumTUInList; NumTU++) { + if (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad(NumTU) > 0) { + int TUIndex = state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).ZoneTUPtr(NumTU); + int CoolCoilIndex = state.dataHVACVarRefFlow->VRFTU(TUIndex).CoolCoilIndex; + + Real64 RefTSat = refrig->getSatTemperature(state, clampedPevap, RoutineName); + Real64 h_IU_evap_out_i = refrig->getSupHeatEnthalpy( + state, max(RefTSat, IUEvaporatingTemp + state.dataDXCoils->DXCoil(CoolCoilIndex).ActualSH), clampedPevap, RoutineName); + + if (h_IU_evap_out_i > h_IU_evap_in) { + Real64 m_ref_IU_evap_i = + (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad(NumTU) <= 0.0) + ? 0.0 + : (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad(NumTU) / (h_IU_evap_out_i - h_IU_evap_in)); + m_ref_IU_evap = m_ref_IU_evap + m_ref_IU_evap_i; + h_IU_evap_out = h_IU_evap_out + m_ref_IU_evap_i * h_IU_evap_out_i; + SH_IU_merged = SH_IU_merged + m_ref_IU_evap_i * state.dataDXCoils->DXCoil(CoolCoilIndex).ActualSH; + } + } + } + if (m_ref_IU_evap > 0) { + h_IU_evap_out = h_IU_evap_out / m_ref_IU_evap; + SH_IU_merged = SH_IU_merged / m_ref_IU_evap; + } else { + Real64 RefTSat = refrig->getSatTemperature(state, clampedPevap, RoutineName); + h_IU_evap_out = refrig->getSupHeatEnthalpy(state, max(RefTSat, IUEvaporatingTemp + 3), clampedPevap, RoutineName); + SH_IU_merged = 3; + m_ref_IU_evap = TU_CoolingLoad / (h_IU_evap_out - h_IU_evap_in); + } +} + +// Calculate total IU condenser refrigerant flow rate and weighted subcooling (SC_IU_merged) +// by iterating through terminal units with heating load. Returns m_ref_IU_cond, h_IU_cond_out_ave, SC_IU_merged. +static void calcIUCondRefFlowAndSC(EnergyPlusData &state, + Fluid::RefrigProps *refrig, + int TUListNum, + int NumTUInList, + Real64 Pcond, + Real64 RefPHigh, + Real64 RefPLow, + Real64 TU_HeatingLoad, + Real64 h_IU_cond_in, + Real64 &m_ref_IU_cond, + Real64 &h_IU_cond_out_ave, + Real64 &SC_IU_merged) +{ + static constexpr std::string_view RoutineName("CalcVRFCondenser_FluidTCtrl"); + + m_ref_IU_cond = 0; + h_IU_cond_out_ave = 0; + SC_IU_merged = 0; + + Real64 const clampedPcond = max(min(Pcond, RefPHigh), RefPLow); + + for (int NumTU = 1; NumTU <= NumTUInList; NumTU++) { + if (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad(NumTU) > 0) { + int TUIndex = state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).ZoneTUPtr(NumTU); + int HeatCoilIndex = state.dataHVACVarRefFlow->VRFTU(TUIndex).HeatCoilIndex; + Real64 h_IU_cond_out_i = refrig->getSatEnthalpy(state, + refrig->getSatTemperature(state, clampedPcond, RoutineName) - + state.dataDXCoils->DXCoil(HeatCoilIndex).ActualSC, + 0.0, + RoutineName); + Real64 m_ref_IU_cond_i = + (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad(NumTU) <= 0.0) + ? 0.0 + : (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad(NumTU) / (h_IU_cond_in - h_IU_cond_out_i)); + m_ref_IU_cond = m_ref_IU_cond + m_ref_IU_cond_i; + h_IU_cond_out_ave = h_IU_cond_out_ave + m_ref_IU_cond_i * h_IU_cond_out_i; + SC_IU_merged = SC_IU_merged + m_ref_IU_cond_i * state.dataDXCoils->DXCoil(HeatCoilIndex).ActualSC; + } + } + if (m_ref_IU_cond > 0) { + h_IU_cond_out_ave = h_IU_cond_out_ave / m_ref_IU_cond; + SC_IU_merged = SC_IU_merged / m_ref_IU_cond; + } else { + h_IU_cond_out_ave = refrig->getSatEnthalpy(state, refrig->getSatTemperature(state, clampedPcond, RoutineName) - 5.0, 0.0, RoutineName); + SC_IU_merged = 5; + m_ref_IU_cond = TU_HeatingLoad / (h_IU_cond_in - h_IU_cond_out_ave); + } +} + void VRFCondenserEquipment::CalcVRFCondenser_FluidTCtrl(EnergyPlusData &state, const bool FirstHVACIteration) { @@ -11287,12 +10038,10 @@ void VRFCondenserEquipment::CalcVRFCondenser_FluidTCtrl(EnergyPlusData &state, c Real64 h_IU_evap_in_low; // enthalpy of IU evaporator at inlet (low) [kJ/kg] Real64 h_IU_evap_in_up; // enthalpy of IU evaporator at inlet (up) [kJ/kg] Real64 h_IU_evap_out; // enthalpy of IU evaporator at outlet [kJ/kg] - Real64 h_IU_evap_out_i; // enthalpy of IU evaporator at outlet (individual) [kJ/kg] Real64 h_IU_cond_in; // enthalpy of IU condenser at inlet [kJ/kg] Real64 h_IU_cond_in_low; // enthalpy of IU condenser at inlet (low) [kJ/kg] Real64 h_IU_cond_in_up; // enthalpy of IU condenser at inlet (up) [kJ/kg] Real64 h_IU_cond_out; // enthalpy of IU condenser at outlet [kJ/kg] - Real64 h_IU_cond_out_i; // enthalpy of IU condenser at outlet (individual) [kJ/kg] Real64 h_IU_cond_out_ave; // average enthalpy of the refrigerant leaving IU condensers [kJ/kg] Real64 h_IU_PLc_out; // enthalpy of refrigerant at the outlet of IU evaporator side main pipe, after piping loss (c) [kJ/kg] Real64 h_comp_in; // enthalpy of refrigerant at compressor inlet, after piping loss (c) [kJ/kg] @@ -11301,9 +10050,7 @@ void VRFCondenserEquipment::CalcVRFCondenser_FluidTCtrl(EnergyPlusData &state, c Real64 h_comp_out_new; // enthalpy of refrigerant at compressor outlet (new) [kJ/kg] Real64 m_air; // OU coil air mass flow rate [kg/s] Real64 m_ref_IU_cond; // mass flow rate of Refrigerant through IU condensers [kg/s] - Real64 m_ref_IU_cond_i; // mass flow rate of Refrigerant through an individual IU condenser [kg/s] Real64 m_ref_IU_evap; // mass flow rate of Refrigerant through IU evaporators [kg/s] - Real64 m_ref_IU_evap_i; // mass flow rate of Refrigerant through an individual IU evaporator [kg/s] Real64 m_ref_OU_evap; // mass flow rate of Refrigerant through OU evaporator [kg/s] Real64 m_ref_OU_cond; // mass flow rate of Refrigerant through OU condenser [kg/s] Real64 Ncomp; // compressor power [W] @@ -11520,57 +10267,28 @@ void VRFCondenserEquipment::CalcVRFCondenser_FluidTCtrl(EnergyPlusData &state, c NumIteHIUIn = 1; bool converged_12; do { - m_ref_IU_evap = 0; - h_IU_evap_out = 0; - h_IU_evap_out_i = 0; - m_ref_IU_evap_i = 0; - SH_IU_merged = 0; - // Calculate total IU refrigerant flow rate and SH_IU_merged if (Q_c_TU_PL > CompEvaporatingCAPSpdMax) { // Required load is beyond the max system capacity - RefTSat = this->refrig->getSatTemperature(state, max(min(Pevap, RefPHigh), RefPLow), RoutineName); h_IU_evap_out = this->refrig->getSupHeatEnthalpy( state, max(RefTSat, this->IUEvaporatingTemp + 3), max(min(Pevap, RefPHigh), RefPLow), RoutineName); SH_IU_merged = 3; m_ref_IU_evap = TU_CoolingLoad / (h_IU_evap_out - h_IU_evap_in); - } else { - - for (NumTU = 1; NumTU <= NumTUInList; NumTU++) { // Calc total refrigerant flow rate - if (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad(NumTU) > 0) { - TUIndex = state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).ZoneTUPtr(NumTU); - CoolCoilIndex = state.dataHVACVarRefFlow->VRFTU(TUIndex).CoolCoilIndex; - - RefTSat = this->refrig->getSatTemperature(state, max(min(Pevap, RefPHigh), RefPLow), RoutineName); - h_IU_evap_out_i = this->refrig->getSupHeatEnthalpy( - state, - max(RefTSat, this->IUEvaporatingTemp + state.dataDXCoils->DXCoil(CoolCoilIndex).ActualSH), - max(min(Pevap, RefPHigh), RefPLow), - RoutineName); - - if (h_IU_evap_out_i > h_IU_evap_in) { - m_ref_IU_evap_i = (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad(NumTU) <= 0.0) - ? 0.0 - : (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad(NumTU) / - (h_IU_evap_out_i - h_IU_evap_in)); // Ref Flow Rate in the IU( kg/s ) - m_ref_IU_evap = m_ref_IU_evap + m_ref_IU_evap_i; - h_IU_evap_out = h_IU_evap_out + m_ref_IU_evap_i * h_IU_evap_out_i; - SH_IU_merged = SH_IU_merged + m_ref_IU_evap_i * state.dataDXCoils->DXCoil(CoolCoilIndex).ActualSH; - } - } - } - if (m_ref_IU_evap > 0) { - h_IU_evap_out = h_IU_evap_out / m_ref_IU_evap; - SH_IU_merged = SH_IU_merged / m_ref_IU_evap; - } else { - RefTSat = this->refrig->getSatTemperature(state, max(min(Pevap, RefPHigh), RefPLow), RoutineName); - h_IU_evap_out = this->refrig->getSupHeatEnthalpy( - state, max(RefTSat, this->IUEvaporatingTemp + 3), max(min(Pevap, RefPHigh), RefPLow), RoutineName); - SH_IU_merged = 3; - m_ref_IU_evap = TU_CoolingLoad / (h_IU_evap_out - h_IU_evap_in); - } + calcIUEvapRefFlowAndSH(state, + this->refrig, + this->IUEvaporatingTemp, + TUListNum, + NumTUInList, + Pevap, + RefPHigh, + RefPLow, + TU_CoolingLoad, + h_IU_evap_in, + m_ref_IU_evap, + h_IU_evap_out, + SH_IU_merged); } // *Calculate piping loss @@ -11706,14 +10424,9 @@ void VRFCondenserEquipment::CalcVRFCondenser_FluidTCtrl(EnergyPlusData &state, c bool converged_23; do { - m_ref_IU_cond = 0; - h_IU_cond_out_ave = 0; - SC_IU_merged = 0; - // Calculate total refrigerant flow rate if (Q_h_TU_PL > CompEvaporatingCAPSpdMax + CompEvaporatingPWRSpdMax) { // Required load is beyond the max system capacity - h_IU_cond_out = this->refrig->getSatEnthalpy(state, this->refrig->getSatTemperature(state, max(min(Pcond, RefPHigh), RefPLow), RoutineName) - 5.0, @@ -11722,39 +10435,19 @@ void VRFCondenserEquipment::CalcVRFCondenser_FluidTCtrl(EnergyPlusData &state, c h_IU_cond_out_ave = h_IU_cond_out; SC_IU_merged = 5; m_ref_IU_cond = TU_HeatingLoad / (h_IU_cond_in - h_IU_cond_out); - } else { - for (NumTU = 1; NumTU <= NumTUInList; NumTU++) { - if (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad(NumTU) > 0) { - TUIndex = state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).ZoneTUPtr(NumTU); - HeatCoilIndex = state.dataHVACVarRefFlow->VRFTU(TUIndex).HeatCoilIndex; - h_IU_cond_out_i = - this->refrig->getSatEnthalpy(state, - this->refrig->getSatTemperature(state, max(min(Pcond, RefPHigh), RefPLow), RoutineName) - - state.dataDXCoils->DXCoil(HeatCoilIndex).ActualSC, - 0.0, - RoutineName); // Quality=0 - m_ref_IU_cond_i = - (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad(NumTU) <= 0.0) - ? 0.0 - : (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad(NumTU) / (h_IU_cond_in - h_IU_cond_out_i)); - m_ref_IU_cond = m_ref_IU_cond + m_ref_IU_cond_i; - h_IU_cond_out_ave = h_IU_cond_out_ave + m_ref_IU_cond_i * h_IU_cond_out_i; - SC_IU_merged = SC_IU_merged + m_ref_IU_cond_i * state.dataDXCoils->DXCoil(HeatCoilIndex).ActualSC; - } - } - if (m_ref_IU_cond > 0) { - h_IU_cond_out_ave = h_IU_cond_out_ave / m_ref_IU_cond; // h_merge - SC_IU_merged = SC_IU_merged / m_ref_IU_cond; - } else { - h_IU_cond_out_ave = - this->refrig->getSatEnthalpy(state, - this->refrig->getSatTemperature(state, max(min(Pcond, RefPHigh), RefPLow), RoutineName) - 5.0, - 0.0, - RoutineName); // Quality=0 - SC_IU_merged = 5; - m_ref_IU_cond = TU_HeatingLoad / (h_IU_cond_in - h_IU_cond_out_ave); - } + calcIUCondRefFlowAndSC(state, + this->refrig, + TUListNum, + NumTUInList, + Pcond, + RefPHigh, + RefPLow, + TU_HeatingLoad, + h_IU_cond_in, + m_ref_IU_cond, + h_IU_cond_out_ave, + SC_IU_merged); } // *Calculate piping loss @@ -11944,40 +10637,18 @@ void VRFCondenserEquipment::CalcVRFCondenser_FluidTCtrl(EnergyPlusData &state, c bool converged_230; do { // *PL-h: Calculate total refrigerant flow rate - m_ref_IU_cond = 0; - h_IU_cond_out_ave = 0; - SC_IU_merged = 0; - for (NumTU = 1; NumTU <= NumTUInList; NumTU++) { - if (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad(NumTU) > 0) { - TUIndex = state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).ZoneTUPtr(NumTU); - HeatCoilIndex = state.dataHVACVarRefFlow->VRFTU(TUIndex).HeatCoilIndex; - h_IU_cond_out_i = - this->refrig->getSatEnthalpy(state, - this->refrig->getSatTemperature(state, max(min(Pcond, RefPHigh), RefPLow), RoutineName) - - state.dataDXCoils->DXCoil(HeatCoilIndex).ActualSC, - 0.0, - RoutineName); // Quality=0 - m_ref_IU_cond_i = - (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad(NumTU) <= 0.0) - ? 0.0 - : (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad(NumTU) / (h_IU_cond_in - h_IU_cond_out_i)); - m_ref_IU_cond = m_ref_IU_cond + m_ref_IU_cond_i; - h_IU_cond_out_ave = h_IU_cond_out_ave + m_ref_IU_cond_i * h_IU_cond_out_i; - SC_IU_merged = SC_IU_merged + m_ref_IU_cond_i * state.dataDXCoils->DXCoil(HeatCoilIndex).ActualSC; - } - } - if (m_ref_IU_cond > 0) { - h_IU_cond_out_ave = h_IU_cond_out_ave / m_ref_IU_cond; - SC_IU_merged = SC_IU_merged / m_ref_IU_cond; - } else { - h_IU_cond_out_ave = - this->refrig->getSatEnthalpy(state, - this->refrig->getSatTemperature(state, max(min(Pcond, RefPHigh), RefPLow), RoutineName) - 5.0, - 0.0, - RoutineName); // Quality=0 - SC_IU_merged = 5; - m_ref_IU_cond = TU_HeatingLoad / (h_IU_cond_in - h_IU_cond_out_ave); - } + calcIUCondRefFlowAndSC(state, + this->refrig, + TUListNum, + NumTUInList, + Pcond, + RefPHigh, + RefPLow, + TU_HeatingLoad, + h_IU_cond_in, + m_ref_IU_cond, + h_IU_cond_out_ave, + SC_IU_merged); // *PL-h: Calculate piping loss this->VRFOU_PipeLossH( @@ -11988,42 +10659,19 @@ void VRFCondenserEquipment::CalcVRFCondenser_FluidTCtrl(EnergyPlusData &state, c // *PL-c: Calculate total IU refrigerant flow rate and SH_IU_merged h_IU_evap_in = h_IU_cond_out_ave; - m_ref_IU_evap = 0; - h_IU_evap_out = 0; - SH_IU_merged = 0; - for (NumTU = 1; NumTU <= NumTUInList; NumTU++) { // Calc total refrigerant flow rate - if (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad(NumTU) > 0) { - TUIndex = state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).ZoneTUPtr(NumTU); - CoolCoilIndex = state.dataHVACVarRefFlow->VRFTU(TUIndex).CoolCoilIndex; - - RefTSat = this->refrig->getSatTemperature(state, max(min(Pevap, RefPHigh), RefPLow), RoutineName); - h_IU_evap_out_i = - this->refrig->getSupHeatEnthalpy(state, - max(RefTSat, this->IUEvaporatingTemp + state.dataDXCoils->DXCoil(CoolCoilIndex).ActualSH), - max(min(Pevap, RefPHigh), RefPLow), - RoutineName); - - if (h_IU_evap_out_i > h_IU_evap_in) { - m_ref_IU_evap_i = (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad(NumTU) <= 0.0) - ? 0.0 - : (state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad(NumTU) / - (h_IU_evap_out_i - h_IU_evap_in)); // Ref Flow Rate in the IU( kg/s ) - m_ref_IU_evap = m_ref_IU_evap + m_ref_IU_evap_i; - h_IU_evap_out = h_IU_evap_out + m_ref_IU_evap_i * h_IU_evap_out_i; - SH_IU_merged = SH_IU_merged + m_ref_IU_evap_i * state.dataDXCoils->DXCoil(CoolCoilIndex).ActualSH; - } - } - } - if (m_ref_IU_evap > 0) { - h_IU_evap_out = h_IU_evap_out / m_ref_IU_evap; - SH_IU_merged = SH_IU_merged / m_ref_IU_evap; - } else { - RefTSat = this->refrig->getSatTemperature(state, max(min(Pevap, RefPHigh), RefPLow), RoutineName); - h_IU_evap_out = this->refrig->getSupHeatEnthalpy( - state, max(RefTSat, this->IUEvaporatingTemp + 3), max(min(Pevap, RefPHigh), RefPLow), RoutineName); - SH_IU_merged = 3; - m_ref_IU_evap = TU_CoolingLoad / (h_IU_evap_out - h_IU_evap_in); - } + calcIUEvapRefFlowAndSH(state, + this->refrig, + this->IUEvaporatingTemp, + TUListNum, + NumTUInList, + Pevap, + RefPHigh, + RefPLow, + TU_CoolingLoad, + h_IU_evap_in, + m_ref_IU_evap, + h_IU_evap_out, + SH_IU_merged); // *PL-c: Calculate piping loss this->VRFOU_PipeLossC(state, diff --git a/src/EnergyPlus/HeatBalanceAirManager.cc b/src/EnergyPlus/HeatBalanceAirManager.cc index e3e002c695e..2cab40ce65f 100644 --- a/src/EnergyPlus/HeatBalanceAirManager.cc +++ b/src/EnergyPlus/HeatBalanceAirManager.cc @@ -232,6 +232,641 @@ void SetZoneMassConservationFlag(EnergyPlusData &state) } } +// Helper: set up the 11 standard "Zone Mixing" output variables for a given zone. +// Called from five places in GetSimpleAirModelInputs (Mixing, CrossMixing to-zone, +// CrossMixing from-zone, RefDoorMixing zone-A, and RefDoorMixing zone-B). +static void setupZoneMixingOutputVars(EnergyPlusData &state, DataHeatBalance::AirReportVars &znAirRpt, std::string const &zoneName) +{ + SetupOutputVariable(state, + "Zone Mixing Volume", + Constant::Units::m3, + znAirRpt.MixVolume, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Mixing Current Density Volume Flow Rate", + Constant::Units::m3_s, + znAirRpt.MixVdotCurDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Mixing Standard Density Volume Flow Rate", + Constant::Units::m3_s, + znAirRpt.MixVdotStdDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Mixing Mass", + Constant::Units::kg, + znAirRpt.MixMass, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Mixing Mass Flow Rate", + Constant::Units::kg_s, + znAirRpt.MixMdot, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Mixing Sensible Heat Loss Energy", + Constant::Units::J, + znAirRpt.MixHeatLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Mixing Sensible Heat Gain Energy", + Constant::Units::J, + znAirRpt.MixHeatGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Mixing Latent Heat Loss Energy", + Constant::Units::J, + znAirRpt.MixLatentLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Mixing Latent Heat Gain Energy", + Constant::Units::J, + znAirRpt.MixLatentGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Mixing Total Heat Loss Energy", + Constant::Units::J, + znAirRpt.MixTotalLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Mixing Total Heat Gain Energy", + Constant::Units::J, + znAirRpt.MixTotalGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); +} + +// Helper: set up the 18 standard "Zone Ventilation" output variables for a given zone. +// Called from two places in GetSimpleAirModelInputs (DesignFlowRate and WindAndStackOpenArea). +static void setupZoneVentilationOutputVars(EnergyPlusData &state, DataHeatBalance::AirReportVars &znAirRpt, std::string const &zoneName) +{ + SetupOutputVariable(state, + "Zone Ventilation Sensible Heat Loss Energy", + Constant::Units::J, + znAirRpt.VentilHeatLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Sensible Heat Gain Energy", + Constant::Units::J, + znAirRpt.VentilHeatGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Latent Heat Loss Energy", + Constant::Units::J, + znAirRpt.VentilLatentLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Latent Heat Gain Energy", + Constant::Units::J, + znAirRpt.VentilLatentGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Total Heat Loss Energy", + Constant::Units::J, + znAirRpt.VentilTotalLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Total Heat Gain Energy", + Constant::Units::J, + znAirRpt.VentilTotalGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Current Density Volume Flow Rate", + Constant::Units::m3_s, + znAirRpt.VentilVdotCurDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Standard Density Volume Flow Rate", + Constant::Units::m3_s, + znAirRpt.VentilVdotStdDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Outdoor Density Volume Flow Rate", + Constant::Units::m3_s, + znAirRpt.VentilVdotOutDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Current Density Volume", + Constant::Units::m3, + znAirRpt.VentilVolumeCurDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Standard Density Volume", + Constant::Units::m3, + znAirRpt.VentilVolumeStdDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Mass", + Constant::Units::kg, + znAirRpt.VentilMass, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Mass Flow Rate", + Constant::Units::kg_s, + znAirRpt.VentilMdot, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Current Density Air Change Rate", + Constant::Units::ach, + znAirRpt.VentilAirChangeRateCurDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Standard Density Air Change Rate", + Constant::Units::ach, + znAirRpt.VentilAirChangeRateStdDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Outdoor Density Air Change Rate", + Constant::Units::ach, + znAirRpt.VentilAirChangeRateOutDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Fan Electricity Energy", + Constant::Units::J, + znAirRpt.VentilFanElec, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName, + Constant::eResource::Electricity, + OutputProcessor::Group::Building, + OutputProcessor::EndUseCat::Fans, + "Ventilation (simple)", + zoneName); + SetupOutputVariable(state, + "Zone Ventilation Air Inlet Temperature", + Constant::Units::C, + znAirRpt.VentilAirTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); +} + +// Helper: read the primary numeric field for EffectiveLeakageArea and FlowCoefficient +// infiltration objects, computing the exterior-surface-area space fraction and checking +// that the space has exterior surfaces. Returns the space-fractioned value in destValue. +static void readExteriorAreaInfiltrationInput(EnergyPlusData &state, + bool &errorsFound, + std::string_view routineName, + std::string_view currentModuleObject, + InternalHeatGains::GlobalInternalGainMiscObject const &inputObj, + DataHeatBalance::ZoneData const &thisZone, + DataHeatBalance::SpaceData const &thisSpace, + int spaceIndex, + Array1D const &rNumericArgs, + Array1D_bool const &lNumericFieldBlanks, + Array1D_string const &cNumericFieldNames, + Real64 &destValue) +{ + if (lNumericFieldBlanks(1)) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\", field {} is blank. 0 Infiltration will result.", + routineName, + currentModuleObject, + inputObj.Name, + cNumericFieldNames(1))); + } else { + Real64 spaceFrac = 1.0; + if (!inputObj.spaceListActive && (inputObj.numOfSpaces > 1)) { + Real64 const zoneExteriorTotalSurfArea = thisZone.ExteriorTotalSurfArea; + if (zoneExteriorTotalSurfArea > 0.0) { + spaceFrac = thisSpace.ExteriorTotalSurfArea / zoneExteriorTotalSurfArea; + } else { + ShowSevereError(state, + EnergyPlus::format("{}Zone exterior surface area is zero when allocating Infiltration to Spaces.", routineName)); + ShowContinueError(state, + EnergyPlus::format("Occurs for {}=\"{}\" in Zone=\"{}\".", currentModuleObject, inputObj.Name, thisZone.Name)); + errorsFound = true; + } + } + destValue = rNumericArgs(1) * spaceFrac; + } + if (spaceIndex > 0 && thisSpace.ExteriorTotalSurfArea <= 0.0) { + ShowWarningError(state, + EnergyPlus::format(R"({}{}="{}", Space="{}" does not have surfaces exposed to outdoors.)", + routineName, + currentModuleObject, + inputObj.Name, + thisSpace.Name)); + ShowContinueError(state, "Infiltration model is appropriate for exterior spaces not interior spaces, simulation continues."); + } +} + +// Helper: compute the design-level airflow for FlowPerArea, FlowPerPerson, and AirChanges +// AirflowSpec cases, which share identical logic across Ventilation, Mixing, and CrossMixing. +// Returns true if the case was handled; false for FlowPerZone, FlowPerExterior*, or Invalid +// (which the caller must handle itself). +static bool computeAirflowDesignLevel(EnergyPlusData &state, + AirflowSpec flow, + Real64 &designLevel, + int spaceIndex, + DataHeatBalance::SpaceData const &thisSpace, + Array1D const &rNumericArgs, + Array1D_bool const &lNumericFieldBlanks, + Array1D_string const &cAlphaFieldNames, + Array1D_string const &cNumericFieldNames, + std::string_view routineName, + std::string_view currentModuleObject, + std::string_view objName, + std::string_view flowTypeName, + bool &errorsFound) +{ + switch (flow) { + case AirflowSpec::FlowPerArea: + if (spaceIndex != 0) { + if (rNumericArgs(2) >= 0.0) { + designLevel = rNumericArgs(2) * thisSpace.FloorArea; + if (thisSpace.FloorArea <= 0.0) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Space Floor Area = 0. 0 {} will result.", + routineName, + currentModuleObject, + objName, + cAlphaFieldNames(4), + cNumericFieldNames(2), + flowTypeName)); + } + } else { + ShowSevereError( + state, + EnergyPlus::format( + "{}{}=\"{}\", invalid flow/area specification [<0.0]={:.3R}", routineName, currentModuleObject, objName, rNumericArgs(2))); + errorsFound = true; + } + } + if (lNumericFieldBlanks(2)) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 {} will result.", + routineName, + currentModuleObject, + objName, + cAlphaFieldNames(4), + cNumericFieldNames(2), + flowTypeName)); + } + return true; + + case AirflowSpec::FlowPerPerson: + if (spaceIndex != 0) { + if (rNumericArgs(3) >= 0.0) { + designLevel = rNumericArgs(3) * thisSpace.TotOccupants; + if (thisSpace.TotOccupants <= 0.0) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Space Total Occupants = 0. 0 {} will result.", + routineName, + currentModuleObject, + objName, + cAlphaFieldNames(4), + cNumericFieldNames(3), + flowTypeName)); + } + } else { + ShowSevereError( + state, + EnergyPlus::format( + "{}{}=\"{}\", invalid flow/person specification [<0.0]={:.3R}", routineName, currentModuleObject, objName, rNumericArgs(3))); + errorsFound = true; + } + } + if (lNumericFieldBlanks(3)) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 {} will result.", + routineName, + currentModuleObject, + objName, + cAlphaFieldNames(4), + cNumericFieldNames(3), + flowTypeName)); + } + return true; + + case AirflowSpec::AirChanges: + if (spaceIndex != 0) { + if (rNumericArgs(4) >= 0.0) { + designLevel = rNumericArgs(4) * thisSpace.Volume / Constant::rSecsInHour; + if (thisSpace.Volume <= 0.0) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Space Volume = 0. 0 {} will result.", + routineName, + currentModuleObject, + objName, + cAlphaFieldNames(4), + cNumericFieldNames(4), + flowTypeName)); + } + } else { + ShowSevereError(state, + EnergyPlus::format("{}{}=\"{}\", invalid ACH (air changes per hour) specification [<0.0]={:.3R}", + routineName, + currentModuleObject, + objName, + rNumericArgs(4))); + errorsFound = true; + } + } + if (lNumericFieldBlanks(4)) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 {} will result.", + routineName, + currentModuleObject, + objName, + cAlphaFieldNames(4), + cNumericFieldNames(4), + flowTypeName)); + } + return true; + + default: + return false; + } +} + +// Helper: set up the 16 standard per-object "Infiltration" output variables. +static void setupInfiltrationObjOutputVars(EnergyPlusData &state, DataHeatBalance::InfiltrationData &infil) +{ + std::string const &name = infil.Name; + SetupOutputVariable(state, + "Infiltration Sensible Heat Loss Energy", + Constant::Units::J, + infil.InfilHeatLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + "Infiltration Sensible Heat Gain Energy", + Constant::Units::J, + infil.InfilHeatGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + "Infiltration Latent Heat Loss Energy", + Constant::Units::J, + infil.InfilLatentLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + "Infiltration Latent Heat Gain Energy", + Constant::Units::J, + infil.InfilLatentGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + "Infiltration Total Heat Loss Energy", + Constant::Units::J, + infil.InfilTotalLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + "Infiltration Total Heat Gain Energy", + Constant::Units::J, + infil.InfilTotalGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + "Infiltration Current Density Volume Flow Rate", + Constant::Units::m3_s, + infil.InfilVdotCurDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + "Infiltration Standard Density Volume Flow Rate", + Constant::Units::m3_s, + infil.InfilVdotStdDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + "Infiltration Outdoor Density Volume Flow Rate", + Constant::Units::m3_s, + infil.InfilVdotOutDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + "Infiltration Current Density Volume", + Constant::Units::m3, + infil.InfilVolumeCurDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + "Infiltration Standard Density Volume", + Constant::Units::m3, + infil.InfilVolumeStdDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + "Infiltration Mass", + Constant::Units::kg, + infil.InfilMass, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + "Infiltration Mass Flow Rate", + Constant::Units::kg_s, + infil.InfilMdot, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + "Infiltration Current Density Air Change Rate", + Constant::Units::ach, + infil.InfilAirChangeRateCurDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + "Infiltration Standard Density Air Change Rate", + Constant::Units::ach, + infil.InfilAirChangeRateStdDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + "Infiltration Outdoor Density Air Change Rate", + Constant::Units::ach, + infil.InfilAirChangeRateOutDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + name); +} + +// Helper: set up the 16 standard zone-level "Zone Infiltration" output variables. +static void setupZoneInfiltrationOutputVars(EnergyPlusData &state, DataHeatBalance::AirReportVars &znAirRpt, std::string const &zoneName) +{ + SetupOutputVariable(state, + "Zone Infiltration Sensible Heat Loss Energy", + Constant::Units::J, + znAirRpt.InfilHeatLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Sensible Heat Gain Energy", + Constant::Units::J, + znAirRpt.InfilHeatGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Latent Heat Loss Energy", + Constant::Units::J, + znAirRpt.InfilLatentLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Latent Heat Gain Energy", + Constant::Units::J, + znAirRpt.InfilLatentGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Total Heat Loss Energy", + Constant::Units::J, + znAirRpt.InfilTotalLoss, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Total Heat Gain Energy", + Constant::Units::J, + znAirRpt.InfilTotalGain, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Current Density Volume Flow Rate", + Constant::Units::m3_s, + znAirRpt.InfilVdotCurDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Standard Density Volume Flow Rate", + Constant::Units::m3_s, + znAirRpt.InfilVdotStdDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Outdoor Density Volume Flow Rate", + Constant::Units::m3_s, + znAirRpt.InfilVdotOutDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Current Density Volume", + Constant::Units::m3, + znAirRpt.InfilVolumeCurDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Standard Density Volume", + Constant::Units::m3, + znAirRpt.InfilVolumeStdDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Mass", + Constant::Units::kg, + znAirRpt.InfilMass, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Mass Flow Rate", + Constant::Units::kg_s, + znAirRpt.InfilMdot, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Current Density Air Change Rate", + Constant::Units::ach, + znAirRpt.InfilAirChangeRateCurDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Standard Density Air Change Rate", + Constant::Units::ach, + znAirRpt.InfilAirChangeRateStdDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); + SetupOutputVariable(state, + "Zone Infiltration Outdoor Density Air Change Rate", + Constant::Units::ach, + znAirRpt.InfilAirChangeRateOutDensity, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + zoneName); +} + void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF errors found in input { @@ -286,6 +921,27 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err "! <{} Airflow Stats Nominal>,Name,Input Object, Schedule Name,Zone Name, Zone Floor Area {{m2}}, # Zone Occupants,{}\n"); static constexpr std::string_view Format_722(" {}, {}\n"); + // Helper lambda: look up an optional temperature-limit schedule by alpha index. + // If NumAlpha > alphaThreshold and the field is not blank, look up the schedule, + // validate that all values are within [-MixingTempLimit, MixingTempLimit], and + // assign the result to schedOut. Reports errors on missing or out-of-range schedules. + auto getOptionalTempLimitSched = [&](const ErrorObjectHeader &eoh, int alphaThreshold, int alphaIdx, Sched::Schedule *&schedOut) { + if (NumAlpha <= alphaThreshold) { + return; + } + if (lAlphaFieldBlanks(alphaIdx)) { + return; + } + if ((schedOut = Sched::GetSchedule(state, cAlphaArgs(alphaIdx))) == nullptr) { + ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(alphaIdx), cAlphaArgs(alphaIdx)); + ErrorsFound = true; + } else if (!schedOut->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { + Sched::ShowSevereBadMinMax( + state, eoh, cAlphaFieldNames(alphaIdx), cAlphaArgs(alphaIdx), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); + ErrorsFound = true; + } + }; + RepVarSet.dimension(state.dataGlobal->NumOfZones, true); // Following used for reporting @@ -426,15 +1082,11 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err lAlphaFieldBlanks.dimension(maxAlpha, true); lNumericFieldBlanks.dimension(maxNumber, true); - cCurrentModuleObject = "ZoneAirBalance:OutdoorAir"; - state.dataHeatBal->TotZoneAirBalance = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject); - - state.dataHeatBal->ZoneAirBalance.allocate(state.dataHeatBal->TotZoneAirBalance); - - for (int Loop = 1; Loop <= state.dataHeatBal->TotZoneAirBalance; ++Loop) { + // Helper lambda that wraps the repeated 11-argument getObjectItem call. + auto getItem = [&](int itemNum) { state.dataInputProcessing->inputProcessor->getObjectItem(state, cCurrentModuleObject, - Loop, + itemNum, cAlphaArgs, NumAlpha, rNumericArgs, @@ -444,6 +1096,15 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err lAlphaFieldBlanks, cAlphaFieldNames, cNumericFieldNames); + }; + + cCurrentModuleObject = "ZoneAirBalance:OutdoorAir"; + state.dataHeatBal->TotZoneAirBalance = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject); + + state.dataHeatBal->ZoneAirBalance.allocate(state.dataHeatBal->TotZoneAirBalance); + + for (int Loop = 1; Loop <= state.dataHeatBal->TotZoneAirBalance; ++Loop) { + getItem(Loop); ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)}; bool IsNotOK = false; @@ -681,18 +1342,7 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err cCurrentModuleObject = "ZoneInfiltration:DesignFlowRate"; for (int infilInputNum = 1; infilInputNum <= numDesignFlowInfiltrationObjects; ++infilInputNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - cCurrentModuleObject, - infilInputNum, - cAlphaArgs, - NumAlpha, - rNumericArgs, - NumNumber, - IOStat, - lNumericFieldBlanks, - lAlphaFieldBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(infilInputNum); ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)}; // Create one Infiltration instance for every space associated with this input object @@ -928,18 +1578,7 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err if (totLeakageAreaInfiltration > 0) { cCurrentModuleObject = "ZoneInfiltration:EffectiveLeakageArea"; for (int infilInputNum = 1; infilInputNum <= numLeakageAreaInfiltrationObjects; ++infilInputNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - cCurrentModuleObject, - infilInputNum, - cAlphaArgs, - NumAlpha, - rNumericArgs, - NumNumber, - IOStat, - lNumericFieldBlanks, - lAlphaFieldBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(infilInputNum); ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)}; @@ -965,45 +1604,18 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err thisInfiltration.BasicStackCoefficient = rNumericArgs(2); thisInfiltration.BasicWindCoefficient = rNumericArgs(3); - if (lNumericFieldBlanks(1)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", field {} is blank. 0 Infiltration will result.", - RoutineName, - cCurrentModuleObject, - thisInfiltrationInput.Name, - cNumericFieldNames(1))); - } else { - Real64 spaceFrac = 1.0; - if (!thisInfiltrationInput.spaceListActive && (thisInfiltrationInput.numOfSpaces > 1)) { - Real64 const zoneExteriorTotalSurfArea = thisZone.ExteriorTotalSurfArea; - if (zoneExteriorTotalSurfArea > 0.0) { - spaceFrac = thisSpace.ExteriorTotalSurfArea / zoneExteriorTotalSurfArea; - } else { - ShowSevereError( - state, - EnergyPlus::format("{}Zone exterior surface area is zero when allocating Infiltration to Spaces.", RoutineName)); - ShowContinueError( - state, - EnergyPlus::format( - "Occurs for {}=\"{}\" in Zone=\"{}\".", cCurrentModuleObject, thisInfiltrationInput.Name, thisZone.Name)); - ErrorsFound = true; - } - } - - thisInfiltration.LeakageArea = rNumericArgs(1) * spaceFrac; - } - // check if space has exterior surfaces - if (thisInfiltration.spaceIndex > 0) { - if (thisSpace.ExteriorTotalSurfArea <= 0.0) { - ShowWarningError(state, - EnergyPlus::format(R"({}{}="{}", Space="{}" does not have surfaces exposed to outdoors.)", - RoutineName, - cCurrentModuleObject, - thisInfiltrationInput.Name, - thisSpace.Name)); - ShowContinueError(state, "Infiltration model is appropriate for exterior spaces not interior spaces, simulation continues."); - } - } + readExteriorAreaInfiltrationInput(state, + ErrorsFound, + RoutineName, + cCurrentModuleObject, + thisInfiltrationInput, + thisZone, + thisSpace, + thisInfiltration.spaceIndex, + rNumericArgs, + lNumericFieldBlanks, + cNumericFieldNames, + thisInfiltration.LeakageArea); } } } @@ -1011,18 +1623,7 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err if (totFlowCoefficientInfiltration > 0) { cCurrentModuleObject = "ZoneInfiltration:FlowCoefficient"; for (int infilInputNum = 1; infilInputNum <= numFlowCoefficientInfiltrationObjects; ++infilInputNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - cCurrentModuleObject, - infilInputNum, - cAlphaArgs, - NumAlpha, - rNumericArgs, - NumNumber, - IOStat, - lNumericFieldBlanks, - lAlphaFieldBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(infilInputNum); ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)}; @@ -1050,46 +1651,18 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err thisInfiltration.AIM2WindCoefficient = rNumericArgs(4); thisInfiltration.ShelterFactor = rNumericArgs(5); - if (lNumericFieldBlanks(1)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", field {} is blank. 0 Infiltration will result.", - RoutineName, - cCurrentModuleObject, - thisInfiltrationInput.Name, - cNumericFieldNames(1))); - } else { - Real64 spaceFrac = 1.0; - if (!thisInfiltrationInput.spaceListActive && (thisInfiltrationInput.numOfSpaces > 1)) { - Real64 const zoneExteriorTotalSurfArea = thisZone.ExteriorTotalSurfArea; - if (zoneExteriorTotalSurfArea > 0.0) { - spaceFrac = thisSpace.ExteriorTotalSurfArea / zoneExteriorTotalSurfArea; - } else { - ShowSevereError( - state, - EnergyPlus::format("{}Zone exterior surface area is zero when allocating Infiltration to Spaces.", RoutineName)); - ShowContinueError( - state, - EnergyPlus::format( - "Occurs for {}=\"{}\" in Zone=\"{}\".", cCurrentModuleObject, thisInfiltrationInput.Name, thisZone.Name)); - ErrorsFound = true; - } - } - - thisInfiltration.FlowCoefficient = rNumericArgs(1) * spaceFrac; - // check if space has exterior surfaces - if (thisInfiltration.spaceIndex > 0) { - if (thisSpace.ExteriorTotalSurfArea <= 0.0) { - ShowWarningError(state, - EnergyPlus::format(R"({}{}="{}", Space="{}" does not have surfaces exposed to outdoors.)", - RoutineName, - cCurrentModuleObject, - thisInfiltrationInput.Name, - thisSpace.Name)); - ShowContinueError(state, - "Infiltration model is appropriate for exterior spaces not interior spaces, simulation continues."); - } - } - } + readExteriorAreaInfiltrationInput(state, + ErrorsFound, + RoutineName, + cCurrentModuleObject, + thisInfiltrationInput, + thisZone, + thisSpace, + thisInfiltration.spaceIndex, + rNumericArgs, + lNumericFieldBlanks, + cNumericFieldNames, + thisInfiltration.FlowCoefficient); } } } @@ -1099,233 +1672,13 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err if (state.dataHeatBal->Infiltration(Loop).ZonePtr > 0 && !state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).zoneOAQuadratureSum) { // Object report variables - SetupOutputVariable(state, - "Infiltration Sensible Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->Infiltration(Loop).InfilHeatLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Sensible Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->Infiltration(Loop).InfilHeatGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Latent Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->Infiltration(Loop).InfilLatentLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Latent Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->Infiltration(Loop).InfilLatentGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Total Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->Infiltration(Loop).InfilTotalLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Total Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->Infiltration(Loop).InfilTotalGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Current Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->Infiltration(Loop).InfilVdotCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Standard Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->Infiltration(Loop).InfilVdotStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Outdoor Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->Infiltration(Loop).InfilVdotOutDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Current Density Volume", - Constant::Units::m3, - state.dataHeatBal->Infiltration(Loop).InfilVolumeCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Standard Density Volume", - Constant::Units::m3, - state.dataHeatBal->Infiltration(Loop).InfilVolumeStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Mass", - Constant::Units::kg, - state.dataHeatBal->Infiltration(Loop).InfilMass, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Mass Flow Rate", - Constant::Units::kg_s, - state.dataHeatBal->Infiltration(Loop).InfilMdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Current Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->Infiltration(Loop).InfilAirChangeRateCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Standard Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->Infiltration(Loop).InfilAirChangeRateStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Infiltration(Loop).Name); - SetupOutputVariable(state, - "Infiltration Outdoor Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->Infiltration(Loop).InfilAirChangeRateOutDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Infiltration(Loop).Name); + setupInfiltrationObjOutputVars(state, state.dataHeatBal->Infiltration(Loop)); if (RepVarSet(state.dataHeatBal->Infiltration(Loop).ZonePtr)) { RepVarSet(state.dataHeatBal->Infiltration(Loop).ZonePtr) = false; - SetupOutputVariable(state, - "Zone Infiltration Sensible Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilHeatLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Sensible Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilHeatGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Latent Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilLatentLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Latent Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilLatentGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Total Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilTotalLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Total Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilTotalGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Current Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilVdotCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Standard Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilVdotStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Outdoor Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilVdotOutDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Current Density Volume", - Constant::Units::m3, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilVolumeCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Standard Density Volume", - Constant::Units::m3, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilVolumeStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Mass", - Constant::Units::kg, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilMass, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Mass Flow Rate", - Constant::Units::kg_s, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilMdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Current Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilAirChangeRateCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Standard Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilAirChangeRateStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); - SetupOutputVariable(state, - "Zone Infiltration Outdoor Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr).InfilAirChangeRateOutDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); + setupZoneInfiltrationOutputVars(state, + state.dataHeatBal->ZnAirRpt(state.dataHeatBal->Infiltration(Loop).ZonePtr), + state.dataHeatBal->Zone(state.dataHeatBal->Infiltration(Loop).ZonePtr).Name); } } @@ -1366,23 +1719,27 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err state.dataHeatBal->TotVentilation = totDesignFlowVentilation + totWindStackVentilation; state.dataHeatBal->Ventilation.allocate(state.dataHeatBal->TotVentilation); + // Helper lambda: register zone-level output vars (first time only) and EMS actuator for a ventilation object. + // Called identically at the end of both the DesignFlowRate and WindAndStack ventilation input loops. + auto finalizeVentilationObject = [&](DataHeatBalance::VentilationData &vent, const DataHeatBalance::ZoneData &zone) { + if (vent.ZonePtr > 0) { + if (RepVarSet(vent.ZonePtr) && !zone.zoneOAQuadratureSum) { + RepVarSet(vent.ZonePtr) = false; + setupZoneVentilationOutputVars(state, state.dataHeatBal->ZnAirRpt(vent.ZonePtr), zone.Name); + } + } + if (state.dataGlobal->AnyEnergyManagementSystemInModel) { + SetupEMSActuator( + state, "Zone Ventilation", vent.Name, "Air Exchange Flow Rate", "[m3/s]", vent.EMSSimpleVentOn, vent.EMSimpleVentFlowRate); + } + }; + int ventilationNum = 0; if (numDesignFlowVentilationObjects > 0) { cCurrentModuleObject = "ZoneVentilation:DesignFlowRate"; for (int ventInputNum = 1; ventInputNum <= numDesignFlowVentilationObjects; ++ventInputNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - cCurrentModuleObject, - ventInputNum, - cAlphaArgs, - NumAlpha, - rNumericArgs, - NumNumber, - IOStat, - lNumericFieldBlanks, - lAlphaFieldBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(ventInputNum); ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)}; auto &thisVentilationInput = ventilationDesignFlowRateObjects(ventInputNum); @@ -1400,133 +1757,39 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err thisVentilation.availSched = Sched::GetScheduleAlwaysOn(state); // Defaults to constant-1.0 } else if ((thisVentilation.availSched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { if (Item1 == 1) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - ErrorsFound = true; - } - } - - // Ventilation equipment design level calculation method - AirflowSpec flow = static_cast(getEnumValue(airflowSpecNamesUC, cAlphaArgs(4))); // NOLINT(modernize-use-auto) - switch (flow) { - case AirflowSpec::FlowPerZone: - thisVentilation.DesignLevel = rNumericArgs(1); - if (lNumericFieldBlanks(1)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Ventilation will result.", - RoutineName, - cCurrentModuleObject, - thisVentilation.Name, - cAlphaFieldNames(4), - cNumericFieldNames(1))); - } - break; - - case AirflowSpec::FlowPerArea: - if (thisVentilation.spaceIndex != 0) { - if (rNumericArgs(2) >= 0.0) { - thisVentilation.DesignLevel = rNumericArgs(2) * thisSpace.FloorArea; - if (thisSpace.FloorArea <= 0.0) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Space Floor Area = 0. 0 Ventilation will result.", - RoutineName, - cCurrentModuleObject, - thisVentilation.Name, - cAlphaFieldNames(4), - cNumericFieldNames(2))); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid flow/area specification [<0.0]={:.3R}", - RoutineName, - cCurrentModuleObject, - thisVentilation.Name, - rNumericArgs(2))); - ErrorsFound = true; - } - } - if (lNumericFieldBlanks(2)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Ventilation will result.", - RoutineName, - cCurrentModuleObject, - thisVentilation.Name, - cAlphaFieldNames(4), - cNumericFieldNames(2))); - } - break; - - case AirflowSpec::FlowPerPerson: - if (thisVentilation.spaceIndex != 0) { - if (rNumericArgs(3) >= 0.0) { - thisVentilation.DesignLevel = rNumericArgs(3) * thisSpace.TotOccupants; - if (thisSpace.TotOccupants <= 0.0) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Zone Total Occupants = 0. 0 Ventilation will result.", - RoutineName, - cCurrentModuleObject, - thisVentilation.Name, - cAlphaFieldNames(4), - cNumericFieldNames(3))); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid flow/person specification [<0.0]={:.3R}", - RoutineName, - cCurrentModuleObject, - thisVentilation.Name, - rNumericArgs(3))); - ErrorsFound = true; - } - } - if (lNumericFieldBlanks(3)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {}specifies {}, but that field is blank. 0 Ventilation will result.", - RoutineName, - cCurrentModuleObject, - thisVentilation.Name, - cAlphaFieldNames(4), - cNumericFieldNames(3))); + ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); + ErrorsFound = true; } - break; + } - case AirflowSpec::AirChanges: - if (thisVentilation.spaceIndex != 0) { - if (rNumericArgs(4) >= 0.0) { - thisVentilation.DesignLevel = rNumericArgs(4) * thisSpace.Volume / Constant::rSecsInHour; - if (thisSpace.Volume <= 0.0) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Space Volume = 0. 0 Ventilation will result.", - RoutineName, - cCurrentModuleObject, - thisVentilation.Name, - cAlphaFieldNames(4), - cNumericFieldNames(4))); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid ACH (air changes per hour) specification [<0.0]={:.3R}", - RoutineName, - cCurrentModuleObject, - thisVentilation.Name, - rNumericArgs(5))); - ErrorsFound = true; + // Ventilation equipment design level calculation method + AirflowSpec flow = static_cast(getEnumValue(airflowSpecNamesUC, cAlphaArgs(4))); // NOLINT(modernize-use-auto) + if (!computeAirflowDesignLevel(state, + flow, + thisVentilation.DesignLevel, + thisVentilation.spaceIndex, + thisSpace, + rNumericArgs, + lNumericFieldBlanks, + cAlphaFieldNames, + cNumericFieldNames, + RoutineName, + cCurrentModuleObject, + thisVentilation.Name, + "Ventilation", + ErrorsFound)) { + if (flow == AirflowSpec::FlowPerZone) { + thisVentilation.DesignLevel = rNumericArgs(1); + if (lNumericFieldBlanks(1)) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Ventilation will result.", + RoutineName, + cCurrentModuleObject, + thisVentilation.Name, + cAlphaFieldNames(4), + cNumericFieldNames(1))); } - } - if (lNumericFieldBlanks(4)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Ventilation will result.", - RoutineName, - cCurrentModuleObject, - thisVentilation.Name, - cAlphaFieldNames(4), - cNumericFieldNames(4))); - } - break; - - default: - if (Item1 == 1) { + } else if (Item1 == 1) { ShowSevereError( state, EnergyPlus::format( @@ -1823,152 +2086,7 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err // Report variables should be added for individual VENTILATION objects, in addition to zone totals below - if (thisVentilation.ZonePtr > 0) { - if (RepVarSet(thisVentilation.ZonePtr) && !thisZone.zoneOAQuadratureSum) { - RepVarSet(thisVentilation.ZonePtr) = false; - SetupOutputVariable(state, - "Zone Ventilation Sensible Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilHeatLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Sensible Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilHeatGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Latent Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilLatentLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Latent Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilLatentGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Total Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilTotalLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Total Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilTotalGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Current Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilVdotCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Standard Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilVdotStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Outdoor Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilVdotOutDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Current Density Volume", - Constant::Units::m3, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilVolumeCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Standard Density Volume", - Constant::Units::m3, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilVolumeStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Mass", - Constant::Units::kg, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilMass, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Mass Flow Rate", - Constant::Units::kg_s, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilMdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Current Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilAirChangeRateCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Standard Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilAirChangeRateStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Outdoor Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilAirChangeRateOutDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Fan Electricity Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilFanElec, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Building, - OutputProcessor::EndUseCat::Fans, - "Ventilation (simple)", - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Air Inlet Temperature", - Constant::Units::C, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilAirTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - } - } - - if (state.dataGlobal->AnyEnergyManagementSystemInModel) { - SetupEMSActuator(state, - "Zone Ventilation", - thisVentilation.Name, - "Air Exchange Flow Rate", - "[m3/s]", - thisVentilation.EMSSimpleVentOn, - thisVentilation.EMSimpleVentFlowRate); - } + finalizeVentilationObject(thisVentilation, thisZone); } } } @@ -1977,18 +2095,7 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err cCurrentModuleObject = "ZoneVentilation:WindandStackOpenArea"; for (int ventInputNum = 1; ventInputNum <= numWindStackVentilationObjects; ++ventInputNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - cCurrentModuleObject, - ventInputNum, - cAlphaArgs, - NumAlpha, - rNumericArgs, - NumNumber, - IOStat, - lNumericFieldBlanks, - lAlphaFieldBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(ventInputNum); ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)}; @@ -2264,153 +2371,7 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err } // Report variables should be added for individual VENTILATION objects, in addition to zone totals below - - if (thisVentilation.ZonePtr > 0) { - if (RepVarSet(thisVentilation.ZonePtr) && !thisZone.zoneOAQuadratureSum) { - RepVarSet(thisVentilation.ZonePtr) = false; - SetupOutputVariable(state, - "Zone Ventilation Sensible Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilHeatLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Sensible Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilHeatGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Latent Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilLatentLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Latent Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilLatentGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Total Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilTotalLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Total Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilTotalGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Current Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilVdotCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Standard Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilVdotStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Outdoor Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilVdotOutDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Current Density Volume", - Constant::Units::m3, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilVolumeCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Standard Density Volume", - Constant::Units::m3, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilVolumeStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Mass", - Constant::Units::kg, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilMass, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Mass Flow Rate", - Constant::Units::kg_s, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilMdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Current Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilAirChangeRateCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Standard Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilAirChangeRateStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Outdoor Density Air Change Rate", - Constant::Units::ach, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilAirChangeRateOutDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Fan Electricity Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilFanElec, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - thisZone.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Building, - OutputProcessor::EndUseCat::Fans, - "Ventilation (simple)", - thisZone.Name); - SetupOutputVariable(state, - "Zone Ventilation Air Inlet Temperature", - Constant::Units::C, - state.dataHeatBal->ZnAirRpt(thisVentilation.ZonePtr).VentilAirTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - thisZone.Name); - } - } - - if (state.dataGlobal->AnyEnergyManagementSystemInModel) { - SetupEMSActuator(state, - "Zone Ventilation", - thisVentilation.Name, - "Air Exchange Flow Rate", - "[m3/s]", - thisVentilation.EMSSimpleVentOn, - thisVentilation.EMSimpleVentFlowRate); - } + finalizeVentilationObject(thisVentilation, thisZone); } } } @@ -2419,6 +2380,40 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err RepVarSet = true; + // Helper lambda: handle FlowPerZone fallback when computeAirflowDesignLevel returns false. + // Applies a space-volume fraction to rNumericArgs(1) when the object spans multiple spaces. + // typeName is used in the warning/error messages (e.g. "Mixing" or "Cross Mixing"). + auto applyMixingFlowPerZone = [&](Real64 &designLevel, + const InternalHeatGains::GlobalInternalGainMiscObject &inputObj, + const DataHeatBalance::SpaceData &thisSpace, + const DataHeatBalance::ZoneData &thisZone, + std::string_view typeName) { + if (lNumericFieldBlanks(1)) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 {} will result.", + RoutineName, + cCurrentModuleObject, + inputObj.Name, + cAlphaFieldNames(4), + cNumericFieldNames(1), + typeName)); + } else { + Real64 spaceFrac = 1.0; + if (!inputObj.spaceListActive && (inputObj.numOfSpaces > 1)) { + Real64 const zoneVolume = thisZone.Volume; + if (zoneVolume > 0.0) { + spaceFrac = thisSpace.Volume / zoneVolume; + } else { + ShowSevereError(state, EnergyPlus::format("{}Zone volume is zero when allocating {} to Spaces.", RoutineName, typeName)); + ShowContinueError(state, + EnergyPlus::format("Occurs for {}=\"{}\" in Zone=\"{}\".", cCurrentModuleObject, inputObj.Name, thisZone.Name)); + ErrorsFound = true; + } + } + designLevel = rNumericArgs(1) * spaceFrac; + } + }; + cCurrentModuleObject = "ZoneMixing"; int numZoneMixingInputObjects = 0; EPVector zoneMixingInputObjects; @@ -2436,18 +2431,7 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err int mixingNum = 0; for (int mixingInputNum = 1; mixingInputNum <= numZoneMixingInputObjects; ++mixingInputNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - cCurrentModuleObject, - mixingInputNum, - cAlphaArgs, - NumAlpha, - rNumericArgs, - NumNumber, - IOStat, - lNumericFieldBlanks, - lAlphaFieldBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(mixingInputNum); ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)}; // Create one Mixing instance for every space associated with this input object @@ -2459,162 +2443,42 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err thisMixing.spaceIndex = thisMixingInput.spaceNums(Item1); auto const &thisSpace = state.dataHeatBal->space(thisMixing.spaceIndex); thisMixing.ZonePtr = thisSpace.zoneNum; - auto &thisZone = state.dataHeatBal->Zone(thisSpace.zoneNum); - - if (lAlphaFieldBlanks(3)) { - thisMixing.sched = Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but defaults to constant-1.0 - } else if ((thisMixing.sched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); - ErrorsFound = true; - } - - // Mixing equipment design level calculation method - AirflowSpec flow = static_cast(getEnumValue(airflowSpecNamesUC, cAlphaArgs(4))); - switch (flow) { - case AirflowSpec::FlowPerZone: - thisMixing.DesignLevel = rNumericArgs(1); - if (lNumericFieldBlanks(1)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(1))); - } else { - Real64 spaceFrac = 1.0; - if (!thisMixingInput.spaceListActive && (thisMixingInput.numOfSpaces > 1)) { - Real64 const zoneVolume = thisZone.Volume; - if (zoneVolume > 0.0) { - spaceFrac = thisSpace.Volume / zoneVolume; - } else { - ShowSevereError(state, EnergyPlus::format("{}Zone volume is zero when allocating Mixing to Spaces.", RoutineName)); - ShowContinueError( - state, - EnergyPlus::format( - "Occurs for {}=\"{}\" in Zone=\"{}\".", cCurrentModuleObject, thisMixingInput.Name, thisZone.Name)); - ErrorsFound = true; - } - } - - thisMixing.DesignLevel = rNumericArgs(1) * spaceFrac; - } - break; - - case AirflowSpec::FlowPerArea: - if (thisMixing.spaceIndex != 0) { - if (rNumericArgs(2) >= 0.0) { - thisMixing.DesignLevel = rNumericArgs(2) * thisSpace.FloorArea; - if (thisMixing.spaceIndex > 0) { - if (thisZone.FloorArea <= 0.0) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Space Floor Area = 0. 0 Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(2))); - } - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid flow/area specification [<0.0]={:.3R}", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - rNumericArgs(2))); - ErrorsFound = true; - } - } - if (lNumericFieldBlanks(2)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(2))); - } - break; - - case AirflowSpec::FlowPerPerson: - if (thisMixing.spaceIndex != 0) { - if (rNumericArgs(3) >= 0.0) { - thisMixing.DesignLevel = rNumericArgs(3) * thisSpace.TotOccupants; - if (thisSpace.TotOccupants <= 0.0) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Space Total Occupants = 0. 0 Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(3))); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid flow/person specification [<0.0]={:.3R}", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - rNumericArgs(3))); - ErrorsFound = true; - } - } - if (lNumericFieldBlanks(3)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(3))); - } - break; - - case AirflowSpec::AirChanges: - if (thisMixing.spaceIndex != 0) { - if (rNumericArgs(4) >= 0.0) { - thisMixing.DesignLevel = rNumericArgs(4) * thisSpace.Volume / Constant::rSecsInHour; - if (thisSpace.Volume <= 0.0) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Space Volume = 0. 0 Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(4))); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid ACH (air changes per hour) specification [<0.0]={:.3R}", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - rNumericArgs(4))); - ErrorsFound = true; - } - } - if (lNumericFieldBlanks(4)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(4))); - } - break; + auto &thisZone = state.dataHeatBal->Zone(thisSpace.zoneNum); - default: - ShowSevereError( - state, - EnergyPlus::format( - "{}{}=\"{}\", invalid calculation method={}", RoutineName, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(4))); + if (lAlphaFieldBlanks(3)) { + thisMixing.sched = Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but defaults to constant-1.0 + } else if ((thisMixing.sched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) { + ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3)); ErrorsFound = true; } + // Mixing equipment design level calculation method + AirflowSpec flow = static_cast(getEnumValue(airflowSpecNamesUC, cAlphaArgs(4))); + if (!computeAirflowDesignLevel(state, + flow, + thisMixing.DesignLevel, + thisMixing.spaceIndex, + thisSpace, + rNumericArgs, + lNumericFieldBlanks, + cAlphaFieldNames, + cNumericFieldNames, + RoutineName, + cCurrentModuleObject, + thisMixingInput.Name, + "Mixing", + ErrorsFound)) { + if (flow == AirflowSpec::FlowPerZone) { + applyMixingFlowPerZone(thisMixing.DesignLevel, thisMixingInput, thisSpace, thisZone, "Mixing"); + } else { + ShowSevereError( + state, + EnergyPlus::format( + "{}{}=\"{}\", invalid calculation method={}", RoutineName, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(4))); + ErrorsFound = true; + } + } + thisMixing.fromSpaceIndex = Util::FindItemInList(cAlphaArgs(5), state.dataHeatBal->space); if (thisMixing.fromSpaceIndex == 0) { thisMixing.FromZone = Util::FindItemInList(cAlphaArgs(5), state.dataHeatBal->Zone); @@ -2654,164 +2518,18 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err } } - // Min indoor temp - if (NumAlpha > 6) { - if (lAlphaFieldBlanks(7)) { - // Is this an error or is there a default? - } else if ((thisMixing.minIndoorTempSched = Sched::GetSchedule(state, cAlphaArgs(7))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(7), cAlphaArgs(7)); - ErrorsFound = true; - } else if (!thisMixing.minIndoorTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(7), cAlphaArgs(7), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } - - // Max indoor temp - if (NumAlpha > 7) { - if (lAlphaFieldBlanks(8)) { - } else if ((thisMixing.maxIndoorTempSched = Sched::GetSchedule(state, cAlphaArgs(8))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(8), cAlphaArgs(8)); - ErrorsFound = true; - } else if (!thisMixing.maxIndoorTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(8), cAlphaArgs(8), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } - - // Min source temp - if (NumAlpha > 8) { - if (lAlphaFieldBlanks(9)) { - } else if ((thisMixing.minSourceTempSched = Sched::GetSchedule(state, cAlphaArgs(9))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(9), cAlphaArgs(9)); - ErrorsFound = true; - } else if (!thisMixing.minSourceTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(9), cAlphaArgs(9), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } - - // Max source temp - if (NumAlpha > 9) { - if (lAlphaFieldBlanks(10)) { - } else if ((thisMixing.maxSourceTempSched = Sched::GetSchedule(state, cAlphaArgs(10))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(10), cAlphaArgs(10)); - ErrorsFound = true; - } else if (!thisMixing.maxSourceTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(10), cAlphaArgs(10), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } - - if (NumAlpha > 10) { - if (lAlphaFieldBlanks(11)) { - } else if ((thisMixing.minOutdoorTempSched = Sched::GetSchedule(state, cAlphaArgs(11))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(11), cAlphaArgs(11)); - ErrorsFound = true; - } else if (!thisMixing.minOutdoorTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(11), cAlphaArgs(11), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } - - // - if (NumAlpha > 11) { - if (lAlphaFieldBlanks(12)) { - } else if ((thisMixing.maxOutdoorTempSched = Sched::GetSchedule(state, cAlphaArgs(12))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(12), cAlphaArgs(12)); - ErrorsFound = true; - } else if (!thisMixing.maxOutdoorTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(12), cAlphaArgs(12), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } + getOptionalTempLimitSched(eoh, 6, 7, thisMixing.minIndoorTempSched); + getOptionalTempLimitSched(eoh, 7, 8, thisMixing.maxIndoorTempSched); + getOptionalTempLimitSched(eoh, 8, 9, thisMixing.minSourceTempSched); + getOptionalTempLimitSched(eoh, 9, 10, thisMixing.maxSourceTempSched); + getOptionalTempLimitSched(eoh, 10, 11, thisMixing.minOutdoorTempSched); + getOptionalTempLimitSched(eoh, 11, 12, thisMixing.maxOutdoorTempSched); if (thisMixing.ZonePtr > 0) { if (RepVarSet(thisMixing.ZonePtr)) { RepVarSet(thisMixing.ZonePtr) = false; - SetupOutputVariable(state, - "Zone Mixing Volume", - Constant::Units::m3, - state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr).MixVolume, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); - SetupOutputVariable(state, - "Zone Mixing Current Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr).MixVdotCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); - SetupOutputVariable(state, - "Zone Mixing Standard Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr).MixVdotStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); - SetupOutputVariable(state, - "Zone Mixing Mass", - Constant::Units::kg, - state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr).MixMass, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); - SetupOutputVariable(state, - "Zone Mixing Mass Flow Rate", - Constant::Units::kg_s, - state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr).MixMdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); - SetupOutputVariable(state, - "Zone Mixing Sensible Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr).MixHeatLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); - SetupOutputVariable(state, - "Zone Mixing Sensible Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr).MixHeatGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); - SetupOutputVariable(state, - "Zone Mixing Latent Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr).MixLatentLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); - SetupOutputVariable(state, - "Zone Mixing Latent Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr).MixLatentGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); - SetupOutputVariable(state, - "Zone Mixing Total Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr).MixTotalLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); - SetupOutputVariable(state, - "Zone Mixing Total Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr).MixTotalGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); + setupZoneMixingOutputVars( + state, state.dataHeatBal->ZnAirRpt(thisMixing.ZonePtr), state.dataHeatBal->Zone(thisMixing.ZonePtr).Name); } } if (state.dataGlobal->AnyEnergyManagementSystemInModel) { @@ -2941,18 +2659,7 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err int mixingNum = 0; for (int mixingInputNum = 1; mixingInputNum <= numZoneCrossMixingInputObjects; ++mixingInputNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - cCurrentModuleObject, - mixingInputNum, - cAlphaArgs, - NumAlpha, - rNumericArgs, - NumNumber, - IOStat, - lNumericFieldBlanks, - lAlphaFieldBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(mixingInputNum); ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)}; @@ -2974,153 +2681,31 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err ErrorsFound = true; } - // Mixing equipment design level calculation method. + // Cross Mixing equipment design level calculation method. AirflowSpec flow = static_cast(getEnumValue(airflowSpecNamesUC, cAlphaArgs(4))); // NOLINT(modernize-use-auto) - switch (flow) { - case AirflowSpec::FlowPerZone: - thisMixing.DesignLevel = rNumericArgs(1); - if (lNumericFieldBlanks(1)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Cross Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(1))); + if (!computeAirflowDesignLevel(state, + flow, + thisMixing.DesignLevel, + thisMixing.spaceIndex, + thisSpace, + rNumericArgs, + lNumericFieldBlanks, + cAlphaFieldNames, + cNumericFieldNames, + RoutineName, + cCurrentModuleObject, + thisMixingInput.Name, + "Cross Mixing", + ErrorsFound)) { + if (flow == AirflowSpec::FlowPerZone) { + applyMixingFlowPerZone(thisMixing.DesignLevel, thisMixingInput, thisSpace, thisZone, "Cross Mixing"); } else { - Real64 spaceFrac = 1.0; - if (!thisMixingInput.spaceListActive && (thisMixingInput.numOfSpaces > 1)) { - Real64 const zoneVolume = thisZone.Volume; - if (zoneVolume > 0.0) { - spaceFrac = thisSpace.Volume / zoneVolume; - } else { - ShowSevereError(state, - EnergyPlus::format("{}Zone volume is zero when allocating Cross Mixing to Spaces.", RoutineName)); - ShowContinueError( - state, - EnergyPlus::format( - "Occurs for {}=\"{}\" in Zone=\"{}\".", cCurrentModuleObject, thisMixingInput.Name, thisZone.Name)); - ErrorsFound = true; - } - } - - thisMixing.DesignLevel = rNumericArgs(1) * spaceFrac; - } - break; - - case AirflowSpec::FlowPerArea: - if (thisMixing.spaceIndex != 0) { - if (rNumericArgs(2) >= 0.0) { - thisMixing.DesignLevel = rNumericArgs(2) * thisSpace.FloorArea; - if (thisMixing.spaceIndex > 0) { - if (thisZone.FloorArea <= 0.0) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Space Floor Area = 0. 0 Cross Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(2))); - } - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid flow/area specification [<0.0]={:.3R}", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - rNumericArgs(2))); - ErrorsFound = true; - } - } - if (lNumericFieldBlanks(2)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Cross Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(2))); - } - break; - - case AirflowSpec::FlowPerPerson: - if (thisMixing.spaceIndex != 0) { - if (rNumericArgs(3) >= 0.0) { - thisMixing.DesignLevel = rNumericArgs(3) * thisSpace.TotOccupants; - if (thisSpace.TotOccupants <= 0.0) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Space Total Occupants = 0. 0 Cross Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(3))); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid flow/person specification [<0.0]={:.3R}", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - rNumericArgs(3))); - ErrorsFound = true; - } - } - if (lNumericFieldBlanks(3)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Cross Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(3))); - } - break; - - case AirflowSpec::AirChanges: - if (thisMixing.spaceIndex != 0) { - if (rNumericArgs(4) >= 0.0) { - thisMixing.DesignLevel = rNumericArgs(4) * thisSpace.Volume / Constant::rSecsInHour; - if (thisSpace.Volume <= 0.0) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but Space Volume = 0. 0 Cross Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(4))); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid ACH (air changes per hour) specification [<0.0]={:.3R}", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - rNumericArgs(4))); - ErrorsFound = true; - } - } - if (lNumericFieldBlanks(4)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} specifies {}, but that field is blank. 0 Cross Mixing will result.", - RoutineName, - cCurrentModuleObject, - thisMixingInput.Name, - cAlphaFieldNames(4), - cNumericFieldNames(4))); + ShowSevereError( + state, + EnergyPlus::format( + "{}{}=\"{}\", invalid calculation method={}", RoutineName, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(4))); + ErrorsFound = true; } - break; - - default: - ShowSevereError( - state, - EnergyPlus::format( - "{}{}=\"{}\", invalid calculation method={}", RoutineName, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(4))); - ErrorsFound = true; } thisMixing.fromSpaceIndex = Util::FindItemInList(cAlphaArgs(5), state.dataHeatBal->space); @@ -3169,82 +2754,12 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err } } - // Min indoor temp - if (NumAlpha > 6) { - if (lAlphaFieldBlanks(7)) { - } else if ((thisMixing.minIndoorTempSched = Sched::GetSchedule(state, cAlphaArgs(7))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(7), cAlphaArgs(7)); - ErrorsFound = true; - } else if (!thisMixing.minIndoorTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(7), cAlphaArgs(7), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } - - // Max indoor temp - if (NumAlpha > 7) { - if (lAlphaFieldBlanks(8)) { - } else if ((thisMixing.maxIndoorTempSched = Sched::GetSchedule(state, cAlphaArgs(8))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(8), cAlphaArgs(8)); - ErrorsFound = true; - } else if (!thisMixing.maxIndoorTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(8), cAlphaArgs(8), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } - - // Min source temp - if (NumAlpha > 8) { - if (lAlphaFieldBlanks(9)) { - } else if ((thisMixing.minSourceTempSched = Sched::GetSchedule(state, cAlphaArgs(9))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(9), cAlphaArgs(9)); - ErrorsFound = true; - } else if (!thisMixing.minSourceTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(9), cAlphaArgs(9), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } - - // Max source temp - if (NumAlpha > 9) { - if (lAlphaFieldBlanks(10)) { - } else if ((thisMixing.maxSourceTempSched = Sched::GetSchedule(state, cAlphaArgs(10))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(10), cAlphaArgs(10)); - ErrorsFound = true; - } else if (!thisMixing.maxSourceTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(10), cAlphaArgs(10), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } - - // Min outdoor temp - if (NumAlpha > 10) { - if (lAlphaFieldBlanks(11)) { - } else if ((thisMixing.minOutdoorTempSched = Sched::GetSchedule(state, cAlphaArgs(11))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(11), cAlphaArgs(11)); - ErrorsFound = true; - } else if (!thisMixing.minOutdoorTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(11), cAlphaArgs(11), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } - - if (NumAlpha > 11) { - if (lAlphaFieldBlanks(12)) { - } else if ((thisMixing.maxOutdoorTempSched = Sched::GetSchedule(state, cAlphaArgs(12))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(12), cAlphaArgs(12)); - ErrorsFound = true; - } else if (!thisMixing.maxOutdoorTempSched->checkMinMaxVals(state, Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit)) { - Sched::ShowSevereBadMinMax( - state, eoh, cAlphaFieldNames(12), cAlphaArgs(12), Clusive::In, -MixingTempLimit, Clusive::In, MixingTempLimit); - ErrorsFound = true; - } - } + getOptionalTempLimitSched(eoh, 6, 7, thisMixing.minIndoorTempSched); + getOptionalTempLimitSched(eoh, 7, 8, thisMixing.maxIndoorTempSched); + getOptionalTempLimitSched(eoh, 8, 9, thisMixing.minSourceTempSched); + getOptionalTempLimitSched(eoh, 9, 10, thisMixing.maxSourceTempSched); + getOptionalTempLimitSched(eoh, 10, 11, thisMixing.minOutdoorTempSched); + getOptionalTempLimitSched(eoh, 11, 12, thisMixing.maxOutdoorTempSched); } } // for (mixingInputNum) @@ -3269,172 +2784,16 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err for (int mixingRepNum = 1; mixingRepNum <= state.dataHeatBal->TotCrossMixing; ++mixingRepNum) { int zoneNum = state.dataHeatBal->CrossMixing(mixingRepNum).ZonePtr; if (zoneNum > 0) { - std::string const &zoneName = state.dataHeatBal->Zone(zoneNum).Name; - auto &thisZnAirRpt = state.dataHeatBal->ZnAirRpt(zoneNum); if (RepVarSet(zoneNum)) { RepVarSet(zoneNum) = false; - SetupOutputVariable(state, - "Zone Mixing Volume", - Constant::Units::m3, - thisZnAirRpt.MixVolume, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - zoneName); - SetupOutputVariable(state, - "Zone Mixing Current Density Volume Flow Rate", - Constant::Units::m3_s, - thisZnAirRpt.MixVdotCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - zoneName); - SetupOutputVariable(state, - "Zone Mixing Standard Density Volume Flow Rate", - Constant::Units::m3_s, - thisZnAirRpt.MixVdotStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - zoneName); - SetupOutputVariable(state, - "Zone Mixing Mass", - Constant::Units::kg, - thisZnAirRpt.MixMass, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - zoneName); - SetupOutputVariable(state, - "Zone Mixing Mass Flow Rate", - Constant::Units::kg_s, - thisZnAirRpt.MixMdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - zoneName); - SetupOutputVariable(state, - "Zone Mixing Sensible Heat Loss Energy", - Constant::Units::J, - thisZnAirRpt.MixHeatLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - zoneName); - SetupOutputVariable(state, - "Zone Mixing Sensible Heat Gain Energy", - Constant::Units::J, - thisZnAirRpt.MixHeatGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - zoneName); - SetupOutputVariable(state, - "Zone Mixing Latent Heat Loss Energy", - Constant::Units::J, - thisZnAirRpt.MixLatentLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - zoneName); - SetupOutputVariable(state, - "Zone Mixing Latent Heat Gain Energy", - Constant::Units::J, - thisZnAirRpt.MixLatentGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - zoneName); - SetupOutputVariable(state, - "Zone Mixing Total Heat Loss Energy", - Constant::Units::J, - thisZnAirRpt.MixTotalLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - zoneName); - SetupOutputVariable(state, - "Zone Mixing Total Heat Gain Energy", - Constant::Units::J, - thisZnAirRpt.MixTotalGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - zoneName); + setupZoneMixingOutputVars(state, state.dataHeatBal->ZnAirRpt(zoneNum), state.dataHeatBal->Zone(zoneNum).Name); } } int fromZoneNum = state.dataHeatBal->CrossMixing(mixingRepNum).FromZone; if (fromZoneNum > 0) { if (RepVarSet(fromZoneNum)) { RepVarSet(fromZoneNum) = false; - std::string const &fromZoneName = state.dataHeatBal->Zone(fromZoneNum).Name; - auto &thisZnAirRpt = state.dataHeatBal->ZnAirRpt(fromZoneNum); - SetupOutputVariable(state, - "Zone Mixing Volume", - Constant::Units::m3, - thisZnAirRpt.MixVolume, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - fromZoneName); - SetupOutputVariable(state, - "Zone Mixing Current Density Volume Flow Rate", - Constant::Units::m3_s, - thisZnAirRpt.MixVdotCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - fromZoneName); - SetupOutputVariable(state, - "Zone Mixing Standard Density Volume Flow Rate", - Constant::Units::m3_s, - thisZnAirRpt.MixVdotStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - fromZoneName); - SetupOutputVariable(state, - "Zone Mixing Mass", - Constant::Units::kg, - thisZnAirRpt.MixMass, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - fromZoneName); - SetupOutputVariable(state, - "Zone Mixing Mass Flow Rate", - Constant::Units::kg_s, - thisZnAirRpt.MixMdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - fromZoneName); - SetupOutputVariable(state, - "Zone Mixing Sensible Heat Loss Energy", - Constant::Units::J, - thisZnAirRpt.MixHeatLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - fromZoneName); - SetupOutputVariable(state, - "Zone Mixing Sensible Heat Gain Energy", - Constant::Units::J, - thisZnAirRpt.MixHeatGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - fromZoneName); - SetupOutputVariable(state, - "Zone Mixing Latent Heat Loss Energy", - Constant::Units::J, - thisZnAirRpt.MixLatentLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - fromZoneName); - SetupOutputVariable(state, - "Zone Mixing Latent Heat Gain Energy", - Constant::Units::J, - thisZnAirRpt.MixLatentGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - fromZoneName); - SetupOutputVariable(state, - "Zone Mixing Total Heat Loss Energy", - Constant::Units::J, - thisZnAirRpt.MixTotalLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - fromZoneName); - SetupOutputVariable(state, - "Zone Mixing Total Heat Gain Energy", - Constant::Units::J, - thisZnAirRpt.MixTotalGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - fromZoneName); + setupZoneMixingOutputVars(state, state.dataHeatBal->ZnAirRpt(fromZoneNum), state.dataHeatBal->Zone(fromZoneNum).Name); } } @@ -3460,53 +2819,39 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err for (int Loop = 1; Loop <= state.dataHeatBal->TotRefDoorMixing; ++Loop) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - cCurrentModuleObject, - Loop, - cAlphaArgs, - NumAlpha, - rNumericArgs, - NumNumber, - IOStat, - lNumericFieldBlanks, - lAlphaFieldBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(Loop); ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)}; NameThisObject = cAlphaArgs(1); + // Helper lambda: look up a zone-or-space name from alpha field alphaIdx, resolve to a zone number, + // and report an error if neither a zone nor a space is found. + auto lookupRefDoorZone = [&](int alphaIdx, int &zoneNum, int &spaceNum) { + zoneNum = Util::FindItemInList(cAlphaArgs(alphaIdx), state.dataHeatBal->Zone); + spaceNum = Util::FindItemInList(cAlphaArgs(alphaIdx), state.dataHeatBal->space); + if ((zoneNum == 0) && (spaceNum == 0)) { + ShowSevereError(state, + EnergyPlus::format("{}{}=\"{}\", invalid (not found) {}=\"{}\".", + RoutineName, + cCurrentModuleObject, + cAlphaArgs(1), + cAlphaFieldNames(alphaIdx), + cAlphaArgs(alphaIdx))); + ErrorsFound = true; + } else if (zoneNum == 0) { + zoneNum = state.dataHeatBal->space(spaceNum).zoneNum; + } + }; + int AlphaNum = 2; - int Zone1Num = Util::FindItemInList(cAlphaArgs(AlphaNum), state.dataHeatBal->Zone); - int space1Num = Util::FindItemInList(cAlphaArgs(AlphaNum), state.dataHeatBal->space); - if ((Zone1Num == 0) && (space1Num == 0)) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid (not found) {}=\"{}\".", - RoutineName, - cCurrentModuleObject, - cAlphaArgs(1), - cAlphaFieldNames(AlphaNum), - cAlphaArgs(AlphaNum))); - ErrorsFound = true; - } else if (Zone1Num == 0) { - Zone1Num = state.dataHeatBal->space(space1Num).zoneNum; - } + int Zone1Num = 0; + int space1Num = 0; + lookupRefDoorZone(AlphaNum, Zone1Num, space1Num); ++AlphaNum; // 3 - int Zone2Num = Util::FindItemInList(cAlphaArgs(AlphaNum), state.dataHeatBal->Zone); - int space2Num = Util::FindItemInList(cAlphaArgs(AlphaNum), state.dataHeatBal->space); - if ((Zone2Num == 0) && (space2Num == 0)) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid (not found) {}=\"{}\".", - RoutineName, - cCurrentModuleObject, - cAlphaArgs(1), - cAlphaFieldNames(AlphaNum), - cAlphaArgs(AlphaNum))); - ErrorsFound = true; - } else if (Zone2Num == 0) { - Zone2Num = state.dataHeatBal->space(space2Num).zoneNum; - } + int Zone2Num = 0; + int space2Num = 0; + lookupRefDoorZone(AlphaNum, Zone2Num, space2Num); int spaceNumA = 0; int spaceNumB = 0; @@ -3535,51 +2880,34 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err auto &zoneA = state.dataHeatBal->RefDoorMixing(ZoneNumA); auto &zoneB = state.dataHeatBal->RefDoorMixing(ZoneNumB); - if (!allocated(zoneA.openScheds)) { - zoneA.DoorMixingObjectName.allocate(state.dataGlobal->NumOfZones); - zoneA.openScheds.allocate(state.dataGlobal->NumOfZones); - zoneA.DoorHeight.allocate(state.dataGlobal->NumOfZones); - zoneA.DoorArea.allocate(state.dataGlobal->NumOfZones); - zoneA.Protection.allocate(state.dataGlobal->NumOfZones); - zoneA.MateZonePtr.allocate(state.dataGlobal->NumOfZones); - zoneA.EMSRefDoorMixingOn.allocate(state.dataGlobal->NumOfZones); - zoneA.EMSRefDoorFlowRate.allocate(state.dataGlobal->NumOfZones); - zoneA.VolRefDoorFlowRate.allocate(state.dataGlobal->NumOfZones); - zoneA.DoorProtTypeName.allocate(state.dataGlobal->NumOfZones); - zoneA.DoorMixingObjectName = ""; - zoneA.openScheds = nullptr; - zoneA.DoorHeight = 0.0; - zoneA.DoorArea = 0.0; - zoneA.Protection = RefDoorNone; - zoneA.MateZonePtr = 0; - zoneA.EMSRefDoorMixingOn = false; - zoneA.EMSRefDoorFlowRate = 0.0; - zoneA.VolRefDoorFlowRate = 0.0; - zoneA.DoorProtTypeName = ""; - } // First refrigeration mixing in this zone - - if (!allocated(zoneB.openScheds)) { - zoneB.DoorMixingObjectName.allocate(state.dataGlobal->NumOfZones); - zoneB.openScheds.allocate(state.dataGlobal->NumOfZones); - zoneB.DoorHeight.allocate(state.dataGlobal->NumOfZones); - zoneB.DoorArea.allocate(state.dataGlobal->NumOfZones); - zoneB.Protection.allocate(state.dataGlobal->NumOfZones); - zoneB.MateZonePtr.allocate(state.dataGlobal->NumOfZones); - zoneB.EMSRefDoorMixingOn.allocate(state.dataGlobal->NumOfZones); - zoneB.EMSRefDoorFlowRate.allocate(state.dataGlobal->NumOfZones); - zoneB.VolRefDoorFlowRate.allocate(state.dataGlobal->NumOfZones); - zoneB.DoorProtTypeName.allocate(state.dataGlobal->NumOfZones); - zoneB.DoorMixingObjectName = ""; - zoneB.openScheds = nullptr; - zoneB.DoorHeight = 0.0; - zoneB.DoorArea = 0.0; - zoneB.Protection = RefDoorNone; - zoneB.MateZonePtr = 0; - zoneB.EMSRefDoorMixingOn = false; - zoneB.EMSRefDoorFlowRate = 0.0; - zoneB.VolRefDoorFlowRate = 0.0; - zoneB.DoorProtTypeName = ""; - } // First refrigeration mixing in this zone + // Initialize all per-zone arrays on first use (identical logic for both sides of a door). + auto initRefDoorZone = [&](DataHeatBalance::MixingData &zone) { + if (allocated(zone.openScheds)) { + return; + } + zone.DoorMixingObjectName.allocate(state.dataGlobal->NumOfZones); + zone.openScheds.allocate(state.dataGlobal->NumOfZones); + zone.DoorHeight.allocate(state.dataGlobal->NumOfZones); + zone.DoorArea.allocate(state.dataGlobal->NumOfZones); + zone.Protection.allocate(state.dataGlobal->NumOfZones); + zone.MateZonePtr.allocate(state.dataGlobal->NumOfZones); + zone.EMSRefDoorMixingOn.allocate(state.dataGlobal->NumOfZones); + zone.EMSRefDoorFlowRate.allocate(state.dataGlobal->NumOfZones); + zone.VolRefDoorFlowRate.allocate(state.dataGlobal->NumOfZones); + zone.DoorProtTypeName.allocate(state.dataGlobal->NumOfZones); + zone.DoorMixingObjectName = ""; + zone.openScheds = nullptr; + zone.DoorHeight = 0.0; + zone.DoorArea = 0.0; + zone.Protection = RefDoorNone; + zone.MateZonePtr = 0; + zone.EMSRefDoorMixingOn = false; + zone.EMSRefDoorFlowRate = 0.0; + zone.VolRefDoorFlowRate = 0.0; + zone.DoorProtTypeName = ""; + }; + initRefDoorZone(zoneA); // First refrigeration mixing in this zone + initRefDoorZone(zoneB); // First refrigeration mixing in this zone ConnectionNumber = zoneA.NumRefDoorConnections + 1; zoneA.NumRefDoorConnections = ConnectionNumber; @@ -3701,83 +3029,7 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err if (ZoneNumA > 0) { if (RepVarSet(ZoneNumA)) { RepVarSet(ZoneNumA) = false; - SetupOutputVariable(state, - "Zone Mixing Volume", - Constant::Units::m3, - state.dataHeatBal->ZnAirRpt(ZoneNumA).MixVolume, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumA).Name); - SetupOutputVariable(state, - "Zone Mixing Current Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(ZoneNumA).MixVdotCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(ZoneNumA).Name); - SetupOutputVariable(state, - "Zone Mixing Standard Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(ZoneNumA).MixVdotStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(ZoneNumA).Name); - SetupOutputVariable(state, - "Zone Mixing Mass", - Constant::Units::kg, - state.dataHeatBal->ZnAirRpt(ZoneNumA).MixMass, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumA).Name); - SetupOutputVariable(state, - "Zone Mixing Mass Flow Rate", - Constant::Units::kg_s, - state.dataHeatBal->ZnAirRpt(ZoneNumA).MixMdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(ZoneNumA).Name); - SetupOutputVariable(state, - "Zone Mixing Sensible Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumA).MixHeatLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumA).Name); - SetupOutputVariable(state, - "Zone Mixing Sensible Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumA).MixHeatGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumA).Name); - SetupOutputVariable(state, - "Zone Mixing Latent Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumA).MixLatentLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumA).Name); - SetupOutputVariable(state, - "Zone Mixing Latent Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumA).MixLatentGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumA).Name); - SetupOutputVariable(state, - "Zone Mixing Total Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumA).MixTotalLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumA).Name); - SetupOutputVariable(state, - "Zone Mixing Total Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumA).MixTotalGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumA).Name); + setupZoneMixingOutputVars(state, state.dataHeatBal->ZnAirRpt(ZoneNumA), state.dataHeatBal->Zone(ZoneNumA).Name); } } if (state.dataGlobal->AnyEnergyManagementSystemInModel) { @@ -3793,83 +3045,7 @@ void GetSimpleAirModelInputs(EnergyPlusData &state, bool &ErrorsFound) // IF err if (ZoneNumB > 0) { if (RepVarSet(ZoneNumB)) { RepVarSet(ZoneNumB) = false; - SetupOutputVariable(state, - "Zone Mixing Volume", - Constant::Units::m3, - state.dataHeatBal->ZnAirRpt(ZoneNumB).MixVolume, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumB).Name); - SetupOutputVariable(state, - "Zone Mixing Current Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(ZoneNumB).MixVdotCurDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(ZoneNumB).Name); - SetupOutputVariable(state, - "Zone Mixing Standard Density Volume Flow Rate", - Constant::Units::m3_s, - state.dataHeatBal->ZnAirRpt(ZoneNumB).MixVdotStdDensity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(ZoneNumB).Name); - SetupOutputVariable(state, - "Zone Mixing Mass", - Constant::Units::kg, - state.dataHeatBal->ZnAirRpt(ZoneNumB).MixMass, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumB).Name); - SetupOutputVariable(state, - "Zone Mixing Mass Flow Rate", - Constant::Units::kg_s, - state.dataHeatBal->ZnAirRpt(ZoneNumB).MixMdot, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(ZoneNumB).Name); - SetupOutputVariable(state, - "Zone Mixing Sensible Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumB).MixHeatLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumB).Name); - SetupOutputVariable(state, - "Zone Mixing Sensible Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumB).MixHeatGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumB).Name); - SetupOutputVariable(state, - "Zone Mixing Latent Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumB).MixLatentLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumB).Name); - SetupOutputVariable(state, - "Zone Mixing Latent Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumB).MixLatentGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumB).Name); - SetupOutputVariable(state, - "Zone Mixing Total Heat Loss Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumB).MixTotalLoss, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumB).Name); - SetupOutputVariable(state, - "Zone Mixing Total Heat Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZnAirRpt(ZoneNumB).MixTotalGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(ZoneNumB).Name); + setupZoneMixingOutputVars(state, state.dataHeatBal->ZnAirRpt(ZoneNumB), state.dataHeatBal->Zone(ZoneNumB).Name); } } if (state.dataGlobal->AnyEnergyManagementSystemInModel) { diff --git a/src/EnergyPlus/HeatingCoils.cc b/src/EnergyPlus/HeatingCoils.cc index 28b644efc44..d7be3532d0f 100644 --- a/src/EnergyPlus/HeatingCoils.cc +++ b/src/EnergyPlus/HeatingCoils.cc @@ -241,6 +241,133 @@ namespace HeatingCoils { } } + // Allocate and validate heat reclaim efficiency for desuperheater heating coils. + // Returns true if the source was validated successfully. + static bool validateHeatReclaimEfficiency(EnergyPlusData &state, + DataHeatBalance::HeatReclaimDataBase &HeatReclaim, + HeatingCoilEquipConditions const &heatingCoil, + int CoilNum) + { + if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) { + HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil); + std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0); + } + HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency; + if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) { + ShowSevereError( + state, + EnergyPlus::format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3", + HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), + heatingCoil.Name, + heatingCoil.ReclaimHeatingCoilName)); + } + state.dataHeatingCoils->ValidSourceType(CoilNum) = true; + return true; + } + + // Parse air inlet/outlet nodes, validate the component set, and optionally parse + // a temperature setpoint sensor node. Shared by all heating coil types. + static void setupCoilAirNodes(EnergyPlusData &state, + HeatingCoilEquipConditions &heatingCoil, + std::string const &CurrentModuleObject, + Array1D_string const &Alphas, + Node::ConnectionObjectType connObjType, + int inletAlphaIdx, + int outletAlphaIdx, + int sensorAlphaIdx) // 0 = skip sensor node + { + bool errFlag = false; + heatingCoil.AirInletNodeNum = GetOnlySingleNode(state, + Alphas(inletAlphaIdx), + errFlag, + connObjType, + Alphas(1), + Node::FluidType::Air, + Node::ConnectionType::Inlet, + Node::CompFluidStream::Primary, + Node::ObjectIsNotParent); + state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; + errFlag = false; + heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state, + Alphas(outletAlphaIdx), + errFlag, + connObjType, + Alphas(1), + Node::FluidType::Air, + Node::ConnectionType::Outlet, + Node::CompFluidStream::Primary, + Node::ObjectIsNotParent); + state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; + + Node::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(inletAlphaIdx), Alphas(outletAlphaIdx), "Air Nodes"); + + if (sensorAlphaIdx > 0) { + errFlag = false; + heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state, + Alphas(sensorAlphaIdx), + errFlag, + connObjType, + Alphas(1), + Node::FluidType::Air, + Node::ConnectionType::Sensor, + Node::CompFluidStream::Primary, + Node::ObjectIsNotParent); + state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; + } + } + + // Setup heating energy/rate output variables (registered first for all coil types). + static void setupHeatingEnergyOutputVars(EnergyPlusData &state, HeatingCoilEquipConditions &heatingCoil) + { + SetupOutputVariable(state, + "Heating Coil Heating Energy", + Constant::Units::J, + heatingCoil.HeatingCoilLoad, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + heatingCoil.Name, + Constant::eResource::EnergyTransfer, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::HeatingCoils); + SetupOutputVariable(state, + "Heating Coil Heating Rate", + Constant::Units::W, + heatingCoil.HeatingCoilRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + heatingCoil.Name); + } + + // Setup electricity energy/rate output variables. + static void setupElectricityOutputVars(EnergyPlusData &state, HeatingCoilEquipConditions &heatingCoil) + { + SetupOutputVariable(state, + "Heating Coil Electricity Energy", + Constant::Units::J, + heatingCoil.ElecUseLoad, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + heatingCoil.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Heating); + SetupOutputVariable(state, + "Heating Coil Electricity Rate", + Constant::Units::W, + heatingCoil.ElecUseRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + heatingCoil.Name); + } + + // Setup all common output variables (heating + electricity) for coil types + // where no fuel-specific variables are interleaved between them. + static void setupCommonHeatingCoilOutputVars(EnergyPlusData &state, HeatingCoilEquipConditions &heatingCoil) + { + setupHeatingEnergyOutputVars(state, heatingCoil); + setupElectricityOutputVars(state, heatingCoil); + } + void GetHeatingCoilInput(EnergyPlusData &state) { @@ -363,79 +490,10 @@ namespace HeatingCoils { heatingCoil.Efficiency = Numbers(1); heatingCoil.NominalCapacity = Numbers(2); - errFlag = false; - heatingCoil.AirInletNodeNum = GetOnlySingleNode(state, - Alphas(3), - errFlag, - Node::ConnectionObjectType::CoilHeatingElectric, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; - errFlag = false; - heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state, - Alphas(4), - errFlag, - Node::ConnectionObjectType::CoilHeatingElectric, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; - - Node::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes"); - - errFlag = false; - heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state, - Alphas(5), - errFlag, - Node::ConnectionObjectType::CoilHeatingElectric, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; + setupCoilAirNodes(state, heatingCoil, CurrentModuleObject, Alphas, Node::ConnectionObjectType::CoilHeatingElectric, 3, 4, 5); // Setup Report variables for the Electric Coils - // CurrentModuleObject = "Coil:Heating:Electric" - SetupOutputVariable(state, - "Heating Coil Heating Energy", - Constant::Units::J, - heatingCoil.HeatingCoilLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - heatingCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::HeatingCoils); - SetupOutputVariable(state, - "Heating Coil Heating Rate", - Constant::Units::W, - heatingCoil.HeatingCoilRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - heatingCoil.Name); - SetupOutputVariable(state, - "Heating Coil Electricity Energy", - Constant::Units::J, - heatingCoil.ElecUseLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - heatingCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Electricity Rate", - Constant::Units::W, - heatingCoil.ElecUseRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - heatingCoil.Name); + setupCommonHeatingCoilOutputVars(state, heatingCoil); } // Get the data for electric heating coils @@ -491,79 +549,10 @@ namespace HeatingCoils { heatingCoil.MSNominalCapacity(StageNum) = Numbers(StageNum * 2 + 1); } - errFlag = false; - heatingCoil.AirInletNodeNum = GetOnlySingleNode(state, - Alphas(3), - errFlag, - Node::ConnectionObjectType::CoilHeatingElectricMultiStage, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; - errFlag = false; - heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state, - Alphas(4), - errFlag, - Node::ConnectionObjectType::CoilHeatingElectricMultiStage, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; - - Node::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes"); - - errFlag = false; - heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state, - Alphas(5), - errFlag, - Node::ConnectionObjectType::CoilHeatingElectricMultiStage, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; + setupCoilAirNodes(state, heatingCoil, CurrentModuleObject, Alphas, Node::ConnectionObjectType::CoilHeatingElectricMultiStage, 3, 4, 5); // Setup Report variables for the Electric Coils - // CurrentModuleObject = "Coil:Heating:Electric:MultiStage" - SetupOutputVariable(state, - "Heating Coil Heating Energy", - Constant::Units::J, - heatingCoil.HeatingCoilLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - heatingCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::HeatingCoils); - SetupOutputVariable(state, - "Heating Coil Heating Rate", - Constant::Units::W, - heatingCoil.HeatingCoilRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - heatingCoil.Name); - SetupOutputVariable(state, - "Heating Coil Electricity Energy", - Constant::Units::J, - heatingCoil.ElecUseLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - heatingCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Electricity Rate", - Constant::Units::W, - heatingCoil.ElecUseRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - heatingCoil.Name); + setupCommonHeatingCoilOutputVars(state, heatingCoil); } // Get the data for for fuel heating coils @@ -627,42 +616,7 @@ namespace HeatingCoils { heatingCoil.Efficiency = Numbers(1); heatingCoil.NominalCapacity = Numbers(2); - errFlag = false; - heatingCoil.AirInletNodeNum = GetOnlySingleNode(state, - Alphas(4), - errFlag, - Node::ConnectionObjectType::CoilHeatingFuel, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; - errFlag = false; - heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state, - Alphas(5), - errFlag, - Node::ConnectionObjectType::CoilHeatingFuel, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; - - Node::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(4), Alphas(5), "Air Nodes"); - - errFlag = false; - heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state, - Alphas(6), - errFlag, - Node::ConnectionObjectType::CoilHeatingFuel, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; + setupCoilAirNodes(state, heatingCoil, CurrentModuleObject, Alphas, Node::ConnectionObjectType::CoilHeatingFuel, 4, 5, 6); // parasitic electric load associated with the fuel heating coil heatingCoil.ParasiticElecLoad = Numbers(3); @@ -673,25 +627,9 @@ namespace HeatingCoils { heatingCoil.ParasiticFuelCapacity = Numbers(4); // Setup Report variables for the Fuel Coils - // CurrentModuleObject = "Coil:Heating:OtherFuel" - - SetupOutputVariable(state, - "Heating Coil Heating Energy", - Constant::Units::J, - heatingCoil.HeatingCoilLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - heatingCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::HeatingCoils); - SetupOutputVariable(state, - "Heating Coil Heating Rate", - Constant::Units::W, - heatingCoil.HeatingCoilRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - heatingCoil.Name); + // Register heating energy/rate first, then fuel-specific, then electricity + // to match original output variable ordering. + setupHeatingEnergyOutputVars(state, heatingCoil); SetupOutputVariable(state, EnergyPlus::format("Heating Coil {} Energy", sFuelType), Constant::Units::J, @@ -709,23 +647,7 @@ namespace HeatingCoils { OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, heatingCoil.Name); - SetupOutputVariable(state, - "Heating Coil Electricity Energy", - Constant::Units::J, - heatingCoil.ElecUseLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - heatingCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Electricity Rate", - Constant::Units::W, - heatingCoil.ElecUseRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - heatingCoil.Name); + setupElectricityOutputVars(state, heatingCoil); SetupOutputVariable(state, "Heating Coil Runtime Fraction", Constant::Units::None, @@ -811,42 +733,7 @@ namespace HeatingCoils { heatingCoil.MSParasiticElecLoad(StageNum) = Numbers(StageNum * 3 + 2); } - errFlag = false; - heatingCoil.AirInletNodeNum = GetOnlySingleNode(state, - Alphas(3), - errFlag, - Node::ConnectionObjectType::CoilHeatingGasMultiStage, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; - errFlag = false; - heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state, - Alphas(4), - errFlag, - Node::ConnectionObjectType::CoilHeatingGasMultiStage, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; - - Node::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes"); - - errFlag = false; - heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state, - Alphas(5), - errFlag, - Node::ConnectionObjectType::CoilHeatingGasMultiStage, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; + setupCoilAirNodes(state, heatingCoil, CurrentModuleObject, Alphas, Node::ConnectionObjectType::CoilHeatingGasMultiStage, 3, 4, 5); // parasitic electric load associated with the gas heating coil heatingCoil.ParasiticElecLoad = Numbers(10); @@ -856,24 +743,9 @@ namespace HeatingCoils { // parasitic gas load associated with the gas heating coil (standing pilot light) // Setup Report variables for the Gas Coils - // CurrentModuleObject = "Coil:Heating:Gas:MultiStage" - SetupOutputVariable(state, - "Heating Coil Heating Energy", - Constant::Units::J, - heatingCoil.HeatingCoilLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - heatingCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::HeatingCoils); - SetupOutputVariable(state, - "Heating Coil Heating Rate", - Constant::Units::W, - heatingCoil.HeatingCoilRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - heatingCoil.Name); + // Register heating energy/rate first, then fuel-specific, then electricity + // to match original output variable ordering. + setupHeatingEnergyOutputVars(state, heatingCoil); SetupOutputVariable(state, "Heating Coil NaturalGas Energy", Constant::Units::J, @@ -891,23 +763,7 @@ namespace HeatingCoils { OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, heatingCoil.Name); - SetupOutputVariable(state, - "Heating Coil Electricity Energy", - Constant::Units::J, - heatingCoil.ElecUseLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - heatingCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Electricity Rate", - Constant::Units::W, - heatingCoil.ElecUseRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - heatingCoil.Name); + setupElectricityOutputVars(state, heatingCoil); SetupOutputVariable(state, "Heating Coil Runtime Fraction", Constant::Units::None, @@ -983,30 +839,7 @@ namespace HeatingCoils { //(Numbers(1)) error limits checked and defaults applied on efficiency after // identifying source type. - errFlag = false; - heatingCoil.AirInletNodeNum = GetOnlySingleNode(state, - Alphas(3), - errFlag, - Node::ConnectionObjectType::CoilHeatingDesuperheater, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; - errFlag = false; - heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state, - Alphas(4), - errFlag, - Node::ConnectionObjectType::CoilHeatingDesuperheater, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound; - - Node::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes"); + setupCoilAirNodes(state, heatingCoil, CurrentModuleObject, Alphas, Node::ConnectionObjectType::CoilHeatingDesuperheater, 3, 4, 0); if ((Util::SameString(Alphas(5), "Refrigeration:Condenser:AirCooled")) || (Util::SameString(Alphas(5), "Refrigeration:Condenser:EvaporativeCooled")) || @@ -1052,26 +885,9 @@ namespace HeatingCoils { } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:SingleSpeed")) { heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_COOLING; DXCoils::GetDXCoilIndex(state, Alphas(6), heatingCoil.ReclaimHeatingSourceIndexNum, DXCoilErrFlag, Alphas(5)); - if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) { - if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) { - DataHeatBalance::HeatReclaimDataBase &HeatReclaim = - state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum); - if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) { - HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil); - std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0); - } - HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency; - if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) { - ShowSevereError( - state, - EnergyPlus::format( - "{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.3", - HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), - heatingCoil.Name, - heatingCoil.ReclaimHeatingCoilName)); - } - state.dataHeatingCoils->ValidSourceType(CoilNum) = true; - } + if (heatingCoil.ReclaimHeatingSourceIndexNum > 0 && allocated(state.dataHeatBal->HeatReclaimDXCoil)) { + validateHeatReclaimEfficiency( + state, state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum), heatingCoil, CoilNum); } if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) { state.dataHeatingCoils->ValidSourceType(CoilNum) = true; @@ -1079,74 +895,23 @@ namespace HeatingCoils { } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:VariableSpeed")) { heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_VARIABLE_COOLING; heatingCoil.ReclaimHeatingSourceIndexNum = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, Alphas(5), Alphas(6), DXCoilErrFlag); - if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) { - if (allocated(state.dataHeatBal->HeatReclaimVS_Coil)) { - DataHeatBalance::HeatReclaimDataBase &HeatReclaim = - state.dataHeatBal->HeatReclaimVS_Coil(heatingCoil.ReclaimHeatingSourceIndexNum); - if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) { - HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil); - std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0); - } - HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency; - if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) { - ShowSevereError( - state, - EnergyPlus::format( - "{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.3", - HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), - heatingCoil.Name, - heatingCoil.ReclaimHeatingCoilName)); - } - state.dataHeatingCoils->ValidSourceType(CoilNum) = true; - } + if (heatingCoil.ReclaimHeatingSourceIndexNum > 0 && allocated(state.dataHeatBal->HeatReclaimVS_Coil)) { + validateHeatReclaimEfficiency( + state, state.dataHeatBal->HeatReclaimVS_Coil(heatingCoil.ReclaimHeatingSourceIndexNum), heatingCoil, CoilNum); } } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:TwoSpeed")) { heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_MULTISPEED; DXCoils::GetDXCoilIndex(state, Alphas(6), heatingCoil.ReclaimHeatingSourceIndexNum, DXCoilErrFlag, Alphas(5)); - if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) { - if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) { - DataHeatBalance::HeatReclaimDataBase &HeatReclaim = - state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum); - if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) { - HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil); - std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0); - } - HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency; - if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) { - ShowSevereError( - state, - EnergyPlus::format( - "{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.3", - HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), - heatingCoil.Name, - heatingCoil.ReclaimHeatingCoilName)); - } - state.dataHeatingCoils->ValidSourceType(CoilNum) = true; - } + if (heatingCoil.ReclaimHeatingSourceIndexNum > 0 && allocated(state.dataHeatBal->HeatReclaimDXCoil)) { + validateHeatReclaimEfficiency( + state, state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum), heatingCoil, CoilNum); } } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:TwoStageWithHumidityControlMode")) { heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_MULTIMODE; DXCoils::GetDXCoilIndex(state, Alphas(6), heatingCoil.ReclaimHeatingSourceIndexNum, DXCoilErrFlag, Alphas(5)); - if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) { - if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) { - DataHeatBalance::HeatReclaimDataBase &HeatReclaim = - state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum); - if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) { - HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil); - std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0); - } - HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency; - if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) { - ShowSevereError( - state, - EnergyPlus::format( - R"({}, "{}" sum of heat reclaim recovery efficiencies from the same source coil: "{} " cannot be over 0.3)", - HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), - heatingCoil.Name, - heatingCoil.ReclaimHeatingCoilName)); - } - state.dataHeatingCoils->ValidSourceType(CoilNum) = true; - } + if (heatingCoil.ReclaimHeatingSourceIndexNum > 0 && allocated(state.dataHeatBal->HeatReclaimDXCoil)) { + validateHeatReclaimEfficiency( + state, state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum), heatingCoil, CoilNum); } } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX")) { heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_COOLING_DX_NEW; @@ -1158,22 +923,8 @@ namespace HeatingCoils { "{}={}, could not find desuperheater coil {}={}", CurrentModuleObject, heatingCoil.Name, Alphas(5), Alphas(6))); state.dataHeatingCoils->InputErrorsFound = true; } - DataHeatBalance::HeatReclaimDataBase &HeatReclaim = - state.dataCoilCoolingDX->coilCoolingDXs[heatingCoil.ReclaimHeatingSourceIndexNum].reclaimHeat; - if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) { - HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil); - std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0); - } - HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency; - if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) { - ShowSevereError(state, - EnergyPlus::format( - "{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3", - HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), - heatingCoil.Name, - heatingCoil.ReclaimHeatingCoilName)); - } - state.dataHeatingCoils->ValidSourceType(CoilNum) = true; + validateHeatReclaimEfficiency( + state, state.dataCoilCoolingDX->coilCoolingDXs[heatingCoil.ReclaimHeatingSourceIndexNum].reclaimHeat, heatingCoil, CoilNum); } else { ShowSevereError( state, @@ -1210,41 +961,7 @@ namespace HeatingCoils { } // Setup Report variables for the Desuperheater Heating Coils - // CurrentModuleObject = "Coil:Heating:Desuperheater" - SetupOutputVariable(state, - "Heating Coil Heating Energy", - Constant::Units::J, - heatingCoil.HeatingCoilLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - heatingCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::HeatingCoils); - SetupOutputVariable(state, - "Heating Coil Heating Rate", - Constant::Units::W, - heatingCoil.HeatingCoilRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - heatingCoil.Name); - SetupOutputVariable(state, - "Heating Coil Electricity Energy", - Constant::Units::J, - heatingCoil.ElecUseLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - heatingCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Electricity Rate", - Constant::Units::W, - heatingCoil.ElecUseRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - heatingCoil.Name); + setupCommonHeatingCoilOutputVars(state, heatingCoil); SetupOutputVariable(state, "Heating Coil Runtime Fraction", Constant::Units::None, diff --git a/src/EnergyPlus/InternalHeatGains.cc b/src/EnergyPlus/InternalHeatGains.cc index 3e21961f022..8816b6d90d5 100644 --- a/src/EnergyPlus/InternalHeatGains.cc +++ b/src/EnergyPlus/InternalHeatGains.cc @@ -192,6 +192,70 @@ namespace InternalHeatGains { static constexpr std::array(DesignLevelMethod::Num)> DesignLevelMethodNamesUC = { "PEOPLE", "PEOPLE/AREA", "AREA/PERSON", "LIGHTINGLEVEL", "EQUIPMENTLEVEL", "WATTS/AREA", "WATTS/PERSON", "POWER/AREA", "POWER/PERSON"}; + // Print 8 EIO values for 4 day-type schedule groups (weekday, weekend/holiday, summer DD, winter DD) + // as "designLevel * schedMin, designLevel * schedMax" pairs using {:.3R} format. + // If lastNewline is true, the last value ends with "\n"; otherwise with ",". + static void printEioScheduleMinMax(EnergyPlusData &state, Sched::Schedule *sched, Real64 designLevel, bool lastNewline = true) + { + static constexpr std::array dayTypes = {Sched::DayTypeGroup::Weekday, + Sched::DayTypeGroup::WeekEndHoliday, + Sched::DayTypeGroup::SummerDesignDay, + Sched::DayTypeGroup::WinterDesignDay}; + for (int i = 0; i < 4; ++i) { + auto [SchMin, SchMax] = sched->getMinMaxValsByDayType(state, dayTypes[i]); + bool isLast = (i == 3); + print(state.files.eio, "{:.3R},", designLevel * SchMin); + print(state.files.eio, (isLast && lastNewline) ? "{:.3R}\n" : "{:.3R},", designLevel * SchMax); + } + } + + // Print one EIO data row for a ZoneEquipData-derived equipment object. + // Used by ElectricEquipment, GasEquipment, HotWaterEquipment, SteamEquipment, and OtherEquipment. + static void printEquipEioRow(EnergyPlusData &state, + DataHeatBalance::ZoneEquipData const &eq, + std::string_view eioLabel, + std::string_view illegalZoneLabel, + bool hasEndUseSub) + { + static constexpr std::string_view Format_722(" {} Internal Gains Nominal, {},{},{},{:.2R},{:.1R},"); + static constexpr std::string_view Format_724(" {}, {}\n"); + + if (eq.ZonePtr == 0) { + print(state.files.eio, Format_724, illegalZoneLabel, eq.Name); + return; + } + + auto const &zone = state.dataHeatBal->Zone(eq.ZonePtr); + + print(state.files.eio, Format_722, eioLabel, eq.Name, eq.sched->Name, zone.Name, zone.FloorArea, zone.TotOccupants); + print(state.files.eio, "{:.3R},", eq.DesignLevel); + + // Equipment per floor area + if (zone.FloorArea > 0.0) { + print(state.files.eio, "{:.3R},", eq.DesignLevel / zone.FloorArea); + } else { + print(state.files.eio, "N/A,"); + } + // Equipment per person + if (zone.TotOccupants > 0.0) { + print(state.files.eio, "{:.3R},", eq.DesignLevel / zone.TotOccupants); + } else { + print(state.files.eio, "N/A,"); + } + + print(state.files.eio, "{:.3R},", eq.FractionLatent); + print(state.files.eio, "{:.3R},", eq.FractionRadiant); + print(state.files.eio, "{:.3R},", eq.FractionLost); + print(state.files.eio, "{:.3R},", eq.FractionConvected); + if (hasEndUseSub) { + print(state.files.eio, "{},", eq.EndUseSubcategory); + } + print(state.files.eio, "{:.3R},", eq.NomMinDesignLevel); + print(state.files.eio, "{:.3R},", eq.NomMaxDesignLevel); + + printEioScheduleMinMax(state, eq.sched, eq.DesignLevel); + } + void ManageInternalHeatGains(EnergyPlusData &state, ObjexxFCL::Optional_bool_const InitOnly) // when true, just calls the get input, if appropriate and returns. { @@ -287,6 +351,44 @@ namespace InternalHeatGains { auto &ErrorsFound(state.dataInternalHeatGains->ErrorsFound); + // Compute FractionConvected from the three input fractions, snap near-zero to zero, + // and report a "Sum of Fractions > 1.0" severe error when negative. + // emitError is false when the caller only wants to report on the first space instance. + auto calcFractionConvected = [&](Real64 &fractionConvected, + Real64 fractionLatent, + Real64 fractionRadiant, + Real64 fractionLost, + std::string_view moduleObject, + std::string_view itemName, + bool emitError = true) { + fractionConvected = 1.0 - (fractionLatent + fractionRadiant + fractionLost); + if (std::abs(fractionConvected) <= 0.001) { + fractionConvected = 0.0; + } + if (fractionConvected < 0.0 && emitError) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", Sum of Fractions > 1.0", RoutineName, moduleObject, itemName)); + ErrorsFound = true; + } + }; + + // Map DesignLevelMethod enum to the IHGNumbers field index (1-based) for + // Gas/HotWater/Steam/OtherEquipment which all share the same three-method pattern. + auto getEquipLevelFieldNum = [](DesignLevelMethod levelMethod) -> int { + switch (levelMethod) { + case DesignLevelMethod::EquipmentLevel: + return 1; + case DesignLevelMethod::WattsPerArea: + case DesignLevelMethod::PowerPerArea: + return 2; + case DesignLevelMethod::WattsPerPerson: + case DesignLevelMethod::PowerPerPerson: + return 3; + default: + assert(false); + return 1; + } + }; + // TODO MJW: Punt for now, sometimes unit test need these to be allocated in AllocateZoneHeatBalArrays, but simulations need them here if (!state.dataHeatBal->ZoneIntGain.allocated()) { DataHeatBalance::AllocateIntGains(state); @@ -353,6 +455,27 @@ namespace InternalHeatGains { IHGNumNumbers = 0; } + // Read optional CO2 rate factor from field 7 and validate range [0, 4.0e-7]. + auto readAndValidateCO2RateFactor = [&](Real64 &co2RateFactor, std::string_view moduleObject, std::string_view objectName) { + if ((IHGNumNumbers == 7) || (!IHGNumericFieldBlanks(7))) { + co2RateFactor = IHGNumbers(7); + } + if (co2RateFactor < 0.0) { + ShowSevereError( + state, + EnergyPlus::format( + "{}{}=\"{}\", {} < 0.0, value ={:.2R}", RoutineName, moduleObject, objectName, IHGNumericFieldNames(7), IHGNumbers(7))); + ErrorsFound = true; + } + if (co2RateFactor > 4.0e-7) { + ShowSevereError( + state, + EnergyPlus::format( + "{}{}=\"{}\", {} > 4.0E-7, value ={:.2R}", RoutineName, moduleObject, objectName, IHGNumericFieldNames(7), IHGNumbers(7))); + ErrorsFound = true; + } + }; + // PEOPLE: Includes both information related to the heat balance and thermal comfort EPVector peopleObjects; int numPeopleStatements = 0; @@ -1260,6 +1383,25 @@ namespace InternalHeatGains { PreDefTableEntry(state, state.dataOutRptPredefined->pdchInLtArea, "Interior Lighting Total", sumArea); PreDefTableEntry(state, state.dataOutRptPredefined->pdchInLtPower, "Interior Lighting Total", sumPower); + // Validate that IHGAlphas(schedAlphaIdx) is a non-blank schedule name, is found, and has + // a minimum value >= 0. Returns the Schedule pointer (nullptr on error). Used by the + // ElectricEquipment/GasEquipment/HotWaterEquipment/SteamEquipment input blocks which all + // have the schedule at alpha field 3 with a min-zero constraint. + auto getAndValidateSchedMinZero = [&](const ErrorObjectHeader &eoh, int schedAlphaIdx) -> Sched::Schedule * { + Sched::Schedule *sched = Sched::GetSchedule(state, IHGAlphas(schedAlphaIdx)); + if (IHGAlphaFieldBlanks(schedAlphaIdx)) { + ShowSevereEmptyField(state, eoh, IHGAlphaFieldNames(schedAlphaIdx)); + ErrorsFound = true; + } else if (sched == nullptr) { + ShowSevereItemNotFound(state, eoh, IHGAlphaFieldNames(schedAlphaIdx), IHGAlphas(schedAlphaIdx)); + ErrorsFound = true; + } else if (!sched->checkMinVal(state, Clusive::In, 0.0)) { + Sched::ShowSevereBadMin(state, eoh, IHGAlphaFieldNames(schedAlphaIdx), IHGAlphas(schedAlphaIdx), Clusive::In, 0.0); + ErrorsFound = true; + } + return sched; + }; + // ElectricEquipment // Declared in state because the lights inputs are needed for demand manager int numZoneElectricStatements = 0; @@ -1289,17 +1431,7 @@ namespace InternalHeatGains { IHGNumericFieldNames); ErrorObjectHeader eoh{routineName, elecEqModuleObject, IHGAlphas(1)}; - Sched::Schedule *schedPtr = Sched::GetSchedule(state, IHGAlphas(3)); - if (IHGAlphaFieldBlanks(3)) { - ShowSevereEmptyField(state, eoh, IHGAlphaFieldNames(3)); - ErrorsFound = true; - } else if (schedPtr == nullptr) { - ShowSevereItemNotFound(state, eoh, IHGAlphaFieldNames(3), IHGAlphas(3)); - ErrorsFound = true; - } else if (!schedPtr->checkMinVal(state, Clusive::In, 0.0)) { - Sched::ShowSevereBadMin(state, eoh, IHGAlphaFieldNames(3), IHGAlphas(3), Clusive::In, 0.0); - ErrorsFound = true; - } + Sched::Schedule *schedPtr = getAndValidateSchedMinZero(eoh, 3); auto &thisElecEqInput = state.dataInternalHeatGains->zoneElectricObjects(elecEqInputNum); DesignLevelMethod const levelMethod = static_cast(getEnumValue(DesignLevelMethodNamesUC, IHGAlphas(4))); @@ -1344,16 +1476,12 @@ namespace InternalHeatGains { thisZoneElectric.FractionRadiant = IHGNumbers(5); thisZoneElectric.FractionLost = IHGNumbers(6); // FractionConvected is a calculated field - thisZoneElectric.FractionConvected = - 1.0 - (thisZoneElectric.FractionLatent + thisZoneElectric.FractionRadiant + thisZoneElectric.FractionLost); - if (std::abs(thisZoneElectric.FractionConvected) <= 0.001) { - thisZoneElectric.FractionConvected = 0.0; - } - if (thisZoneElectric.FractionConvected < 0.0) { - ShowSevereError( - state, EnergyPlus::format("{}{}=\"{}\", Sum of Fractions > 1.0", RoutineName, elecEqModuleObject, thisElecEqInput.Name)); - ErrorsFound = true; - } + calcFractionConvected(thisZoneElectric.FractionConvected, + thisZoneElectric.FractionLatent, + thisZoneElectric.FractionRadiant, + thisZoneElectric.FractionLost, + elecEqModuleObject, + thisElecEqInput.Name); if (IHGNumAlphas > 4) { thisZoneElectric.EndUseSubcategory = IHGAlphas(5); @@ -1410,37 +1538,11 @@ namespace InternalHeatGains { IHGNumericFieldNames); ErrorObjectHeader eoh{routineName, gasEqModuleObject, IHGAlphas(1)}; - Sched::Schedule *schedPtr = Sched::GetSchedule(state, IHGAlphas(3)); - if (IHGAlphaFieldBlanks(3)) { - ShowSevereEmptyField(state, eoh, IHGAlphaFieldNames(3)); - ErrorsFound = true; - } else if (schedPtr == nullptr) { - ShowSevereItemNotFound(state, eoh, IHGAlphaFieldNames(3), IHGAlphas(3)); - ErrorsFound = true; - } else if (!schedPtr->checkMinVal(state, Clusive::In, 0.0)) { - Sched::ShowSevereBadMin(state, eoh, IHGAlphaFieldNames(3), IHGAlphas(3), Clusive::In, 0.0); - ErrorsFound = true; - } + Sched::Schedule *schedPtr = getAndValidateSchedMinZero(eoh, 3); auto &thisGasEqInput = zoneGasObjects(gasEqInputNum); DesignLevelMethod const levelMethod = static_cast(getEnumValue(DesignLevelMethodNamesUC, IHGAlphas(4))); - int fieldNum = 1; - switch (levelMethod) { - case DesignLevelMethod::EquipmentLevel: { - fieldNum = 1; - } break; - case DesignLevelMethod::WattsPerArea: - case DesignLevelMethod::PowerPerArea: { - fieldNum = 2; - } break; - case DesignLevelMethod::WattsPerPerson: - case DesignLevelMethod::PowerPerPerson: { - fieldNum = 3; - } break; - default: { - assert(false); - } break; - } + int const fieldNum = getEquipLevelFieldNum(levelMethod); Real64 const levelValue = IHGNumbers(fieldNum); bool const levelBlank = IHGNumericFieldBlanks(fieldNum); std::string_view const levelField = IHGNumericFieldNames(fieldNum); @@ -1467,42 +1569,15 @@ namespace InternalHeatGains { thisZoneGas.FractionRadiant = IHGNumbers(5); thisZoneGas.FractionLost = IHGNumbers(6); - if ((IHGNumNumbers == 7) || (!IHGNumericFieldBlanks(7))) { - thisZoneGas.CO2RateFactor = IHGNumbers(7); - } - if (thisZoneGas.CO2RateFactor < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} < 0.0, value ={:.2R}", - RoutineName, - gasEqModuleObject, - thisGasEqInput.Name, - IHGNumericFieldNames(7), - IHGNumbers(7))); - ErrorsFound = true; - } - if (thisZoneGas.CO2RateFactor > 4.0e-7) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} > 4.0E-7, value ={:.2R}", - RoutineName, - gasEqModuleObject, - thisGasEqInput.Name, - IHGNumericFieldNames(7), - IHGNumbers(7))); - ErrorsFound = true; - } + readAndValidateCO2RateFactor(thisZoneGas.CO2RateFactor, gasEqModuleObject, thisGasEqInput.Name); // FractionConvected is a calculated field - thisZoneGas.FractionConvected = 1.0 - (thisZoneGas.FractionLatent + thisZoneGas.FractionRadiant + thisZoneGas.FractionLost); - if (std::abs(thisZoneGas.FractionConvected) <= 0.001) { - thisZoneGas.FractionConvected = 0.0; - } - if (thisZoneGas.FractionConvected < 0.0) { - if (Item1 == 1) { - ShowSevereError( - state, - EnergyPlus::format("{}{}=\"{}\", Sum of Fractions > 1.0", RoutineName, gasEqModuleObject, thisGasEqInput.Name)); - ErrorsFound = true; - } - } + calcFractionConvected(thisZoneGas.FractionConvected, + thisZoneGas.FractionLatent, + thisZoneGas.FractionRadiant, + thisZoneGas.FractionLost, + gasEqModuleObject, + thisGasEqInput.Name, + Item1 == 1); if (IHGNumAlphas > 4) { thisZoneGas.EndUseSubcategory = IHGAlphas(5); @@ -1563,37 +1638,11 @@ namespace InternalHeatGains { IHGNumericFieldNames); ErrorObjectHeader eoh{routineName, hwEqModuleObject, IHGAlphas(1)}; - Sched::Schedule *schedPtr = Sched::GetSchedule(state, IHGAlphas(3)); - if (IHGAlphaFieldBlanks(3)) { - ShowSevereEmptyField(state, eoh, IHGAlphaFieldNames(3)); - ErrorsFound = true; - } else if (schedPtr == nullptr) { - ShowSevereItemNotFound(state, eoh, IHGAlphaFieldNames(3), IHGAlphas(3)); - ErrorsFound = true; - } else if (!schedPtr->checkMinVal(state, Clusive::In, 0.0)) { - Sched::ShowSevereBadMin(state, eoh, IHGAlphaFieldNames(3), IHGAlphas(3), Clusive::In, 0.0); - ErrorsFound = true; - } + Sched::Schedule *schedPtr = getAndValidateSchedMinZero(eoh, 3); auto &thisHWEqInput = hotWaterEqObjects(hwEqInputNum); DesignLevelMethod const levelMethod = static_cast(getEnumValue(DesignLevelMethodNamesUC, IHGAlphas(4))); - int fieldNum = 1; - switch (levelMethod) { - case DesignLevelMethod::EquipmentLevel: { - fieldNum = 1; - } break; - case DesignLevelMethod::WattsPerArea: - case DesignLevelMethod::PowerPerArea: { - fieldNum = 2; - } break; - case DesignLevelMethod::WattsPerPerson: - case DesignLevelMethod::PowerPerPerson: { - fieldNum = 3; - } break; - default: { - assert(false); - } break; - } + int const fieldNum = getEquipLevelFieldNum(levelMethod); Real64 const levelValue = IHGNumbers(fieldNum); bool const levelBlank = IHGNumericFieldBlanks(fieldNum); std::string_view const levelField = IHGNumericFieldNames(fieldNum); @@ -1620,15 +1669,12 @@ namespace InternalHeatGains { thisZoneHWEq.FractionRadiant = IHGNumbers(5); thisZoneHWEq.FractionLost = IHGNumbers(6); // FractionConvected is a calculated field - thisZoneHWEq.FractionConvected = 1.0 - (thisZoneHWEq.FractionLatent + thisZoneHWEq.FractionRadiant + thisZoneHWEq.FractionLost); - if (std::abs(thisZoneHWEq.FractionConvected) <= 0.001) { - thisZoneHWEq.FractionConvected = 0.0; - } - if (thisZoneHWEq.FractionConvected < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", Sum of Fractions > 1.0", RoutineName, hwEqModuleObject, thisHWEqInput.Name)); - ErrorsFound = true; - } + calcFractionConvected(thisZoneHWEq.FractionConvected, + thisZoneHWEq.FractionLatent, + thisZoneHWEq.FractionRadiant, + thisZoneHWEq.FractionLost, + hwEqModuleObject, + thisHWEqInput.Name); if (IHGNumAlphas > 4) { thisZoneHWEq.EndUseSubcategory = IHGAlphas(5); @@ -1686,37 +1732,11 @@ namespace InternalHeatGains { IHGNumericFieldNames); ErrorObjectHeader eoh{routineName, stmEqModuleObject, IHGAlphas(1)}; - Sched::Schedule *schedPtr = Sched::GetSchedule(state, IHGAlphas(3)); - if (IHGAlphaFieldBlanks(3)) { - ShowSevereEmptyField(state, eoh, IHGAlphaFieldNames(3)); - ErrorsFound = true; - } else if (schedPtr == nullptr) { - ShowSevereItemNotFound(state, eoh, IHGAlphaFieldNames(3), IHGAlphas(3)); - ErrorsFound = true; - } else if (!schedPtr->checkMinVal(state, Clusive::In, 0.0)) { - Sched::ShowSevereBadMin(state, eoh, IHGAlphaFieldNames(3), IHGAlphas(3), Clusive::In, 0.0); - ErrorsFound = true; - } + Sched::Schedule *schedPtr = getAndValidateSchedMinZero(eoh, 3); auto &thisStmEqInput = steamEqObjects(stmEqInputNum); DesignLevelMethod const levelMethod = static_cast(getEnumValue(DesignLevelMethodNamesUC, IHGAlphas(4))); - int fieldNum = 1; - switch (levelMethod) { - case DesignLevelMethod::EquipmentLevel: { - fieldNum = 1; - } break; - case DesignLevelMethod::WattsPerArea: - case DesignLevelMethod::PowerPerArea: { - fieldNum = 2; - } break; - case DesignLevelMethod::WattsPerPerson: - case DesignLevelMethod::PowerPerPerson: { - fieldNum = 3; - } break; - default: { - assert(false); - } break; - } + int const fieldNum = getEquipLevelFieldNum(levelMethod); Real64 const levelValue = IHGNumbers(fieldNum); bool const levelBlank = IHGNumericFieldBlanks(fieldNum); std::string_view const levelField = IHGNumericFieldNames(fieldNum); @@ -1743,16 +1763,12 @@ namespace InternalHeatGains { thisZoneStmEq.FractionRadiant = IHGNumbers(5); thisZoneStmEq.FractionLost = IHGNumbers(6); // FractionConvected is a calculated field - thisZoneStmEq.FractionConvected = - 1.0 - (thisZoneStmEq.FractionLatent + thisZoneStmEq.FractionRadiant + thisZoneStmEq.FractionLost); - if (std::abs(thisZoneStmEq.FractionConvected) <= 0.001) { - thisZoneStmEq.FractionConvected = 0.0; - } - if (thisZoneStmEq.FractionConvected < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", Sum of Fractions > 1.0", RoutineName, stmEqModuleObject, IHGAlphas(1))); - ErrorsFound = true; - } + calcFractionConvected(thisZoneStmEq.FractionConvected, + thisZoneStmEq.FractionLatent, + thisZoneStmEq.FractionRadiant, + thisZoneStmEq.FractionLost, + stmEqModuleObject, + IHGAlphas(1)); if (IHGNumAlphas > 4) { thisZoneStmEq.EndUseSubcategory = IHGAlphas(5); @@ -1831,23 +1847,7 @@ namespace InternalHeatGains { auto &thisOthEqInput = otherEqObjects(othEqInputNum); DesignLevelMethod const levelMethod = static_cast(getEnumValue(DesignLevelMethodNamesUC, IHGAlphas(5))); - int levelFieldNum = 1; - switch (levelMethod) { - case DesignLevelMethod::EquipmentLevel: { - levelFieldNum = 1; - } break; - case DesignLevelMethod::WattsPerArea: - case DesignLevelMethod::PowerPerArea: { - levelFieldNum = 2; - } break; - case DesignLevelMethod::WattsPerPerson: - case DesignLevelMethod::PowerPerPerson: { - levelFieldNum = 3; - } break; - default: { - assert(false); - } break; - } + int const levelFieldNum = getEquipLevelFieldNum(levelMethod); Real64 const levelValue = IHGNumbers(levelFieldNum); bool const levelBlank = IHGNumericFieldBlanks(levelFieldNum); std::string_view const levelField = IHGNumericFieldNames(levelFieldNum); @@ -1932,41 +1932,15 @@ namespace InternalHeatGains { thisZoneOthEq.FractionRadiant = IHGNumbers(5); thisZoneOthEq.FractionLost = IHGNumbers(6); - if ((IHGNumNumbers == 7) || (!IHGNumericFieldBlanks(7))) { - thisZoneOthEq.CO2RateFactor = IHGNumbers(7); - } - if (thisZoneOthEq.CO2RateFactor < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} < 0.0, value ={:.2R}", - RoutineName, - othEqModuleObject, - thisOthEqInput.Name, - IHGNumericFieldNames(7), - IHGNumbers(7))); - ErrorsFound = true; - } - if (thisZoneOthEq.CO2RateFactor > 4.0e-7) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} > 4.0E-7, value ={:.2R}", - RoutineName, - othEqModuleObject, - thisOthEqInput.Name, - IHGNumericFieldNames(7), - IHGNumbers(7))); - ErrorsFound = true; - } + readAndValidateCO2RateFactor(thisZoneOthEq.CO2RateFactor, othEqModuleObject, thisOthEqInput.Name); // FractionConvected is a calculated field - thisZoneOthEq.FractionConvected = - 1.0 - (thisZoneOthEq.FractionLatent + thisZoneOthEq.FractionRadiant + thisZoneOthEq.FractionLost); - if (std::abs(thisZoneOthEq.FractionConvected) <= 0.001) { - thisZoneOthEq.FractionConvected = 0.0; - } - if (thisZoneOthEq.FractionConvected < 0.0) { - ShowSevereError( - state, EnergyPlus::format("{}{}=\"{}\", Sum of Fractions > 1.0", RoutineName, othEqModuleObject, thisOthEqInput.Name)); - ErrorsFound = true; - } + calcFractionConvected(thisZoneOthEq.FractionConvected, + thisZoneOthEq.FractionLatent, + thisZoneOthEq.FractionRadiant, + thisZoneOthEq.FractionLost, + othEqModuleObject, + thisOthEqInput.Name); if (IHGNumAlphas > 5) { thisZoneOthEq.EndUseSubcategory = IHGAlphas(6); @@ -2188,53 +2162,27 @@ namespace InternalHeatGains { bool hasSupplyApproachTemp = !IHGNumericFieldBlanks(10); bool hasReturnApproachTemp = !IHGNumericFieldBlanks(11); - // Performance curves - thisZoneITEq.CPUPowerFLTCurve = GetCurveIndex(state, IHGAlphas(7)); - if (thisZoneITEq.CPUPowerFLTCurve == 0) { - ShowSevereError(state, EnergyPlus::format("{}{} \"{}\"", RoutineName, itEqModuleObject, IHGAlphas(1))); - ShowContinueError(state, EnergyPlus::format("Invalid {}={}", IHGAlphaFieldNames(7), IHGAlphas(7))); - ErrorsFound = true; - } - - thisZoneITEq.AirFlowFLTCurve = GetCurveIndex(state, IHGAlphas(8)); - if (thisZoneITEq.AirFlowFLTCurve == 0) { - ShowSevereError(state, EnergyPlus::format("{}{} \"{}\"", RoutineName, itEqModuleObject, IHGAlphas(1))); - ShowContinueError(state, EnergyPlus::format("Invalid {}={}", IHGAlphaFieldNames(8), IHGAlphas(8))); - ErrorsFound = true; - } - - thisZoneITEq.FanPowerFFCurve = GetCurveIndex(state, IHGAlphas(9)); - if (thisZoneITEq.FanPowerFFCurve == 0) { - ShowSevereError(state, EnergyPlus::format("{}{} \"{}\"", RoutineName, itEqModuleObject, IHGAlphas(1))); - ShowContinueError(state, EnergyPlus::format("Invalid {}={}", IHGAlphaFieldNames(9), IHGAlphas(9))); - ErrorsFound = true; - } - - if (!IHGAlphaFieldBlanks(15)) { - // If this field isn't blank, it must point to a valid curve - thisZoneITEq.RecircFLTCurve = GetCurveIndex(state, IHGAlphas(15)); - if (thisZoneITEq.RecircFLTCurve == 0) { - ShowSevereError(state, EnergyPlus::format("{}{} \"{}\"", RoutineName, itEqModuleObject, IHGAlphas(1))); - ShowContinueError(state, EnergyPlus::format("Invalid {}={}", IHGAlphaFieldNames(15), IHGAlphas(15))); - ErrorsFound = true; + // Helper to look up a required or optional curve, emitting a severe error when invalid. + // For optional curves, pass optional=true; blank fields return 0 without error. + auto getITECurve = [&](int alphaIdx, bool optional = false) -> int { + if (optional && IHGAlphaFieldBlanks(alphaIdx)) { + return 0; // blank optional field defaults to always 1.0 } - } else { - // If this curve is left blank, then the curve is assumed to always equal 1.0. - thisZoneITEq.RecircFLTCurve = 0; - } - - if (!IHGAlphaFieldBlanks(16)) { - // If this field isn't blank, it must point to a valid curve - thisZoneITEq.UPSEfficFPLRCurve = GetCurveIndex(state, IHGAlphas(16)); - if (thisZoneITEq.UPSEfficFPLRCurve == 0) { + int idx = GetCurveIndex(state, IHGAlphas(alphaIdx)); + if (idx == 0) { ShowSevereError(state, EnergyPlus::format("{}{} \"{}\"", RoutineName, itEqModuleObject, IHGAlphas(1))); - ShowContinueError(state, EnergyPlus::format("Invalid {}={}", IHGAlphaFieldNames(16), IHGAlphas(16))); + ShowContinueError(state, EnergyPlus::format("Invalid {}={}", IHGAlphaFieldNames(alphaIdx), IHGAlphas(alphaIdx))); ErrorsFound = true; } - } else { - // If this curve is left blank, then the curve is assumed to always equal 1.0. - thisZoneITEq.UPSEfficFPLRCurve = 0; - } + return idx; + }; + + // Performance curves + thisZoneITEq.CPUPowerFLTCurve = getITECurve(7); + thisZoneITEq.AirFlowFLTCurve = getITECurve(8); + thisZoneITEq.FanPowerFFCurve = getITECurve(9); + thisZoneITEq.RecircFLTCurve = getITECurve(15, true); + thisZoneITEq.UPSEfficFPLRCurve = getITECurve(16, true); // Environmental class thisZoneITEq.Class = static_cast(getEnumValue(ITEClassNamesUC, Util::makeUPPER(IHGAlphas(10)))); @@ -2887,8 +2835,6 @@ namespace InternalHeatGains { } for (int Loop = 1; Loop <= state.dataHeatBal->TotElecEquip; ++Loop) { - auto &elecEq = state.dataHeatBal->ZoneElectric(Loop); - if (Loop == 1) { print(state.files.eio, Format_723, @@ -2901,54 +2847,10 @@ namespace InternalHeatGains { "Minimum Equipment Level for Summer Design Days {W}, Maximum Equipment Level for Summer Design Days {W}," "Minimum Equipment Level for Winter Design Days {W}, Maximum Equipment Level for Winter Design Days {W}\n"); } - - if (elecEq.ZonePtr == 0) { - print(state.files.eio, Format_724, "Electric Equipment-Illegal Zone specified", elecEq.Name); - continue; - } - - auto &zone = state.dataHeatBal->Zone(elecEq.ZonePtr); - - print(state.files.eio, Format_722, "ElectricEquipment", elecEq.Name, elecEq.sched->Name, zone.Name, zone.FloorArea, zone.TotOccupants); - print(state.files.eio, "{:.3R},", elecEq.DesignLevel); - - print_and_divide_if_greater_than_zero(elecEq.DesignLevel, zone.FloorArea); - print_and_divide_if_greater_than_zero(elecEq.DesignLevel, zone.TotOccupants); - - print(state.files.eio, "{:.3R},", elecEq.FractionLatent); - print(state.files.eio, "{:.3R},", elecEq.FractionRadiant); - print(state.files.eio, "{:.3R},", elecEq.FractionLost); - print(state.files.eio, "{:.3R},", elecEq.FractionConvected); - print(state.files.eio, "{},", elecEq.EndUseSubcategory); - print(state.files.eio, "{:.3R},", elecEq.NomMinDesignLevel); - print(state.files.eio, "{:.3R},", elecEq.NomMaxDesignLevel); - - Real64 SchMin, SchMax; - - // weekdays - std::tie(SchMin, SchMax) = elecEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::Weekday); - print(state.files.eio, "{:.3R},", elecEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", elecEq.DesignLevel * SchMax); - - // weekends/holidays - std::tie(SchMin, SchMax) = elecEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WeekEndHoliday); - print(state.files.eio, "{:.3R},", elecEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", elecEq.DesignLevel * SchMax); - - // summer design days - std::tie(SchMin, SchMax) = elecEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::SummerDesignDay); - print(state.files.eio, "{:.3R},", elecEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", elecEq.DesignLevel * SchMax); - - // winter design days - std::tie(SchMin, SchMax) = elecEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WinterDesignDay); - print(state.files.eio, "{:.3R},", elecEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R}\n", elecEq.DesignLevel * SchMax); + printEquipEioRow(state, state.dataHeatBal->ZoneElectric(Loop), "ElectricEquipment", "Electric Equipment-Illegal Zone specified", true); } for (int Loop = 1; Loop <= state.dataHeatBal->TotGasEquip; ++Loop) { - auto &gasEq = state.dataHeatBal->ZoneGas(Loop); - if (Loop == 1) { print(state.files.eio, Format_723, @@ -2961,53 +2863,10 @@ namespace InternalHeatGains { "Minimum Equipment Level for Summer Design Days {W}, Maximum Equipment Level for Summer Design Days {W}," "Minimum Equipment Level for Winter Design Days {W}, Maximum Equipment Level for Winter Design Days {W}\n"); } - - if (gasEq.ZonePtr == 0) { - print(state.files.eio, Format_724, "Gas Equipment-Illegal Zone specified", gasEq.Name); - continue; - } - - auto &zone = state.dataHeatBal->Zone(gasEq.ZonePtr); - - print(state.files.eio, Format_722, "GasEquipment", gasEq.Name, gasEq.sched->Name, zone.Name, zone.FloorArea, zone.TotOccupants); - print(state.files.eio, "{:.3R},", gasEq.DesignLevel); - - print_and_divide_if_greater_than_zero(gasEq.DesignLevel, zone.FloorArea); - print_and_divide_if_greater_than_zero(gasEq.DesignLevel, zone.TotOccupants); - - print(state.files.eio, "{:.3R},", gasEq.FractionLatent); - print(state.files.eio, "{:.3R},", gasEq.FractionRadiant); - print(state.files.eio, "{:.3R},", gasEq.FractionLost); - print(state.files.eio, "{:.3R},", gasEq.FractionConvected); - print(state.files.eio, "{},", gasEq.EndUseSubcategory); - print(state.files.eio, "{:.3R},", gasEq.NomMinDesignLevel); - print(state.files.eio, "{:.3R},", gasEq.NomMaxDesignLevel); - - Real64 SchMin, SchMax; - // weekdays - std::tie(SchMin, SchMax) = gasEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::Weekday); - print(state.files.eio, "{:.3R},", gasEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", gasEq.DesignLevel * SchMax); - - // weekends/holidays - std::tie(SchMin, SchMax) = gasEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WeekEndHoliday); - print(state.files.eio, "{:.3R},", gasEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", gasEq.DesignLevel * SchMax); - - // summer design days - std::tie(SchMin, SchMax) = gasEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::SummerDesignDay); - print(state.files.eio, "{:.3R},", gasEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", gasEq.DesignLevel * SchMax); - - // winter design days - std::tie(SchMin, SchMax) = gasEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WinterDesignDay); - print(state.files.eio, "{:.3R},", gasEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R}\n", gasEq.DesignLevel * SchMax); + printEquipEioRow(state, state.dataHeatBal->ZoneGas(Loop), "GasEquipment", "Gas Equipment-Illegal Zone specified", true); } for (int Loop = 1; Loop <= state.dataHeatBal->TotHWEquip; ++Loop) { - auto &hotWaterEq = state.dataHeatBal->ZoneHWEq(Loop); - if (Loop == 1) { print(state.files.eio, Format_723, @@ -3020,116 +2879,24 @@ namespace InternalHeatGains { "Minimum Equipment Level for Summer Design Days {W}, Maximum Equipment Level for Summer Design Days {W}," "Minimum Equipment Level for Winter Design Days {W}, Maximum Equipment Level for Winter Design Days {W}\n"); } + printEquipEioRow(state, state.dataHeatBal->ZoneHWEq(Loop), "HotWaterEquipment", "Hot Water Equipment-Illegal Zone specified", true); + } - if (hotWaterEq.ZonePtr == 0) { - print(state.files.eio, Format_724, "Hot Water Equipment-Illegal Zone specified", hotWaterEq.Name); - continue; + for (int Loop = 1; Loop <= state.dataHeatBal->TotStmEquip; ++Loop) { + if (Loop == 1) { + print(state.files.eio, + Format_723, + "SteamEquipment", + "Equipment Level {W},Equipment/Floor Area {W/m2},Equipment per person {W/person},Fraction Latent,Fraction Radiant,Fraction " + "Lost,Fraction Convected,End-Use SubCategory," + "Minimum Equipment Level for All Day Types {W},Maximum Equipment Level for All Day Types {W}," + "Minimum Equipment Level for Weekdays {W}, Maximum Equipment Level for Weekdays {W}," + "Minimum Equipment Level for Weekends/Holidays {W}, Maximum Equipment Level for Weekends /Holidays {W}," + "Minimum Equipment Level for Summer Design Days {W}, Maximum Equipment Level for Summer Design Days {W}," + "Minimum Equipment Level for Winter Design Days {W}, Maximum Equipment Level for Winter Design Days {W}\n"); } - - auto const &zone = state.dataHeatBal->Zone(hotWaterEq.ZonePtr); - - print(state.files.eio, - Format_722, - "HotWaterEquipment", - hotWaterEq.Name, - hotWaterEq.sched->Name, - zone.Name, - zone.FloorArea, - zone.TotOccupants); - - print(state.files.eio, "{:.3R},", hotWaterEq.DesignLevel); - - print_and_divide_if_greater_than_zero(hotWaterEq.DesignLevel, zone.FloorArea); - print_and_divide_if_greater_than_zero(hotWaterEq.DesignLevel, zone.TotOccupants); - - print(state.files.eio, "{:.3R},", hotWaterEq.FractionLatent); - print(state.files.eio, "{:.3R},", hotWaterEq.FractionRadiant); - print(state.files.eio, "{:.3R},", hotWaterEq.FractionLost); - print(state.files.eio, "{:.3R},", hotWaterEq.FractionConvected); - print(state.files.eio, "{},", hotWaterEq.EndUseSubcategory); - print(state.files.eio, "{:.3R},", hotWaterEq.NomMinDesignLevel); - print(state.files.eio, "{:.3R},", hotWaterEq.NomMaxDesignLevel); - - Real64 SchMin, SchMax; - // weekdays - std::tie(SchMin, SchMax) = hotWaterEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::Weekday); - print(state.files.eio, "{:.3R},", hotWaterEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", hotWaterEq.DesignLevel * SchMax); - - // weekends/holidays - std::tie(SchMin, SchMax) = hotWaterEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WeekEndHoliday); - print(state.files.eio, "{:.3R},", hotWaterEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", hotWaterEq.DesignLevel * SchMax); - - // summer design days - std::tie(SchMin, SchMax) = hotWaterEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::SummerDesignDay); - print(state.files.eio, "{:.3R},", hotWaterEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", hotWaterEq.DesignLevel * SchMax); - - // winter design days - std::tie(SchMin, SchMax) = hotWaterEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WinterDesignDay); - print(state.files.eio, "{:.3R},", hotWaterEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R}\n", hotWaterEq.DesignLevel * SchMax); - } - - for (int Loop = 1; Loop <= state.dataHeatBal->TotStmEquip; ++Loop) { - auto &steamEq = state.dataHeatBal->ZoneSteamEq(Loop); - - if (Loop == 1) { - print(state.files.eio, - Format_723, - "SteamEquipment", - "Equipment Level {W},Equipment/Floor Area {W/m2},Equipment per person {W/person},Fraction Latent,Fraction Radiant,Fraction " - "Lost,Fraction Convected,End-Use SubCategory," - "Minimum Equipment Level for All Day Types {W},Maximum Equipment Level for All Day Types {W}," - "Minimum Equipment Level for Weekdays {W}, Maximum Equipment Level for Weekdays {W}," - "Minimum Equipment Level for Weekends/Holidays {W}, Maximum Equipment Level for Weekends /Holidays {W}," - "Minimum Equipment Level for Summer Design Days {W}, Maximum Equipment Level for Summer Design Days {W}," - "Minimum Equipment Level for Winter Design Days {W}, Maximum Equipment Level for Winter Design Days {W}\n"); - } - - if (steamEq.ZonePtr == 0) { - print(state.files.eio, Format_724, "Steam Equipment-Illegal Zone specified", steamEq.Name); - continue; - } - - auto &zone = state.dataHeatBal->Zone(steamEq.ZonePtr); - - print(state.files.eio, Format_722, "SteamEquipment", steamEq.Name, steamEq.sched->Name, zone.Name, zone.FloorArea, zone.TotOccupants); - print(state.files.eio, "{:.3R},", steamEq.DesignLevel); - - print_and_divide_if_greater_than_zero(steamEq.DesignLevel, zone.FloorArea); - print_and_divide_if_greater_than_zero(steamEq.DesignLevel, zone.TotOccupants); - - print(state.files.eio, "{:.3R},", steamEq.FractionLatent); - print(state.files.eio, "{:.3R},", steamEq.FractionRadiant); - print(state.files.eio, "{:.3R},", steamEq.FractionLost); - print(state.files.eio, "{:.3R},", steamEq.FractionConvected); - print(state.files.eio, "{},", steamEq.EndUseSubcategory); - print(state.files.eio, "{:.3R},", steamEq.NomMinDesignLevel); - print(state.files.eio, "{:.3R},", steamEq.NomMaxDesignLevel); - - Real64 SchMin, SchMax; - // weekdays - std::tie(SchMin, SchMax) = steamEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::Weekday); - print(state.files.eio, "{:.3R},", steamEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", steamEq.DesignLevel * SchMax); - - // weekends/holidays - std::tie(SchMin, SchMax) = steamEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WeekEndHoliday); - print(state.files.eio, "{:.3R},", steamEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", steamEq.DesignLevel * SchMax); - - // summer design days - std::tie(SchMin, SchMax) = steamEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::SummerDesignDay); - print(state.files.eio, "{:.3R},", steamEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", steamEq.DesignLevel * SchMax); - - // winter design days - std::tie(SchMin, SchMax) = steamEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WinterDesignDay); - print(state.files.eio, "{:.3R},", steamEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R}\n", steamEq.DesignLevel * SchMax); - } + printEquipEioRow(state, state.dataHeatBal->ZoneSteamEq(Loop), "SteamEquipment", "Steam Equipment-Illegal Zone specified", true); + } for (int Loop = 1; Loop <= state.dataHeatBal->TotOthEquip; ++Loop) { if (Loop == 1) { @@ -3144,50 +2911,7 @@ namespace InternalHeatGains { "Minimum Equipment Level for Summer Design Days {W}, Maximum Equipment Level for Summer Design Days {W}," "Minimum Equipment Level for Winter Design Days {W}, Maximum Equipment Level for Winter Design Days {W}\n"); } - - auto &otherEq = state.dataHeatBal->ZoneOtherEq(Loop); - - if (otherEq.ZonePtr == 0) { - print(state.files.eio, Format_724, "Other Equipment-Illegal Zone specified", otherEq.Name); - continue; - } - - auto const &zone = state.dataHeatBal->Zone(otherEq.ZonePtr); - - print(state.files.eio, Format_722, "OtherEquipment", otherEq.Name, otherEq.sched->Name, zone.Name, zone.FloorArea, zone.TotOccupants); - print(state.files.eio, "{:.3R},", otherEq.DesignLevel); - - print_and_divide_if_greater_than_zero(otherEq.DesignLevel, zone.FloorArea); - print_and_divide_if_greater_than_zero(otherEq.DesignLevel, zone.TotOccupants); - - print(state.files.eio, "{:.3R},", otherEq.FractionLatent); - print(state.files.eio, "{:.3R},", otherEq.FractionRadiant); - print(state.files.eio, "{:.3R},", otherEq.FractionLost); - print(state.files.eio, "{:.3R},", otherEq.FractionConvected); - print(state.files.eio, "{:.3R},", otherEq.NomMinDesignLevel); - print(state.files.eio, "{:.3R},", otherEq.NomMaxDesignLevel); - - Real64 SchMin, SchMax; - - // weekdays - std::tie(SchMin, SchMax) = otherEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::Weekday); - print(state.files.eio, "{:.3R},", otherEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", otherEq.DesignLevel * SchMax); - - // weekends/holidays - std::tie(SchMin, SchMax) = otherEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WeekEndHoliday); - print(state.files.eio, "{:.3R},", otherEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", otherEq.DesignLevel * SchMax); - - // summer design days - std::tie(SchMin, SchMax) = otherEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::SummerDesignDay); - print(state.files.eio, "{:.3R},", otherEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R},", otherEq.DesignLevel * SchMax); - - // winter design days - std::tie(SchMin, SchMax) = otherEq.sched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WinterDesignDay); - print(state.files.eio, "{:.3R},", otherEq.DesignLevel * SchMin); - print(state.files.eio, "{:.3R}\n", otherEq.DesignLevel * SchMax); + printEquipEioRow(state, state.dataHeatBal->ZoneOtherEq(Loop), "OtherEquipment", "Other Equipment-Illegal Zone specified", false); } for (int Loop = 1; Loop <= state.dataHeatBal->TotITEquip; ++Loop) { @@ -3237,26 +2961,7 @@ namespace InternalHeatGains { print(state.files.eio, "{:.3R},", itEq.NomMinDesignLevel); print(state.files.eio, "{:.3R},", itEq.NomMaxDesignLevel); - Real64 SchMin, SchMax; - // weekdays - std::tie(SchMin, SchMax) = itEq.operSched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::Weekday); - print(state.files.eio, "{:.3R},", itEq.DesignTotalPower * SchMin); - print(state.files.eio, "{:.3R},", itEq.DesignTotalPower * SchMax); - - // weekends/holidays - std::tie(SchMin, SchMax) = itEq.operSched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WeekEndHoliday); - print(state.files.eio, "{:.3R},", itEq.DesignTotalPower * SchMin); - print(state.files.eio, "{:.3R},", itEq.DesignTotalPower * SchMax); - - // summer design days - std::tie(SchMin, SchMax) = itEq.operSched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::SummerDesignDay); - print(state.files.eio, "{:.3R},", itEq.DesignTotalPower * SchMin); - print(state.files.eio, "{:.3R},", itEq.DesignTotalPower * SchMax); - - // winter design days - std::tie(SchMin, SchMax) = itEq.operSched->getMinMaxValsByDayType(state, Sched::DayTypeGroup::WinterDesignDay); - print(state.files.eio, "{:.3R},", itEq.DesignTotalPower * SchMin); - print(state.files.eio, "{:.3R},", itEq.DesignTotalPower * SchMax); + printEioScheduleMinMax(state, itEq.operSched, itEq.DesignTotalPower, false); print(state.files.eio, "{:.10R}\n", itEq.DesignAirVolFlowRate); } @@ -3572,154 +3277,704 @@ namespace InternalHeatGains { return designLevel; } - void setupIHGOutputs(EnergyPlusData &state) + // Register the 10 overall internal heat gain output variables for a single zone or space. + static void setupOverallOutputs(EnergyPlusData &state, DataHeatBalance::ZoneReportVars &rpt, std::string const &name, std::string_view prefix) + { + SetupOutputVariable(state, + EnergyPlus::format("{} Total Internal Radiant Heating Energy", prefix), + Constant::Units::J, + rpt.TotRadiantGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Total Internal Radiant Heating Rate", prefix), + Constant::Units::W, + rpt.TotRadiantGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Total Internal Visible Radiation Heating Energy", prefix), + Constant::Units::J, + rpt.TotVisHeatGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Total Internal Visible Radiation Heating Rate", prefix), + Constant::Units::W, + rpt.TotVisHeatGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Total Internal Convective Heating Energy", prefix), + Constant::Units::J, + rpt.TotConvectiveGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Total Internal Convective Heating Rate", prefix), + Constant::Units::W, + rpt.TotConvectiveGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Total Internal Latent Gain Energy", prefix), + Constant::Units::J, + rpt.TotLatentGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Total Internal Latent Gain Rate", prefix), + Constant::Units::W, + rpt.TotLatentGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Total Internal Total Heating Energy", prefix), + Constant::Units::J, + rpt.TotTotalHeatGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Total Internal Total Heating Rate", prefix), + Constant::Units::W, + rpt.TotTotalHeatGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + } + + // Register the 12 People zone/space total output variables for a single zone or space. + static void + setupPeopleZoneSpaceOutputs(EnergyPlusData &state, DataHeatBalance::ZoneReportVars &rpt, std::string const &name, std::string_view prefix) + { + SetupOutputVariable(state, + EnergyPlus::format("{} People Occupant Count", prefix), + Constant::Units::None, + rpt.PeopleNumOcc, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} People Radiant Heating Energy", prefix), + Constant::Units::J, + rpt.PeopleRadGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} People Radiant Heating Rate", prefix), + Constant::Units::W, + rpt.PeopleRadGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} People Convective Heating Energy", prefix), + Constant::Units::J, + rpt.PeopleConGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} People Convective Heating Rate", prefix), + Constant::Units::W, + rpt.PeopleConGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} People Sensible Heating Energy", prefix), + Constant::Units::J, + rpt.PeopleSenGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} People Sensible Heating Rate", prefix), + Constant::Units::W, + rpt.PeopleSenGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} People Latent Gain Energy", prefix), + Constant::Units::J, + rpt.PeopleLatGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} People Latent Gain Rate", prefix), + Constant::Units::W, + rpt.PeopleLatGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} People Total Heating Energy", prefix), + Constant::Units::J, + rpt.PeopleTotGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} People Total Heating Rate", prefix), + Constant::Units::W, + rpt.PeopleTotGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + } + + // Register the 12 Lights zone/space total output variables for a single zone or space. + static void + setupLightsZoneSpaceOutputs(EnergyPlusData &state, DataHeatBalance::ZoneReportVars &rpt, std::string const &name, std::string_view prefix) + { + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Electricity Rate", prefix), + Constant::Units::W, + rpt.LtsPower, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Electricity Energy", prefix), + Constant::Units::J, + rpt.LtsElecConsump, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Radiant Heating Energy", prefix), + Constant::Units::J, + rpt.LtsRadGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Radiant Heating Rate", prefix), + Constant::Units::W, + rpt.LtsRadGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Visible Radiation Heating Energy", prefix), + Constant::Units::J, + rpt.LtsVisGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Visible Radiation Heating Rate", prefix), + Constant::Units::W, + rpt.LtsVisGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Convective Heating Energy", prefix), + Constant::Units::J, + rpt.LtsConGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Convective Heating Rate", prefix), + Constant::Units::W, + rpt.LtsConGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Return Air Heating Energy", prefix), + Constant::Units::J, + rpt.LtsRetAirGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Return Air Heating Rate", prefix), + Constant::Units::W, + rpt.LtsRetAirGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Total Heating Energy", prefix), + Constant::Units::J, + rpt.LtsTotGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lights Total Heating Rate", prefix), + Constant::Units::W, + rpt.LtsTotGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + } + + // Register the 12 standard equipment zone/space output variables (Power, Consump, Rad, Con, Lat, Lost, Tot and their rates). + // Used for Electric Equipment, Gas Equipment, Hot Water Equipment, and Steam Equipment. + using ZRV = DataHeatBalance::ZoneReportVars; + static void setupEquipZoneSpaceOutputs(EnergyPlusData &state, + ZRV &rpt, + std::string const &name, + std::string_view prefix, + std::string_view equipLabel, + std::string_view energyLabel, + Real64 ZRV::*power, + Real64 ZRV::*consump, + Real64 ZRV::*radGain, + Real64 ZRV::*conGain, + Real64 ZRV::*latGain, + Real64 ZRV::*lost, + Real64 ZRV::*totGain, + Real64 ZRV::*radGainRate, + Real64 ZRV::*conGainRate, + Real64 ZRV::*latGainRate, + Real64 ZRV::*lostRate, + Real64 ZRV::*totGainRate) + { + SetupOutputVariable(state, + EnergyPlus::format("{} {} {} Rate", prefix, equipLabel, energyLabel), + Constant::Units::W, + rpt.*power, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} {} Energy", prefix, equipLabel, energyLabel), + Constant::Units::J, + rpt.*consump, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Radiant Heating Energy", prefix, equipLabel), + Constant::Units::J, + rpt.*radGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Radiant Heating Rate", prefix, equipLabel), + Constant::Units::W, + rpt.*radGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Convective Heating Energy", prefix, equipLabel), + Constant::Units::J, + rpt.*conGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Convective Heating Rate", prefix, equipLabel), + Constant::Units::W, + rpt.*conGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Latent Gain Energy", prefix, equipLabel), + Constant::Units::J, + rpt.*latGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Latent Gain Rate", prefix, equipLabel), + Constant::Units::W, + rpt.*latGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Lost Heat Energy", prefix, equipLabel), + Constant::Units::J, + rpt.*lost, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Lost Heat Rate", prefix, equipLabel), + Constant::Units::W, + rpt.*lostRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Total Heating Energy", prefix, equipLabel), + Constant::Units::J, + rpt.*totGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Total Heating Rate", prefix, equipLabel), + Constant::Units::W, + rpt.*totGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + } + + // Register the standard per-object output variables for equipment that uses ZoneEquipData. + // Covers Electric Equipment, Gas Equipment, Hot Water Equipment, Steam Equipment, and Baseboard. + // Each call registers: Power rate, Consumption energy (with resource metering), + // then Rad/Con/Lat/Lost/Tot energy+rate pairs. + static void setupEquipObjectOutputs(EnergyPlusData &state, + DataHeatBalance::ZoneEquipData &equip, + std::string_view equipLabel, + std::string_view energyLabel, + Constant::eResource resource) + { + SetupOutputVariable(state, + EnergyPlus::format("{} {} Rate", equipLabel, energyLabel), + Constant::Units::W, + equip.Power, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + equip.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Energy", equipLabel, energyLabel), + Constant::Units::J, + equip.Consumption, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + equip.Name, + resource, + OutputProcessor::Group::Building, + OutputProcessor::EndUseCat::InteriorEquipment, + equip.EndUseSubcategory, + state.dataHeatBal->Zone(equip.ZonePtr).Name, + state.dataHeatBal->Zone(equip.ZonePtr).Multiplier, + state.dataHeatBal->Zone(equip.ZonePtr).ListMultiplier, + state.dataHeatBal->space(equip.spaceIndex).spaceType); + SetupOutputVariable(state, + EnergyPlus::format("{} Radiant Heating Energy", equipLabel), + Constant::Units::J, + equip.RadGainEnergy, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + equip.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} Radiant Heating Rate", equipLabel), + Constant::Units::W, + equip.RadGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + equip.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} Convective Heating Energy", equipLabel), + Constant::Units::J, + equip.ConGainEnergy, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + equip.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} Convective Heating Rate", equipLabel), + Constant::Units::W, + equip.ConGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + equip.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} Latent Gain Energy", equipLabel), + Constant::Units::J, + equip.LatGainEnergy, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + equip.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} Latent Gain Rate", equipLabel), + Constant::Units::W, + equip.LatGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + equip.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lost Heat Energy", equipLabel), + Constant::Units::J, + equip.LostEnergy, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + equip.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} Lost Heat Rate", equipLabel), + Constant::Units::W, + equip.LostRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + equip.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} Total Heating Energy", equipLabel), + Constant::Units::J, + equip.TotGainEnergy, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + equip.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} Total Heating Rate", equipLabel), + Constant::Units::W, + equip.TotGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + equip.Name); + } + + // Dispatch zone and space total output variables for equipment types that use setupEquipZoneSpaceOutputs, + // then reset the addZoneOutputs/addSpaceOutputs flags. Used for Electric, Gas, Hot Water, and Steam equipment. + static void dispatchEquipZoneSpaceOutputs(EnergyPlusData &state, + Array1D_bool &addZoneOutputs, + Array1D_bool &addSpaceOutputs, + std::string_view equipLabel, + std::string_view energyLabel, + Real64 ZRV::*power, + Real64 ZRV::*consump, + Real64 ZRV::*radGain, + Real64 ZRV::*conGain, + Real64 ZRV::*latGain, + Real64 ZRV::*lost, + Real64 ZRV::*totGain, + Real64 ZRV::*radGainRate, + Real64 ZRV::*conGainRate, + Real64 ZRV::*latGainRate, + Real64 ZRV::*lostRate, + Real64 ZRV::*totGainRate) { for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) { - // Overall Zone Variables - SetupOutputVariable(state, - "Zone Total Internal Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).TotRadiantGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Total Internal Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).TotRadiantGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Total Internal Visible Radiation Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).TotVisHeatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Total Internal Visible Radiation Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).TotVisHeatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Total Internal Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).TotConvectiveGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Total Internal Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).TotConvectiveGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Total Internal Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).TotLatentGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); + if (addZoneOutputs(zoneNum)) { + setupEquipZoneSpaceOutputs(state, + state.dataHeatBal->ZoneRpt(zoneNum), + state.dataHeatBal->Zone(zoneNum).Name, + "Zone", + equipLabel, + energyLabel, + power, + consump, + radGain, + conGain, + latGain, + lost, + totGain, + radGainRate, + conGainRate, + latGainRate, + lostRate, + totGainRate); + } + addZoneOutputs(zoneNum) = false; + } + for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) { + if (addSpaceOutputs(spaceNum)) { + setupEquipZoneSpaceOutputs(state, + state.dataHeatBal->spaceRpt(spaceNum), + state.dataHeatBal->space(spaceNum).Name, + "Space", + equipLabel, + energyLabel, + power, + consump, + radGain, + conGain, + latGain, + lost, + totGain, + radGainRate, + conGainRate, + latGainRate, + lostRate, + totGainRate); + } + addSpaceOutputs(spaceNum) = false; + } + } + + // Register the 8 Baseboard zone/space total output variables for a single zone or space. + static void + setupBaseboardZoneSpaceOutputs(EnergyPlusData &state, DataHeatBalance::ZoneReportVars &rpt, std::string const &name, std::string_view prefix) + { + SetupOutputVariable(state, + EnergyPlus::format("{} Baseboard Electricity Rate", prefix), + Constant::Units::W, + rpt.BaseHeatPower, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Baseboard Electricity Energy", prefix), + Constant::Units::J, + rpt.BaseHeatElecCons, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Baseboard Radiant Heating Energy", prefix), + Constant::Units::J, + rpt.BaseHeatRadGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Baseboard Radiant Heating Rate", prefix), + Constant::Units::W, + rpt.BaseHeatRadGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Baseboard Convective Heating Energy", prefix), + Constant::Units::J, + rpt.BaseHeatConGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Baseboard Convective Heating Rate", prefix), + Constant::Units::W, + rpt.BaseHeatConGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Baseboard Total Heating Energy", prefix), + Constant::Units::J, + rpt.BaseHeatTotGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Baseboard Total Heating Rate", prefix), + Constant::Units::W, + rpt.BaseHeatTotGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + } + + // Register the Other Equipment zone/space total output variables for a single zone or space. + static void setupOtherEquipZoneSpaceOutputs(EnergyPlusData &state, + DataHeatBalance::ZoneReportVars &rpt, + std::string const &name, + std::string_view prefix, + std::vector const &fuelTypes) + { + for (size_t i = 0; i < fuelTypes.size(); ++i) { + Constant::eFuel fuelType = fuelTypes[i]; + if (fuelType == Constant::eFuel::Invalid || fuelType == Constant::eFuel::None) { + continue; + } + std::string_view fuelName = Constant::eFuelNames[(int)fuelType]; SetupOutputVariable(state, - "Zone Total Internal Latent Gain Rate", + EnergyPlus::format("{} Other Equipment {} Rate", prefix, fuelName), Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).TotLatentGainRate, + rpt.OtherPower[(int)fuelType], OutputProcessor::TimeStepType::Zone, OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); + name); SetupOutputVariable(state, - "Zone Total Internal Total Heating Energy", + EnergyPlus::format("{} Other Equipment {} Energy", prefix, fuelName), Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).TotTotalHeatGain, + rpt.OtherConsump[(int)fuelType], OutputProcessor::TimeStepType::Zone, OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Total Internal Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).TotTotalHeatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); + name); + } + SetupOutputVariable(state, + EnergyPlus::format("{} Other Equipment Radiant Heating Energy", prefix), + Constant::Units::J, + rpt.OtherRadGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Other Equipment Radiant Heating Rate", prefix), + Constant::Units::W, + rpt.OtherRadGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Other Equipment Convective Heating Energy", prefix), + Constant::Units::J, + rpt.OtherConGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Other Equipment Convective Heating Rate", prefix), + Constant::Units::W, + rpt.OtherConGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Other Equipment Latent Gain Energy", prefix), + Constant::Units::J, + rpt.OtherLatGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Other Equipment Latent Gain Rate", prefix), + Constant::Units::W, + rpt.OtherLatGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Other Equipment Lost Heat Energy", prefix), + Constant::Units::J, + rpt.OtherLost, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Other Equipment Lost Heat Rate", prefix), + Constant::Units::W, + rpt.OtherLostRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Other Equipment Total Heating Energy", prefix), + Constant::Units::J, + rpt.OtherTotGain, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Sum, + name); + SetupOutputVariable(state, + EnergyPlus::format("{} Other Equipment Total Heating Rate", prefix), + Constant::Units::W, + rpt.OtherTotGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + name); + } + + void setupIHGOutputs(EnergyPlusData &state) + { + for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) { + setupOverallOutputs(state, state.dataHeatBal->ZoneRpt(zoneNum), state.dataHeatBal->Zone(zoneNum).Name, "Zone"); } for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) { - // Overall Space Variables - SetupOutputVariable(state, - "Space Total Internal Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).TotRadiantGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Total Internal Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).TotRadiantGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Total Internal Visible Radiation Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).TotVisHeatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Total Internal Visible Radiation Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).TotVisHeatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Total Internal Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).TotConvectiveGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Total Internal Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).TotConvectiveGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Total Internal Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).TotLatentGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Total Internal Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).TotLatentGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Total Internal Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).TotTotalHeatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Total Internal Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).TotTotalHeatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); + setupOverallOutputs(state, state.dataHeatBal->spaceRpt(spaceNum), state.dataHeatBal->space(spaceNum).Name, "Space"); } // Add zone and space outputs only where the particular type of equipment is actually present @@ -3828,84 +4083,7 @@ namespace InternalHeatGains { for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) { if (addZoneOutputs(zoneNum)) { - // Zone total report variables - SetupOutputVariable(state, - "Zone People Occupant Count", - Constant::Units::None, - state.dataHeatBal->ZoneRpt(zoneNum).PeopleNumOcc, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone People Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).PeopleRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone People Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).PeopleRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone People Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).PeopleConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone People Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).PeopleConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone People Sensible Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).PeopleSenGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone People Sensible Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).PeopleSenGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone People Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).PeopleLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone People Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).PeopleLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone People Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).PeopleTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone People Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).PeopleTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); + setupPeopleZoneSpaceOutputs(state, state.dataHeatBal->ZoneRpt(zoneNum), state.dataHeatBal->Zone(zoneNum).Name, "Zone"); } // Reset zone output flag addZoneOutputs(zoneNum) = false; @@ -3914,83 +4092,7 @@ namespace InternalHeatGains { // Space total report variables for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) { if (addSpaceOutputs(spaceNum)) { - SetupOutputVariable(state, - "Space People Occupant Count", - Constant::Units::None, - state.dataHeatBal->spaceRpt(spaceNum).PeopleNumOcc, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space People Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).PeopleRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space People Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).PeopleRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space People Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).PeopleConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space People Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).PeopleConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space People Sensible Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).PeopleSenGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space People Sensible Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).PeopleSenGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space People Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).PeopleLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space People Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).PeopleLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space People Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).PeopleTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space People Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).PeopleTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); + setupPeopleZoneSpaceOutputs(state, state.dataHeatBal->spaceRpt(spaceNum), state.dataHeatBal->space(spaceNum).Name, "Space"); } // Reset space output flag addSpaceOutputs(spaceNum) = false; @@ -4100,90 +4202,7 @@ namespace InternalHeatGains { // Zone total report variables for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) { if (addZoneOutputs(zoneNum)) { - SetupOutputVariable(state, - "Zone Lights Electricity Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).LtsPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Lights Electricity Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).LtsElecConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Lights Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).LtsRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Lights Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).LtsRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Lights Visible Radiation Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).LtsVisGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Lights Visible Radiation Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).LtsVisGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Lights Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).LtsConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Lights Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).LtsConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Lights Return Air Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).LtsRetAirGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Lights Return Air Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).LtsRetAirGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Lights Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).LtsTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Lights Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).LtsTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); + setupLightsZoneSpaceOutputs(state, state.dataHeatBal->ZoneRpt(zoneNum), state.dataHeatBal->Zone(zoneNum).Name, "Zone"); } // Reset zone output flag addZoneOutputs(zoneNum) = false; @@ -4192,90 +4211,7 @@ namespace InternalHeatGains { // Space total report variables for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) { if (addSpaceOutputs(spaceNum)) { - SetupOutputVariable(state, - "Space Lights Electricity Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).LtsPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Lights Electricity Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).LtsElecConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Lights Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).LtsRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Lights Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).LtsRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Lights Visible Radiation Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).LtsVisGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Lights Visible Radiation Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).LtsVisGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Lights Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).LtsConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Lights Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).LtsConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Lights Return Air Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).LtsRetAirGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Lights Return Air Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).LtsRetAirGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Lights Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).LtsTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Lights Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).LtsTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); + setupLightsZoneSpaceOutputs(state, state.dataHeatBal->spaceRpt(spaceNum), state.dataHeatBal->space(spaceNum).Name, "Space"); } // Reset space output flag addSpaceOutputs(spaceNum) = false; @@ -4285,1146 +4221,201 @@ namespace InternalHeatGains { addZoneOutputs(state.dataHeatBal->ZoneElectric(elecEqNum).ZonePtr) = true; addSpaceOutputs(state.dataHeatBal->ZoneElectric(elecEqNum).spaceIndex) = true; // Object report variables + setupEquipObjectOutputs( + state, state.dataHeatBal->ZoneElectric(elecEqNum), "Electric Equipment", "Electricity", Constant::eResource::Electricity); + } + + dispatchEquipZoneSpaceOutputs(state, + addZoneOutputs, + addSpaceOutputs, + "Electric Equipment", + "Electricity", + &ZRV::ElecPower, + &ZRV::ElecConsump, + &ZRV::ElecRadGain, + &ZRV::ElecConGain, + &ZRV::ElecLatGain, + &ZRV::ElecLost, + &ZRV::ElecTotGain, + &ZRV::ElecRadGainRate, + &ZRV::ElecConGainRate, + &ZRV::ElecLatGainRate, + &ZRV::ElecLostRate, + &ZRV::ElecTotGainRate); + // Object report variables + for (int gasEqNum = 1; gasEqNum <= state.dataHeatBal->TotGasEquip; ++gasEqNum) { + // Set flags for zone and space total report variables + addZoneOutputs(state.dataHeatBal->ZoneGas(gasEqNum).ZonePtr) = true; + addSpaceOutputs(state.dataHeatBal->ZoneGas(gasEqNum).spaceIndex) = true; + // Gas Equipment uses a different output variable order than other equipment types: + // Rate, Energy, then all Energy variables grouped together, then all Rate variables. SetupOutputVariable(state, - "Electric Equipment Electricity Rate", + "Gas Equipment NaturalGas Rate", Constant::Units::W, - state.dataHeatBal->ZoneElectric(elecEqNum).Power, + state.dataHeatBal->ZoneGas(gasEqNum).Power, OutputProcessor::TimeStepType::Zone, OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneElectric(elecEqNum).Name); + state.dataHeatBal->ZoneGas(gasEqNum).Name); SetupOutputVariable(state, - "Electric Equipment Electricity Energy", + "Gas Equipment NaturalGas Energy", Constant::Units::J, - state.dataHeatBal->ZoneElectric(elecEqNum).Consumption, + state.dataHeatBal->ZoneGas(gasEqNum).Consumption, OutputProcessor::TimeStepType::Zone, OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneElectric(elecEqNum).Name, - Constant::eResource::Electricity, + state.dataHeatBal->ZoneGas(gasEqNum).Name, + Constant::eResource::NaturalGas, OutputProcessor::Group::Building, OutputProcessor::EndUseCat::InteriorEquipment, - state.dataHeatBal->ZoneElectric(elecEqNum).EndUseSubcategory, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneElectric(elecEqNum).ZonePtr).Name, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneElectric(elecEqNum).ZonePtr).Multiplier, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneElectric(elecEqNum).ZonePtr).ListMultiplier, - state.dataHeatBal->space(state.dataHeatBal->ZoneElectric(elecEqNum).spaceIndex).spaceType); + state.dataHeatBal->ZoneGas(gasEqNum).EndUseSubcategory, + state.dataHeatBal->Zone(state.dataHeatBal->ZoneGas(gasEqNum).ZonePtr).Name, + state.dataHeatBal->Zone(state.dataHeatBal->ZoneGas(gasEqNum).ZonePtr).Multiplier, + state.dataHeatBal->Zone(state.dataHeatBal->ZoneGas(gasEqNum).ZonePtr).ListMultiplier, + state.dataHeatBal->space(state.dataHeatBal->ZoneGas(gasEqNum).spaceIndex).spaceType); SetupOutputVariable(state, - "Electric Equipment Radiant Heating Energy", + "Gas Equipment Radiant Heating Energy", Constant::Units::J, - state.dataHeatBal->ZoneElectric(elecEqNum).RadGainEnergy, + state.dataHeatBal->ZoneGas(gasEqNum).RadGainEnergy, OutputProcessor::TimeStepType::Zone, OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneElectric(elecEqNum).Name); - SetupOutputVariable(state, - "Electric Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneElectric(elecEqNum).RadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneElectric(elecEqNum).Name); + state.dataHeatBal->ZoneGas(gasEqNum).Name); SetupOutputVariable(state, - "Electric Equipment Convective Heating Energy", + "Gas Equipment Convective Heating Energy", Constant::Units::J, - state.dataHeatBal->ZoneElectric(elecEqNum).ConGainEnergy, + state.dataHeatBal->ZoneGas(gasEqNum).ConGainEnergy, OutputProcessor::TimeStepType::Zone, OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneElectric(elecEqNum).Name); - SetupOutputVariable(state, - "Electric Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneElectric(elecEqNum).ConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneElectric(elecEqNum).Name); + state.dataHeatBal->ZoneGas(gasEqNum).Name); SetupOutputVariable(state, - "Electric Equipment Latent Gain Energy", + "Gas Equipment Latent Gain Energy", Constant::Units::J, - state.dataHeatBal->ZoneElectric(elecEqNum).LatGainEnergy, + state.dataHeatBal->ZoneGas(gasEqNum).LatGainEnergy, OutputProcessor::TimeStepType::Zone, OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneElectric(elecEqNum).Name); + state.dataHeatBal->ZoneGas(gasEqNum).Name); SetupOutputVariable(state, - "Electric Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->ZoneElectric(elecEqNum).LatGainRate, + "Gas Equipment Lost Heat Energy", + Constant::Units::J, + state.dataHeatBal->ZoneGas(gasEqNum).LostEnergy, OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneElectric(elecEqNum).Name); + OutputProcessor::StoreType::Sum, + state.dataHeatBal->ZoneGas(gasEqNum).Name); SetupOutputVariable(state, - "Electric Equipment Lost Heat Energy", + "Gas Equipment Total Heating Energy", Constant::Units::J, - state.dataHeatBal->ZoneElectric(elecEqNum).LostEnergy, + state.dataHeatBal->ZoneGas(gasEqNum).TotGainEnergy, OutputProcessor::TimeStepType::Zone, OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneElectric(elecEqNum).Name); + state.dataHeatBal->ZoneGas(gasEqNum).Name); SetupOutputVariable(state, - "Electric Equipment Lost Heat Rate", + "Gas Equipment Radiant Heating Rate", Constant::Units::W, - state.dataHeatBal->ZoneElectric(elecEqNum).LostRate, + state.dataHeatBal->ZoneGas(gasEqNum).RadGainRate, OutputProcessor::TimeStepType::Zone, OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneElectric(elecEqNum).Name); - SetupOutputVariable(state, - "Electric Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneElectric(elecEqNum).TotGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneElectric(elecEqNum).Name); + state.dataHeatBal->ZoneGas(gasEqNum).Name); SetupOutputVariable(state, - "Electric Equipment Total Heating Rate", + "Gas Equipment Convective Heating Rate", Constant::Units::W, - state.dataHeatBal->ZoneElectric(elecEqNum).TotGainRate, + state.dataHeatBal->ZoneGas(gasEqNum).ConGainRate, OutputProcessor::TimeStepType::Zone, OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneElectric(elecEqNum).Name); - } - - // Zone total report variables - for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) { - if (addZoneOutputs(zoneNum)) { - SetupOutputVariable(state, - "Zone Electric Equipment Electricity Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).ElecPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Electric Equipment Electricity Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).ElecConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - - SetupOutputVariable(state, - "Zone Electric Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).ElecRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Electric Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).ElecRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Electric Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).ElecConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Electric Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).ElecConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Electric Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).ElecLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Electric Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).ElecLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Electric Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).ElecLost, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Electric Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).ElecLostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Electric Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).ElecTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Electric Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).ElecTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - } - // Reset zone output flag - addZoneOutputs(zoneNum) = false; - } - - // space total report variables - for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) { - if (addSpaceOutputs(spaceNum)) { - SetupOutputVariable(state, - "Space Electric Equipment Electricity Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).ElecPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Electric Equipment Electricity Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).ElecConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - - SetupOutputVariable(state, - "Space Electric Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).ElecRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Electric Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).ElecRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Electric Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).ElecConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Electric Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).ElecConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Electric Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).ElecLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Electric Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).ElecLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Electric Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).ElecLost, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Electric Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).ElecLostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Electric Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).ElecTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Electric Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).ElecTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - } - // Reset space output flag - addSpaceOutputs(spaceNum) = false; - } - // Object report variables - for (int gasEqNum = 1; gasEqNum <= state.dataHeatBal->TotGasEquip; ++gasEqNum) { - // Set flags for zone and space total report variables - addZoneOutputs(state.dataHeatBal->ZoneGas(gasEqNum).ZonePtr) = true; - addSpaceOutputs(state.dataHeatBal->ZoneGas(gasEqNum).spaceIndex) = true; - SetupOutputVariable(state, - "Gas Equipment NaturalGas Rate", - Constant::Units::W, - state.dataHeatBal->ZoneGas(gasEqNum).Power, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneGas(gasEqNum).Name); - SetupOutputVariable(state, - "Gas Equipment NaturalGas Energy", - Constant::Units::J, - state.dataHeatBal->ZoneGas(gasEqNum).Consumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneGas(gasEqNum).Name, - Constant::eResource::NaturalGas, - OutputProcessor::Group::Building, - OutputProcessor::EndUseCat::InteriorEquipment, - state.dataHeatBal->ZoneGas(gasEqNum).EndUseSubcategory, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneGas(gasEqNum).ZonePtr).Name, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneGas(gasEqNum).ZonePtr).Multiplier, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneGas(gasEqNum).ZonePtr).ListMultiplier, - state.dataHeatBal->space(state.dataHeatBal->ZoneGas(gasEqNum).spaceIndex).spaceType); - - SetupOutputVariable(state, - "Gas Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneGas(gasEqNum).RadGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneGas(gasEqNum).Name); - SetupOutputVariable(state, - "Gas Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneGas(gasEqNum).ConGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneGas(gasEqNum).Name); - SetupOutputVariable(state, - "Gas Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZoneGas(gasEqNum).LatGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneGas(gasEqNum).Name); - SetupOutputVariable(state, - "Gas Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->ZoneGas(gasEqNum).LostEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneGas(gasEqNum).Name); - SetupOutputVariable(state, - "Gas Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneGas(gasEqNum).TotGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneGas(gasEqNum).Name); - SetupOutputVariable(state, - "Gas Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneGas(gasEqNum).RadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneGas(gasEqNum).Name); - SetupOutputVariable(state, - "Gas Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneGas(gasEqNum).ConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneGas(gasEqNum).Name); - SetupOutputVariable(state, - "Gas Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->ZoneGas(gasEqNum).LatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneGas(gasEqNum).Name); - SetupOutputVariable(state, - "Gas Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->ZoneGas(gasEqNum).LostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneGas(gasEqNum).Name); - SetupOutputVariable(state, - "Gas Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneGas(gasEqNum).TotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneGas(gasEqNum).Name); - } - - // Zone total report variables - for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) { - if (addZoneOutputs(zoneNum)) { - - SetupOutputVariable(state, - "Zone Gas Equipment NaturalGas Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).GasPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Gas Equipment NaturalGas Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).GasConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - - SetupOutputVariable(state, - "Zone Gas Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).GasRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Gas Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).GasRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Gas Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).GasConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Gas Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).GasConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Gas Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).GasLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Gas Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).GasLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Gas Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).GasLost, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Gas Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).GasLostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Gas Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).GasTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Gas Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).GasTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - } - // Reset zone output flag - addZoneOutputs(zoneNum) = false; - } - - // Space total report variables - for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) { - if (addSpaceOutputs(spaceNum)) { - - SetupOutputVariable(state, - "Space Gas Equipment NaturalGas Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).GasPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Gas Equipment NaturalGas Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).GasConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - - SetupOutputVariable(state, - "Space Gas Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).GasRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Gas Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).GasRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Gas Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).GasConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Gas Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).GasConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Gas Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).GasLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Gas Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).GasLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Gas Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).GasLost, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Gas Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).GasLostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Gas Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).GasTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Gas Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).GasTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - } - // Reset space output flag - addSpaceOutputs(spaceNum) = false; - } - - // Object report variables - for (int hwEqNum = 1; hwEqNum <= state.dataHeatBal->TotHWEquip; ++hwEqNum) { - // Set flags for zone and space total report variables - addZoneOutputs(state.dataHeatBal->ZoneHWEq(hwEqNum).ZonePtr) = true; - addSpaceOutputs(state.dataHeatBal->ZoneHWEq(hwEqNum).spaceIndex) = true; - SetupOutputVariable(state, - "Hot Water Equipment District Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneHWEq(hwEqNum).Power, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name); - SetupOutputVariable(state, - "Hot Water Equipment District Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneHWEq(hwEqNum).Consumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name, - Constant::eResource::DistrictHeatingWater, - OutputProcessor::Group::Building, - OutputProcessor::EndUseCat::InteriorEquipment, - state.dataHeatBal->ZoneHWEq(hwEqNum).EndUseSubcategory, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneHWEq(hwEqNum).ZonePtr).Name, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneHWEq(hwEqNum).ZonePtr).Multiplier, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneHWEq(hwEqNum).ZonePtr).ListMultiplier, - state.dataHeatBal->space(state.dataHeatBal->ZoneHWEq(hwEqNum).spaceIndex).spaceType); - - SetupOutputVariable(state, - "Hot Water Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneHWEq(hwEqNum).RadGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name); - SetupOutputVariable(state, - "Hot Water Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneHWEq(hwEqNum).RadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name); - SetupOutputVariable(state, - "Hot Water Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneHWEq(hwEqNum).ConGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name); - SetupOutputVariable(state, - "Hot Water Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneHWEq(hwEqNum).ConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name); - SetupOutputVariable(state, - "Hot Water Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZoneHWEq(hwEqNum).LatGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name); - SetupOutputVariable(state, - "Hot Water Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->ZoneHWEq(hwEqNum).LatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name); - SetupOutputVariable(state, - "Hot Water Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->ZoneHWEq(hwEqNum).LostEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name); - SetupOutputVariable(state, - "Hot Water Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->ZoneHWEq(hwEqNum).LostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name); - SetupOutputVariable(state, - "Hot Water Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneHWEq(hwEqNum).TotGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name); - SetupOutputVariable(state, - "Hot Water Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneHWEq(hwEqNum).TotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneHWEq(hwEqNum).Name); - } - - // Zone total report variables - for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) { - if (addZoneOutputs(zoneNum)) { - SetupOutputVariable(state, - "Zone Hot Water Equipment District Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).HWPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Hot Water Equipment District Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).HWConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - - SetupOutputVariable(state, - "Zone Hot Water Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).HWRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Hot Water Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).HWRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Hot Water Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).HWConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Hot Water Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).HWConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Hot Water Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).HWLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Hot Water Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).HWLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Hot Water Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).HWLost, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Hot Water Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).HWLostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Hot Water Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).HWTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Hot Water Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).HWTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - } - // Reset zone output flag - addZoneOutputs(zoneNum) = false; - } - - // Space total report variables - for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) { - if (addSpaceOutputs(spaceNum)) { - SetupOutputVariable(state, - "Space Hot Water Equipment District Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).HWPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Hot Water Equipment District Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).HWConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - - SetupOutputVariable(state, - "Space Hot Water Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).HWRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Hot Water Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).HWRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Hot Water Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).HWConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Hot Water Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).HWConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Hot Water Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).HWLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Hot Water Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).HWLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Hot Water Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).HWLost, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Hot Water Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).HWLostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Hot Water Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).HWTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Hot Water Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).HWTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - } - // Reset space output flag - addSpaceOutputs(spaceNum) = false; - } - - // Object report variables - for (int stmEqNum = 1; stmEqNum <= state.dataHeatBal->TotStmEquip; ++stmEqNum) { - // Set flags for zone and space total report variables - addZoneOutputs(state.dataHeatBal->ZoneSteamEq(stmEqNum).ZonePtr) = true; - addSpaceOutputs(state.dataHeatBal->ZoneSteamEq(stmEqNum).spaceIndex) = true; - SetupOutputVariable(state, - "Steam Equipment District Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Power, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name); - SetupOutputVariable(state, - "Steam Equipment District Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Consumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name, - Constant::eResource::DistrictHeatingSteam, - OutputProcessor::Group::Building, - OutputProcessor::EndUseCat::InteriorEquipment, - state.dataHeatBal->ZoneSteamEq(stmEqNum).EndUseSubcategory, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneSteamEq(stmEqNum).ZonePtr).Name, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneSteamEq(stmEqNum).ZonePtr).Multiplier, - state.dataHeatBal->Zone(state.dataHeatBal->ZoneSteamEq(stmEqNum).ZonePtr).ListMultiplier, - state.dataHeatBal->space(state.dataHeatBal->ZoneSteamEq(stmEqNum).spaceIndex).spaceType); - - SetupOutputVariable(state, - "Steam Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneSteamEq(stmEqNum).RadGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name); - SetupOutputVariable(state, - "Steam Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneSteamEq(stmEqNum).RadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name); - SetupOutputVariable(state, - "Steam Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneSteamEq(stmEqNum).ConGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name); - SetupOutputVariable(state, - "Steam Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneSteamEq(stmEqNum).ConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name); - SetupOutputVariable(state, - "Steam Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZoneSteamEq(stmEqNum).LatGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name); - SetupOutputVariable(state, - "Steam Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->ZoneSteamEq(stmEqNum).LatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name); - SetupOutputVariable(state, - "Steam Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->ZoneSteamEq(stmEqNum).LostEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name); - SetupOutputVariable(state, - "Steam Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->ZoneSteamEq(stmEqNum).LostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name); - SetupOutputVariable(state, - "Steam Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneSteamEq(stmEqNum).TotGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name); - SetupOutputVariable(state, - "Steam Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneSteamEq(stmEqNum).TotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->ZoneSteamEq(stmEqNum).Name); - } - - // Zone total report variables - for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) { - if (addZoneOutputs(zoneNum)) { - SetupOutputVariable(state, - "Zone Steam Equipment District Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).SteamPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Steam Equipment District Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).SteamConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - - SetupOutputVariable(state, - "Zone Steam Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).SteamRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Steam Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).SteamRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Steam Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).SteamConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Steam Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).SteamConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Steam Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).SteamLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Steam Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).SteamLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Steam Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).SteamLost, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Steam Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).SteamLostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Steam Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).SteamTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Steam Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).SteamTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - } - // Reset zone output flag - addZoneOutputs(zoneNum) = false; - } - - // Space total report variables - for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) { - if (addSpaceOutputs(spaceNum)) { - SetupOutputVariable(state, - "Space Steam Equipment District Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).SteamPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Steam Equipment District Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).SteamConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - - SetupOutputVariable(state, - "Space Steam Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).SteamRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Steam Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).SteamRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Steam Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).SteamConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Steam Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).SteamConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Steam Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).SteamLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Steam Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).SteamLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Steam Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).SteamLost, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Steam Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).SteamLostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Steam Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).SteamTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Steam Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).SteamTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - } - // Reset space output flag - addSpaceOutputs(spaceNum) = false; + state.dataHeatBal->ZoneGas(gasEqNum).Name); + SetupOutputVariable(state, + "Gas Equipment Latent Gain Rate", + Constant::Units::W, + state.dataHeatBal->ZoneGas(gasEqNum).LatGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + state.dataHeatBal->ZoneGas(gasEqNum).Name); + SetupOutputVariable(state, + "Gas Equipment Lost Heat Rate", + Constant::Units::W, + state.dataHeatBal->ZoneGas(gasEqNum).LostRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + state.dataHeatBal->ZoneGas(gasEqNum).Name); + SetupOutputVariable(state, + "Gas Equipment Total Heating Rate", + Constant::Units::W, + state.dataHeatBal->ZoneGas(gasEqNum).TotGainRate, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + state.dataHeatBal->ZoneGas(gasEqNum).Name); + } + + dispatchEquipZoneSpaceOutputs(state, + addZoneOutputs, + addSpaceOutputs, + "Gas Equipment", + "NaturalGas", + &ZRV::GasPower, + &ZRV::GasConsump, + &ZRV::GasRadGain, + &ZRV::GasConGain, + &ZRV::GasLatGain, + &ZRV::GasLost, + &ZRV::GasTotGain, + &ZRV::GasRadGainRate, + &ZRV::GasConGainRate, + &ZRV::GasLatGainRate, + &ZRV::GasLostRate, + &ZRV::GasTotGainRate); + + // Object report variables + for (int hwEqNum = 1; hwEqNum <= state.dataHeatBal->TotHWEquip; ++hwEqNum) { + // Set flags for zone and space total report variables + addZoneOutputs(state.dataHeatBal->ZoneHWEq(hwEqNum).ZonePtr) = true; + addSpaceOutputs(state.dataHeatBal->ZoneHWEq(hwEqNum).spaceIndex) = true; + setupEquipObjectOutputs( + state, state.dataHeatBal->ZoneHWEq(hwEqNum), "Hot Water Equipment", "District Heating", Constant::eResource::DistrictHeatingWater); + } + + dispatchEquipZoneSpaceOutputs(state, + addZoneOutputs, + addSpaceOutputs, + "Hot Water Equipment", + "District Heating", + &ZRV::HWPower, + &ZRV::HWConsump, + &ZRV::HWRadGain, + &ZRV::HWConGain, + &ZRV::HWLatGain, + &ZRV::HWLost, + &ZRV::HWTotGain, + &ZRV::HWRadGainRate, + &ZRV::HWConGainRate, + &ZRV::HWLatGainRate, + &ZRV::HWLostRate, + &ZRV::HWTotGainRate); + + // Object report variables + for (int stmEqNum = 1; stmEqNum <= state.dataHeatBal->TotStmEquip; ++stmEqNum) { + // Set flags for zone and space total report variables + addZoneOutputs(state.dataHeatBal->ZoneSteamEq(stmEqNum).ZonePtr) = true; + addSpaceOutputs(state.dataHeatBal->ZoneSteamEq(stmEqNum).spaceIndex) = true; + setupEquipObjectOutputs( + state, state.dataHeatBal->ZoneSteamEq(stmEqNum), "Steam Equipment", "District Heating", Constant::eResource::DistrictHeatingSteam); } + dispatchEquipZoneSpaceOutputs(state, + addZoneOutputs, + addSpaceOutputs, + "Steam Equipment", + "District Heating", + &ZRV::SteamPower, + &ZRV::SteamConsump, + &ZRV::SteamRadGain, + &ZRV::SteamConGain, + &ZRV::SteamLatGain, + &ZRV::SteamLost, + &ZRV::SteamTotGain, + &ZRV::SteamRadGainRate, + &ZRV::SteamConGainRate, + &ZRV::SteamLatGainRate, + &ZRV::SteamLostRate, + &ZRV::SteamTotGainRate); + // Object report variables for (int othEqNum = 1; othEqNum <= state.dataHeatBal->TotOthEquip; ++othEqNum) { // Set flags for zone and space total report variables @@ -5532,202 +4523,24 @@ namespace InternalHeatGains { // Zone total report variables for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) { if (addZoneOutputs(zoneNum)) { - for (size_t i = 0; i < state.dataHeatBal->Zone(zoneNum).otherEquipFuelTypeNums.size(); ++i) { - Constant::eFuel fuelType = state.dataHeatBal->Zone(zoneNum).otherEquipFuelTypeNums[i]; - if (fuelType == Constant::eFuel::Invalid || fuelType == Constant::eFuel::None) { - continue; - } - - std::string_view fuelName = Constant::eFuelNames[(int)state.dataHeatBal->Zone(zoneNum).otherEquipFuelTypeNums[i]]; - - SetupOutputVariable(state, - EnergyPlus::format("Zone Other Equipment {} Rate", fuelName), - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).OtherPower[(int)fuelType], - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - EnergyPlus::format("Zone Other Equipment {} Energy", fuelName), - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).OtherConsump[(int)fuelType], - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - } - - SetupOutputVariable(state, - "Zone Other Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).OtherRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Other Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).OtherRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Other Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).OtherConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Other Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).OtherConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Other Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).OtherLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Other Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).OtherLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Other Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).OtherLost, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Other Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).OtherLostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Other Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).OtherTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Other Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).OtherTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); + setupOtherEquipZoneSpaceOutputs(state, + state.dataHeatBal->ZoneRpt(zoneNum), + state.dataHeatBal->Zone(zoneNum).Name, + "Zone", + state.dataHeatBal->Zone(zoneNum).otherEquipFuelTypeNums); } - // Reset zone output flag addZoneOutputs(zoneNum) = false; } // Space total report variables for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) { if (addSpaceOutputs(spaceNum)) { - for (size_t i = 0; i < state.dataHeatBal->space(spaceNum).otherEquipFuelTypeNums.size(); ++i) { - Constant::eFuel fuelType = state.dataHeatBal->space(spaceNum).otherEquipFuelTypeNums[i]; - if (fuelType == Constant::eFuel::Invalid || fuelType == Constant::eFuel::None) { - continue; - } - - SetupOutputVariable(state, - EnergyPlus::format("Space Other Equipment {} Rate", Constant::eFuelNames[(int)fuelType]), - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).OtherPower[(int)fuelType], - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - EnergyPlus::format("Space Other Equipment {} Energy", Constant::eFuelNames[(int)fuelType]), - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).OtherConsump[(int)fuelType], - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - } - - SetupOutputVariable(state, - "Space Other Equipment Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).OtherRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Other Equipment Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).OtherRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Other Equipment Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).OtherConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Other Equipment Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).OtherConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Other Equipment Latent Gain Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).OtherLatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Other Equipment Latent Gain Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).OtherLatGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Other Equipment Lost Heat Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).OtherLost, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Other Equipment Lost Heat Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).OtherLostRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Other Equipment Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).OtherTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Other Equipment Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).OtherTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); + setupOtherEquipZoneSpaceOutputs(state, + state.dataHeatBal->spaceRpt(spaceNum), + state.dataHeatBal->space(spaceNum).Name, + "Space", + state.dataHeatBal->space(spaceNum).otherEquipFuelTypeNums); } - // Reset space output flag addSpaceOutputs(spaceNum) = false; } // Object report variables @@ -6306,130 +5119,16 @@ namespace InternalHeatGains { // Zone total report variables for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) { if (addZoneOutputs(zoneNum)) { - SetupOutputVariable(state, - "Zone Baseboard Electricity Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).BaseHeatPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Baseboard Electricity Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).BaseHeatElecCons, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - - SetupOutputVariable(state, - "Zone Baseboard Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).BaseHeatRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Baseboard Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).BaseHeatRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Baseboard Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).BaseHeatConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Baseboard Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).BaseHeatConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Baseboard Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->ZoneRpt(zoneNum).BaseHeatTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->Zone(zoneNum).Name); - SetupOutputVariable(state, - "Zone Baseboard Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->ZoneRpt(zoneNum).BaseHeatTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->Zone(zoneNum).Name); + setupBaseboardZoneSpaceOutputs(state, state.dataHeatBal->ZoneRpt(zoneNum), state.dataHeatBal->Zone(zoneNum).Name, "Zone"); } - // Reset zone output flag addZoneOutputs(zoneNum) = false; } // Space total report variables for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) { if (addSpaceOutputs(spaceNum)) { - SetupOutputVariable(state, - "Space Baseboard Electricity Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).BaseHeatPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Baseboard Electricity Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).BaseHeatElecCons, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - - SetupOutputVariable(state, - "Space Baseboard Radiant Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).BaseHeatRadGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Baseboard Radiant Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).BaseHeatRadGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Baseboard Convective Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).BaseHeatConGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Baseboard Convective Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).BaseHeatConGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Baseboard Total Heating Energy", - Constant::Units::J, - state.dataHeatBal->spaceRpt(spaceNum).BaseHeatTotGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - state.dataHeatBal->space(spaceNum).Name); - SetupOutputVariable(state, - "Space Baseboard Total Heating Rate", - Constant::Units::W, - state.dataHeatBal->spaceRpt(spaceNum).BaseHeatTotGainRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - state.dataHeatBal->space(spaceNum).Name); + setupBaseboardZoneSpaceOutputs(state, state.dataHeatBal->spaceRpt(spaceNum), state.dataHeatBal->space(spaceNum).Name, "Space"); } - // Reset space output flag addSpaceOutputs(spaceNum) = false; } } diff --git a/src/EnergyPlus/LowTempRadiantSystem.cc b/src/EnergyPlus/LowTempRadiantSystem.cc index f7299c47cc4..52deb0725e0 100644 --- a/src/EnergyPlus/LowTempRadiantSystem.cc +++ b/src/EnergyPlus/LowTempRadiantSystem.cc @@ -181,6 +181,209 @@ namespace LowTempRadiantSystem { [[maybe_unused]] constexpr std::array circuitCalcNames = {"OnePerSurface", "CalculateFromCircuitLength"}; constexpr std::array circuitCalcNamesUC = {"ONEPERSURFACE", "CALCULATEFROMCIRCUITLENGTH"}; + // Helper: apply capacity sizing method from a design object to a system instance. + // For DesignCapacity, validates the user-entered numeric; for CapacityPerFloorArea + // and FractionOfAutosized, copies the value from the design object. + static void applyDesignCapacityFromDesignObject(EnergyPlusData &state, + int designCapMethod, + int designCapacityEnum, + int capPerFloorAreaEnum, + int fractionEnum, + Real64 designScaledCapacity, + std::string const ¤tModuleObject, + std::string const &sysName, + std::string_view heatOrCool, + int numericIdx, + int nodeAlpha1Idx, + int nodeAlpha2Idx, + Array1D const &Numbers, + Array1D_bool const &lNumericBlanks, + Array1D_bool const &lAlphaBlanks, + Array1D_string const &cNumericFields, + int &capMethodOut, + Real64 &scaledCapacityOut, + bool &ErrorsFound) + { + using DataSizing::AutoSize; + if (designCapMethod == designCapacityEnum) { + capMethodOut = designCapacityEnum; + if (!lNumericBlanks(numericIdx)) { + scaledCapacityOut = Numbers(numericIdx); + if (scaledCapacityOut < 0.0 && scaledCapacityOut != AutoSize) { + ShowSevereError(state, EnergyPlus::format("{} = {}", currentModuleObject, sysName)); + ShowContinueError(state, EnergyPlus::format("Illegal {} = {:.7T}", cNumericFields(numericIdx), Numbers(numericIdx))); + ErrorsFound = true; + } + } else { + if ((!lAlphaBlanks(nodeAlpha1Idx)) || (!lAlphaBlanks(nodeAlpha2Idx))) { + ShowSevereError(state, EnergyPlus::format("{} = {}", currentModuleObject, sysName)); + ShowContinueError(state, EnergyPlus::format("Input for {} Design Capacity Method = {}DesignCapacity", heatOrCool, heatOrCool)); + ShowContinueError(state, EnergyPlus::format("Blank field not allowed for {}", cNumericFields(numericIdx))); + ErrorsFound = true; + } + } + } else if (designCapMethod == capPerFloorAreaEnum) { + capMethodOut = capPerFloorAreaEnum; + scaledCapacityOut = designScaledCapacity; + } else if (designCapMethod == fractionEnum) { + capMethodOut = fractionEnum; + scaledCapacityOut = designScaledCapacity; + } + } + + // Helper: parse surface list or single surface name for a radiant system. + // Populates the base-class surface arrays (NumOfSurfaces, SurfacePtr, SurfaceName, SurfaceFrac). + // Returns the SurfListNum (>0 if a surface list was found, 0 if single surface). + static int parseSurfaceListOrSingleSurface(EnergyPlusData &state, + RadiantSystemBaseData &sys, + std::string_view routineName, + std::string const ¤tModuleObject, + std::string const &surfAlphaFieldName, + std::string const &surfAlphaValue, + std::string const &objectName, + bool &ErrorsFound) + { + auto &Surface = state.dataSurface->Surface; + int SurfListNum = 0; + if (state.dataSurfLists->NumOfSurfaceLists > 0) { + SurfListNum = Util::FindItemInList(sys.SurfListName, state.dataSurfLists->SurfList); + } + if (SurfListNum > 0) { // Found a valid surface list + sys.NumOfSurfaces = state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces; + sys.SurfacePtr.allocate(sys.NumOfSurfaces); + sys.SurfaceName.allocate(sys.NumOfSurfaces); + sys.SurfaceFrac.allocate(sys.NumOfSurfaces); + for (int SurfNum = 1; SurfNum <= state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces; ++SurfNum) { + sys.SurfacePtr(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfPtr(SurfNum); + sys.SurfaceName(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfName(SurfNum); + sys.SurfaceFrac(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfFlowFrac(SurfNum); + } + } else { // User entered a single surface name rather than a surface list + sys.NumOfSurfaces = 1; + sys.SurfacePtr.allocate(1); + sys.SurfaceName.allocate(1); + sys.SurfaceFrac.allocate(1); + sys.SurfaceName(1) = sys.SurfListName; + sys.SurfacePtr(1) = Util::FindItemInList(sys.SurfaceName(1), Surface); + sys.SurfaceFrac(1) = 1.0; + // Error checking for single surfaces + if (sys.SurfacePtr(1) == 0) { + ShowSevereError(state, EnergyPlus::format("{}Invalid {} = {}", routineName, surfAlphaFieldName, surfAlphaValue)); + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", currentModuleObject, objectName)); + ErrorsFound = true; + } else if (state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(sys.SurfacePtr(1))) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", Invalid Surface", routineName, currentModuleObject, objectName)); + ShowContinueError( + state, + EnergyPlus::format("{}=\"{}\" has been used in another radiant system or ventilated slab.", surfAlphaFieldName, surfAlphaValue)); + ErrorsFound = true; + } + } + return SurfListNum; + } + + // Helper: validate and parse a design capacity sizing method for VariableFlow:Design objects. + // Handles "XDesignCapacity", "CapacityPerFloorArea", and "FractionOfAutosizedXCapacity" patterns. + static void parseDesignCapacitySizingMethod(EnergyPlusData &state, + std::string_view const &methodInput, + std::string const &objectName, + std::string const ¤tModuleObject, + std::string const &alphaFieldName, + std::string_view designCapacityName, + int designCapacityEnum, + std::string_view fractionCapacityName, + int fractionCapacityEnum, + int capPerFloorAreaNumIdx, + int fractionNumIdx, + Array1D const &Numbers, + Array1D_bool const &lNumericBlanks, + Array1D_string const &cNumericFields, + int &capMethodOut, + Real64 &scaledCapacityOut, + bool &ErrorsFound) + { + using DataSizing::AutoSize; + using DataSizing::CapacityPerFloorArea; + + if (Util::SameString(methodInput, designCapacityName)) { + capMethodOut = designCapacityEnum; + } else if (Util::SameString(methodInput, "CapacityPerFloorArea")) { + capMethodOut = CapacityPerFloorArea; + if (!lNumericBlanks(capPerFloorAreaNumIdx)) { + scaledCapacityOut = Numbers(capPerFloorAreaNumIdx); + if (scaledCapacityOut <= 0.0) { + ShowSevereError(state, EnergyPlus::format("{} = {}", currentModuleObject, objectName)); + ShowContinueError(state, EnergyPlus::format("Input for {} = {}", alphaFieldName, methodInput)); + ShowContinueError( + state, EnergyPlus::format("Illegal {} = {:.7T}", cNumericFields(capPerFloorAreaNumIdx), Numbers(capPerFloorAreaNumIdx))); + ErrorsFound = true; + } else if (scaledCapacityOut == AutoSize) { + ShowSevereError(state, EnergyPlus::format("{} = {}", currentModuleObject, objectName)); + ShowContinueError(state, EnergyPlus::format("Input for {} = {}", alphaFieldName, methodInput)); + ShowContinueError(state, EnergyPlus::format("Illegal {} = Autosize", cNumericFields(capPerFloorAreaNumIdx))); + ErrorsFound = true; + } + } else { + ShowSevereError(state, EnergyPlus::format("{} = {}", currentModuleObject, objectName)); + ShowContinueError(state, EnergyPlus::format("Input for {} = {}", alphaFieldName, methodInput)); + ShowContinueError(state, EnergyPlus::format("Blank field not allowed for {}", cNumericFields(capPerFloorAreaNumIdx))); + ErrorsFound = true; + } + } else if (Util::SameString(methodInput, fractionCapacityName)) { + capMethodOut = fractionCapacityEnum; + if (!lNumericBlanks(fractionNumIdx)) { + scaledCapacityOut = Numbers(fractionNumIdx); + if (scaledCapacityOut < 0.0) { + ShowSevereError(state, EnergyPlus::format("{} = {}", currentModuleObject, objectName)); + ShowContinueError(state, EnergyPlus::format("Illegal {} = {:.7T}", cNumericFields(fractionNumIdx), Numbers(fractionNumIdx))); + ErrorsFound = true; + } + } else { + ShowSevereError(state, EnergyPlus::format("{} = {}", currentModuleObject, objectName)); + ShowContinueError(state, EnergyPlus::format("Input for {} = {}", alphaFieldName, methodInput)); + ShowContinueError(state, EnergyPlus::format("Blank field not allowed for {}", cNumericFields(fractionNumIdx))); + ErrorsFound = true; + } + } else { + ShowSevereError(state, EnergyPlus::format("{} = {}", currentModuleObject, objectName)); + ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", alphaFieldName, methodInput)); + ErrorsFound = true; + } + } + + // Helper: check that no surface is assigned to more than one radiant system. + // Marks each surface (and its interzone partner) in AssignedAsRadiantSurface. + static void checkRadiantSurfaceAssignment( + EnergyPlusData &state, Array1D_bool &AssignedAsRadiantSurface, int numSurfaces, const Array1D_int &SurfacePtr, bool &ErrorsFound) + { + auto &Surface = state.dataSurface->Surface; + for (int SurfNum = 1; SurfNum <= numSurfaces; ++SurfNum) { + int CheckSurfNum = SurfacePtr(SurfNum); + if (CheckSurfNum == 0) { + continue; + } + if (AssignedAsRadiantSurface(CheckSurfNum)) { + ShowSevereError( + state, + EnergyPlus::format("Surface {} is referenced by more than one radiant system--this is not allowed", Surface(CheckSurfNum).Name)); + ErrorsFound = true; + } else { + AssignedAsRadiantSurface(CheckSurfNum) = true; + } + // Also check the other side of interzone partitions + if ((Surface(CheckSurfNum).ExtBoundCond > 0) && (Surface(CheckSurfNum).ExtBoundCond != CheckSurfNum)) { + if (AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond)) { + ShowSevereError(state, + EnergyPlus::format("Interzone surface {} is referenced by more than one radiant system--this is not allowed", + Surface(Surface(CheckSurfNum).ExtBoundCond).Name)); + ErrorsFound = true; + } else { + AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond) = true; + } + } + } + } + void SimLowTempRadiantSystem(EnergyPlusData &state, std::string_view CompName, // name of the low temperature radiant system bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep @@ -318,7 +521,6 @@ namespace LowTempRadiantSystem { Array1D_string cAlphaFields; // Alpha field names Array1D_string cNumericFields; // Numeric field names Array1D_bool AssignedAsRadiantSurface; // Set to true when a surface is part of a radiant system - int CheckSurfNum; // Surface number to check to see if it has already been used by a radiant system bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine int IOStatus; // Used in GetObjectItem int Item; // Item to be "gotten" @@ -335,7 +537,6 @@ namespace LowTempRadiantSystem { Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE. auto &Zone = state.dataHeatBal->Zone; - auto &Surface = state.dataSurface->Surface; Array1D_string VarFlowRadDesignNames; Array1D_string CFlowRadDesignNames; @@ -497,51 +698,23 @@ namespace LowTempRadiantSystem { // Determine Low Temp Radiant heating design capacity sizing method thisRadSysDesign.DesignHeatingCapMethodInput = Alphas(5); - if (Util::SameString(thisRadSysDesign.DesignHeatingCapMethodInput, "HeatingDesignCapacity")) { - thisRadSysDesign.DesignHeatingCapMethod = HeatingDesignCapacity; - } else if (Util::SameString(thisRadSysDesign.DesignHeatingCapMethodInput, "CapacityPerFloorArea")) { - thisRadSysDesign.DesignHeatingCapMethod = CapacityPerFloorArea; - if (!lNumericBlanks(4)) { - thisRadSysDesign.DesignScaledHeatingCapacity = Numbers(4); - if (thisRadSysDesign.DesignScaledHeatingCapacity <= 0.0) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName)); - ShowContinueError(state, - EnergyPlus::format("Input for {} = {}", cAlphaFields(5), thisRadSysDesign.DesignHeatingCapMethodInput)); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {:.7T}", cNumericFields(4), Numbers(4))); - ErrorsFound = true; - } else if (thisRadSysDesign.DesignScaledHeatingCapacity == AutoSize) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName)); - ShowContinueError(state, - EnergyPlus::format("Input for {} = {}", cAlphaFields(5), thisRadSysDesign.DesignHeatingCapMethodInput)); - ShowContinueError(state, EnergyPlus::format("Illegal {} = Autosize", cNumericFields(4))); - ErrorsFound = true; - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.Name)); - ShowContinueError(state, EnergyPlus::format("Input for {} = {}", cAlphaFields(5), thisRadSysDesign.DesignHeatingCapMethodInput)); - ShowContinueError(state, EnergyPlus::format("Blank field not allowed for {}", cNumericFields(4))); - ErrorsFound = true; - } - } else if (Util::SameString(thisRadSysDesign.DesignHeatingCapMethodInput, "FractionOfAutosizedHeatingCapacity")) { - thisRadSysDesign.DesignHeatingCapMethod = FractionOfAutosizedHeatingCapacity; - if (!lNumericBlanks(5)) { - thisRadSysDesign.DesignScaledHeatingCapacity = Numbers(5); - if (thisRadSysDesign.DesignScaledHeatingCapacity < 0.0) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName)); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {:.7T}", cNumericFields(5), Numbers(5))); - ErrorsFound = true; - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName)); - ShowContinueError(state, EnergyPlus::format("Input for {} = {}", cAlphaFields(5), thisRadSysDesign.DesignHeatingCapMethodInput)); - ShowContinueError(state, EnergyPlus::format("Blank field not allowed for {}", cNumericFields(5))); - ErrorsFound = true; - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName)); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(5), thisRadSysDesign.DesignHeatingCapMethodInput)); - ErrorsFound = true; - } + parseDesignCapacitySizingMethod(state, + thisRadSysDesign.DesignHeatingCapMethodInput, + thisRadSysDesign.designName, + CurrentModuleObject, + cAlphaFields(5), + "HeatingDesignCapacity", + HeatingDesignCapacity, + "FractionOfAutosizedHeatingCapacity", + FractionOfAutosizedHeatingCapacity, + 4, // capPerFloorArea numeric index + 5, // fraction numeric index + Numbers, + lNumericBlanks, + cNumericFields, + thisRadSysDesign.DesignHeatingCapMethod, + thisRadSysDesign.DesignScaledHeatingCapacity, + ErrorsFound); thisRadSysDesign.HotThrottlRange = Numbers(6); @@ -553,52 +726,23 @@ namespace LowTempRadiantSystem { // Determine Low Temp Radiant cooling design capacity sizing method thisRadSysDesign.DesignCoolingCapMethodInput = Alphas(7); - if (Util::SameString(thisRadSysDesign.DesignCoolingCapMethodInput, "CoolingDesignCapacity")) { - thisRadSysDesign.DesignCoolingCapMethod = CoolingDesignCapacity; - } else if (Util::SameString(thisRadSysDesign.DesignCoolingCapMethodInput, "CapacityPerFloorArea")) { - thisRadSysDesign.DesignCoolingCapMethod = CapacityPerFloorArea; - if (!lNumericBlanks(7)) { - thisRadSysDesign.DesignScaledCoolingCapacity = Numbers(7); - if (thisRadSysDesign.DesignScaledCoolingCapacity <= 0.0) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName)); - ShowContinueError(state, - EnergyPlus::format("Input for {} = {}", cAlphaFields(7), thisRadSysDesign.DesignCoolingCapMethodInput)); - ShowContinueError(state, - EnergyPlus::format("Illegal {} = {:.7T}", cNumericFields(7), thisRadSysDesign.DesignScaledCoolingCapacity)); - ErrorsFound = true; - } else if (thisRadSysDesign.DesignScaledCoolingCapacity == AutoSize) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName)); - ShowContinueError(state, - EnergyPlus::format("Input for {} = {}", cAlphaFields(7), thisRadSysDesign.DesignCoolingCapMethodInput)); - ShowContinueError(state, EnergyPlus::format("Illegal {} = Autosize", cNumericFields(7))); - ErrorsFound = true; - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName)); - ShowContinueError(state, EnergyPlus::format("Input for {} = {}", cAlphaFields(7), thisRadSysDesign.DesignCoolingCapMethodInput)); - ShowContinueError(state, EnergyPlus::format("Blank field not allowed for {}", cNumericFields(7))); - ErrorsFound = true; - } - } else if (Util::SameString(thisRadSysDesign.DesignCoolingCapMethodInput, "FractionOfAutosizedCoolingCapacity")) { - thisRadSysDesign.DesignCoolingCapMethod = FractionOfAutosizedCoolingCapacity; - if (!lNumericBlanks(8)) { - thisRadSysDesign.DesignScaledCoolingCapacity = Numbers(8); - if (thisRadSysDesign.DesignScaledCoolingCapacity < 0.0) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName)); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {:.7T}", cNumericFields(8), Numbers(8))); - ErrorsFound = true; - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName)); - ShowContinueError(state, EnergyPlus::format("Input for {} = {}", cAlphaFields(7), thisRadSysDesign.DesignCoolingCapMethodInput)); - ShowContinueError(state, EnergyPlus::format("Blank field not allowed for {}", cNumericFields(8))); - ErrorsFound = true; - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName)); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {}", cAlphaFields(7), thisRadSysDesign.DesignCoolingCapMethodInput)); - ErrorsFound = true; - } + parseDesignCapacitySizingMethod(state, + thisRadSysDesign.DesignCoolingCapMethodInput, + thisRadSysDesign.designName, + CurrentModuleObject, + cAlphaFields(7), + "CoolingDesignCapacity", + CoolingDesignCapacity, + "FractionOfAutosizedCoolingCapacity", + FractionOfAutosizedCoolingCapacity, + 7, // capPerFloorArea numeric index + 8, // fraction numeric index + Numbers, + lNumericBlanks, + cNumericFields, + thisRadSysDesign.DesignCoolingCapMethod, + thisRadSysDesign.DesignScaledCoolingCapacity, + ErrorsFound); thisRadSysDesign.ColdThrottlRange = Numbers(9); @@ -691,49 +835,19 @@ namespace LowTempRadiantSystem { } thisRadSys.SurfListName = Alphas(5); - SurfListNum = 0; - if (state.dataSurfLists->NumOfSurfaceLists > 0) { - SurfListNum = Util::FindItemInList(thisRadSys.SurfListName, state.dataSurfLists->SurfList); - } - if (SurfListNum > 0) { // Found a valid surface list - thisRadSys.NumOfSurfaces = state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces; - thisRadSys.SurfacePtr.allocate(thisRadSys.NumOfSurfaces); - thisRadSys.SurfaceName.allocate(thisRadSys.NumOfSurfaces); - thisRadSys.SurfaceFrac.allocate(thisRadSys.NumOfSurfaces); - thisRadSys.NumCircuits.allocate(thisRadSys.NumOfSurfaces); - for (SurfNum = 1; SurfNum <= state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces; ++SurfNum) { - thisRadSys.SurfacePtr(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfPtr(SurfNum); - thisRadSys.SurfaceName(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfName(SurfNum); - thisRadSys.SurfaceFrac(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfFlowFrac(SurfNum); + SurfListNum = parseSurfaceListOrSingleSurface( + state, thisRadSys, RoutineName, CurrentModuleObject, cAlphaFields(5), Alphas(5), Alphas(1), ErrorsFound); + thisRadSys.NumCircuits.allocate(thisRadSys.NumOfSurfaces); + if (SurfListNum > 0) { + for (SurfNum = 1; SurfNum <= thisRadSys.NumOfSurfaces; ++SurfNum) { if (thisRadSys.SurfacePtr(SurfNum) > 0) { state.dataSurface->surfIntConv(thisRadSys.SurfacePtr(SurfNum)).hasActiveInIt = true; } } - } else { // User entered a single surface name rather than a surface list - thisRadSys.NumOfSurfaces = 1; - thisRadSys.SurfacePtr.allocate(thisRadSys.NumOfSurfaces); - thisRadSys.SurfaceName.allocate(thisRadSys.NumOfSurfaces); - thisRadSys.SurfaceFrac.allocate(thisRadSys.NumOfSurfaces); - thisRadSys.NumCircuits.allocate(thisRadSys.NumOfSurfaces); - thisRadSys.SurfaceName(1) = thisRadSys.SurfListName; - thisRadSys.SurfacePtr(1) = Util::FindItemInList(thisRadSys.SurfaceName(1), Surface); - thisRadSys.SurfaceFrac(1) = 1.0; + } else { thisRadSys.NumCircuits(1) = 0.0; - // Error checking for single surfaces - if (thisRadSys.SurfacePtr(1) == 0) { - ShowSevereError(state, EnergyPlus::format("{}Invalid {} = {}", RoutineName, cAlphaFields(5), Alphas(5))); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else if (state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(thisRadSys.SurfacePtr(1))) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", Invalid Surface", RoutineName, CurrentModuleObject, Alphas(1))); - ShowContinueError( - state, - EnergyPlus::format("{}=\"{}\" has been used in another radiant system or ventilated slab.", cAlphaFields(5), Alphas(5))); - ErrorsFound = true; - } if (thisRadSys.SurfacePtr(1) != 0) { state.dataSurface->surfIntConv(thisRadSys.SurfacePtr(1)).hasActiveInIt = true; - state.dataSurface->surfIntConv(thisRadSys.SurfacePtr(1)).hasActiveInIt = true; // Ummmm ... what? } } @@ -743,30 +857,25 @@ namespace LowTempRadiantSystem { thisRadSys.TubeLength = Numbers(1); // Determine Low Temp Radiant heating design capacity sizing method - if (variableFlowDesignDataObject.DesignHeatingCapMethod == HeatingDesignCapacity) { - thisRadSys.HeatingCapMethod = HeatingDesignCapacity; - if (!lNumericBlanks(2)) { - thisRadSys.ScaledHeatingCapacity = Numbers(2); - if (thisRadSys.ScaledHeatingCapacity < 0.0 && thisRadSys.ScaledHeatingCapacity != AutoSize) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSys.Name)); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {:.7T}", cNumericFields(2), Numbers(2))); - ErrorsFound = true; - } - } else { - if ((!lAlphaBlanks(6)) || (!lAlphaBlanks(7))) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSys.Name)); - ShowContinueError(state, "Input for Heating Design Capacity Method = HeatingDesignCapacity"); - ShowContinueError(state, EnergyPlus::format("Blank field not allowed for {}", cNumericFields(2))); - ErrorsFound = true; - } - } - } else if (variableFlowDesignDataObject.DesignHeatingCapMethod == CapacityPerFloorArea) { - thisRadSys.HeatingCapMethod = CapacityPerFloorArea; - thisRadSys.ScaledHeatingCapacity = variableFlowDesignDataObject.DesignScaledHeatingCapacity; - } else if (variableFlowDesignDataObject.DesignHeatingCapMethod == FractionOfAutosizedHeatingCapacity) { - thisRadSys.HeatingCapMethod = FractionOfAutosizedHeatingCapacity; - thisRadSys.ScaledHeatingCapacity = variableFlowDesignDataObject.DesignScaledHeatingCapacity; - } + applyDesignCapacityFromDesignObject(state, + variableFlowDesignDataObject.DesignHeatingCapMethod, + HeatingDesignCapacity, + CapacityPerFloorArea, + FractionOfAutosizedHeatingCapacity, + variableFlowDesignDataObject.DesignScaledHeatingCapacity, + CurrentModuleObject, + thisRadSys.Name, + "Heating", + 2, + 6, + 7, + Numbers, + lNumericBlanks, + lAlphaBlanks, + cNumericFields, + thisRadSys.HeatingCapMethod, + thisRadSys.ScaledHeatingCapacity, + ErrorsFound); // Heating user input data thisRadSys.WaterVolFlowMaxHeat = Numbers(3); @@ -803,30 +912,25 @@ namespace LowTempRadiantSystem { } // Determine Low Temp Radiant cooling design capacity sizing method - if (variableFlowDesignDataObject.DesignCoolingCapMethod == CoolingDesignCapacity) { - thisRadSys.CoolingCapMethod = CoolingDesignCapacity; - if (!lNumericBlanks(4)) { - thisRadSys.ScaledCoolingCapacity = Numbers(4); - if (thisRadSys.ScaledCoolingCapacity < 0.0 && thisRadSys.ScaledCoolingCapacity != AutoSize) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSys.Name)); - ShowContinueError(state, EnergyPlus::format("Illegal {} = {:.7T}", cNumericFields(4), Numbers(4))); - ErrorsFound = true; - } - } else { - if ((!lAlphaBlanks(8)) || (!lAlphaBlanks(9))) { - ShowSevereError(state, EnergyPlus::format("{} = {}", CurrentModuleObject, thisRadSys.Name)); - ShowContinueError(state, "Input for Cooling Design Capacity Method = CoolingDesignCapacity"); - ShowContinueError(state, EnergyPlus::format("Blank field not allowed for {}", cNumericFields(4))); - ErrorsFound = true; - } - } - } else if (variableFlowDesignDataObject.DesignCoolingCapMethod == CapacityPerFloorArea) { - thisRadSys.CoolingCapMethod = CapacityPerFloorArea; - thisRadSys.ScaledCoolingCapacity = variableFlowDesignDataObject.DesignScaledCoolingCapacity; - } else if (variableFlowDesignDataObject.DesignCoolingCapMethod == FractionOfAutosizedCoolingCapacity) { - thisRadSys.CoolingCapMethod = FractionOfAutosizedCoolingCapacity; - thisRadSys.ScaledCoolingCapacity = variableFlowDesignDataObject.DesignScaledCoolingCapacity; - } + applyDesignCapacityFromDesignObject(state, + variableFlowDesignDataObject.DesignCoolingCapMethod, + CoolingDesignCapacity, + CapacityPerFloorArea, + FractionOfAutosizedCoolingCapacity, + variableFlowDesignDataObject.DesignScaledCoolingCapacity, + CurrentModuleObject, + thisRadSys.Name, + "Cooling", + 4, + 8, + 9, + Numbers, + lNumericBlanks, + lAlphaBlanks, + cNumericFields, + thisRadSys.CoolingCapMethod, + thisRadSys.ScaledCoolingCapacity, + ErrorsFound); // Cooling user input data thisRadSys.WaterVolFlowMaxCool = Numbers(5); @@ -1010,49 +1114,19 @@ namespace LowTempRadiantSystem { } thisCFloSys.SurfListName = Alphas(5); - SurfListNum = 0; - if (state.dataSurfLists->NumOfSurfaceLists > 0) { - SurfListNum = Util::FindItemInList(thisCFloSys.SurfListName, state.dataSurfLists->SurfList); - } - if (SurfListNum > 0) { // Found a valid surface list - thisCFloSys.NumOfSurfaces = state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces; - thisCFloSys.SurfacePtr.allocate(thisCFloSys.NumOfSurfaces); - thisCFloSys.SurfaceName.allocate(thisCFloSys.NumOfSurfaces); - thisCFloSys.SurfaceFrac.allocate(thisCFloSys.NumOfSurfaces); - thisCFloSys.NumCircuits.allocate(thisCFloSys.NumOfSurfaces); - state.dataLowTempRadSys->MaxCloNumOfSurfaces = max(state.dataLowTempRadSys->MaxCloNumOfSurfaces, thisCFloSys.NumOfSurfaces); - for (SurfNum = 1; SurfNum <= state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces; ++SurfNum) { - thisCFloSys.SurfacePtr(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfPtr(SurfNum); - thisCFloSys.SurfaceName(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfName(SurfNum); - thisCFloSys.SurfaceFrac(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfFlowFrac(SurfNum); + SurfListNum = parseSurfaceListOrSingleSurface( + state, thisCFloSys, RoutineName, CurrentModuleObject, cAlphaFields(5), Alphas(5), Alphas(1), ErrorsFound); + thisCFloSys.NumCircuits.allocate(thisCFloSys.NumOfSurfaces); + state.dataLowTempRadSys->MaxCloNumOfSurfaces = max(state.dataLowTempRadSys->MaxCloNumOfSurfaces, thisCFloSys.NumOfSurfaces); + if (SurfListNum > 0) { + for (SurfNum = 1; SurfNum <= thisCFloSys.NumOfSurfaces; ++SurfNum) { thisCFloSys.NumCircuits(SurfNum) = 0.0; if (thisCFloSys.SurfacePtr(SurfNum) != 0) { state.dataSurface->surfIntConv(thisCFloSys.SurfacePtr(SurfNum)).hasActiveInIt = true; } } - } else { // User entered a single surface name rather than a surface list - thisCFloSys.NumOfSurfaces = 1; - thisCFloSys.SurfacePtr.allocate(thisCFloSys.NumOfSurfaces); - thisCFloSys.SurfaceName.allocate(thisCFloSys.NumOfSurfaces); - thisCFloSys.SurfaceFrac.allocate(thisCFloSys.NumOfSurfaces); - thisCFloSys.NumCircuits.allocate(thisCFloSys.NumOfSurfaces); - state.dataLowTempRadSys->MaxCloNumOfSurfaces = max(state.dataLowTempRadSys->MaxCloNumOfSurfaces, thisCFloSys.NumOfSurfaces); - thisCFloSys.SurfaceName(1) = thisCFloSys.SurfListName; - thisCFloSys.SurfacePtr(1) = Util::FindItemInList(thisCFloSys.SurfaceName(1), Surface); - thisCFloSys.SurfaceFrac(1) = 1.0; + } else { thisCFloSys.NumCircuits(1) = 0.0; - // Error checking for single surfaces - if (thisCFloSys.SurfacePtr(1) == 0) { - ShowSevereError(state, EnergyPlus::format("{}Invalid {} = {}", RoutineName, cAlphaFields(4), Alphas(4))); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else if (state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(thisCFloSys.SurfacePtr(1))) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", Invalid Surface", RoutineName, CurrentModuleObject, Alphas(1))); - ShowContinueError( - state, - EnergyPlus::format("{}=\"{}\" has been used in another radiant system or ventilated slab.", cAlphaFields(5), Alphas(5))); - ErrorsFound = true; - } if (thisCFloSys.SurfacePtr(1) != 0) { state.dataSurface->surfIntConv(thisCFloSys.SurfacePtr(1)).hasActiveInIt = true; state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(thisCFloSys.SurfacePtr(1)) = true; @@ -1238,43 +1312,10 @@ namespace LowTempRadiantSystem { } thisElecSys.SurfListName = Alphas(4); - SurfListNum = 0; - if (state.dataSurfLists->NumOfSurfaceLists > 0) { - SurfListNum = Util::FindItemInList(thisElecSys.SurfListName, state.dataSurfLists->SurfList); - } - if (SurfListNum > 0) { // Found a valid surface list - thisElecSys.NumOfSurfaces = state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces; - thisElecSys.SurfacePtr.allocate(thisElecSys.NumOfSurfaces); - thisElecSys.SurfaceName.allocate(thisElecSys.NumOfSurfaces); - thisElecSys.SurfaceFrac.allocate(thisElecSys.NumOfSurfaces); - for (SurfNum = 1; SurfNum <= state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces; ++SurfNum) { - thisElecSys.SurfacePtr(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfPtr(SurfNum); - thisElecSys.SurfaceName(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfName(SurfNum); - thisElecSys.SurfaceFrac(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfFlowFrac(SurfNum); - } - } else { // User entered a single surface name rather than a surface list - thisElecSys.NumOfSurfaces = 1; - thisElecSys.SurfacePtr.allocate(thisElecSys.NumOfSurfaces); - thisElecSys.SurfaceName.allocate(thisElecSys.NumOfSurfaces); - thisElecSys.SurfaceFrac.allocate(thisElecSys.NumOfSurfaces); - thisElecSys.SurfaceName(1) = thisElecSys.SurfListName; - thisElecSys.SurfacePtr(1) = Util::FindItemInList(thisElecSys.SurfaceName(1), Surface); - thisElecSys.SurfaceFrac(1) = 1.0; - // Error checking for single surfaces - if (thisElecSys.SurfacePtr(1) == 0) { - ShowSevereError(state, EnergyPlus::format("{}Invalid {} = {}", RoutineName, cAlphaFields(4), Alphas(4))); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", CurrentModuleObject, Alphas(1))); - ErrorsFound = true; - } else if (state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(thisElecSys.SurfacePtr(1))) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", Invalid Surface", RoutineName, CurrentModuleObject, Alphas(1))); - ShowContinueError( - state, - EnergyPlus::format("{}=\"{}\" has been used in another radiant system or ventilated slab.", cAlphaFields(4), Alphas(4))); - ErrorsFound = true; - } - if (thisElecSys.SurfacePtr(1) != 0) { - state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(state.dataLowTempRadSys->ElecRadSys(Item).SurfacePtr(1)) = true; - } + SurfListNum = parseSurfaceListOrSingleSurface( + state, thisElecSys, RoutineName, CurrentModuleObject, cAlphaFields(4), Alphas(4), Alphas(1), ErrorsFound); + if (SurfListNum <= 0 && thisElecSys.SurfacePtr(1) != 0) { + state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(thisElecSys.SurfacePtr(1)) = true; } // Error checking for zones and construction information @@ -1388,87 +1429,18 @@ namespace LowTempRadiantSystem { AssignedAsRadiantSurface.dimension(state.dataSurface->TotSurfaces, false); for (Item = 1; Item <= state.dataLowTempRadSys->NumOfHydrLowTempRadSys; ++Item) { - for (SurfNum = 1; SurfNum <= state.dataLowTempRadSys->HydrRadSys(Item).NumOfSurfaces; ++SurfNum) { - CheckSurfNum = state.dataLowTempRadSys->HydrRadSys(Item).SurfacePtr(SurfNum); - if (CheckSurfNum == 0) { - continue; - } - if (AssignedAsRadiantSurface(CheckSurfNum)) { - ShowSevereError(state, - EnergyPlus::format("Surface {} is referenced by more than one radiant system--this is not allowed", - Surface(CheckSurfNum).Name)); - ErrorsFound = true; - } else { - AssignedAsRadiantSurface(CheckSurfNum) = true; - } - // Also check the other side of interzone partitions - if ((Surface(CheckSurfNum).ExtBoundCond > 0) && (Surface(CheckSurfNum).ExtBoundCond != CheckSurfNum)) { - if (AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond)) { - ShowSevereError(state, - EnergyPlus::format("Interzone surface {} is referenced by more than one radiant system--this is not allowed", - Surface(Surface(CheckSurfNum).ExtBoundCond).Name)); - ErrorsFound = true; - } else { - AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond) = true; - } - } - } + auto &sys = state.dataLowTempRadSys->HydrRadSys(Item); + checkRadiantSurfaceAssignment(state, AssignedAsRadiantSurface, sys.NumOfSurfaces, sys.SurfacePtr, ErrorsFound); } for (Item = 1; Item <= state.dataLowTempRadSys->NumOfCFloLowTempRadSys; ++Item) { - for (SurfNum = 1; SurfNum <= state.dataLowTempRadSys->CFloRadSys(Item).NumOfSurfaces; ++SurfNum) { - CheckSurfNum = state.dataLowTempRadSys->CFloRadSys(Item).SurfacePtr(SurfNum); - if (CheckSurfNum == 0) { - continue; - } - if (AssignedAsRadiantSurface(CheckSurfNum)) { - ShowSevereError(state, - EnergyPlus::format("Surface {} is referenced by more than one radiant system--this is not allowed", - Surface(CheckSurfNum).Name)); - ErrorsFound = true; - } else { - AssignedAsRadiantSurface(CheckSurfNum) = true; - } - // Also check the other side of interzone partitions - if ((Surface(CheckSurfNum).ExtBoundCond > 0) && (Surface(CheckSurfNum).ExtBoundCond != CheckSurfNum)) { - if (AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond)) { - ShowSevereError(state, - EnergyPlus::format("Interzone surface {} is referenced by more than one radiant system--this is not allowed", - Surface(Surface(CheckSurfNum).ExtBoundCond).Name)); - ErrorsFound = true; - } else { - AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond) = true; - } - } - } + auto &sys = state.dataLowTempRadSys->CFloRadSys(Item); + checkRadiantSurfaceAssignment(state, AssignedAsRadiantSurface, sys.NumOfSurfaces, sys.SurfacePtr, ErrorsFound); } for (Item = 1; Item <= state.dataLowTempRadSys->NumOfElecLowTempRadSys; ++Item) { - for (SurfNum = 1; SurfNum <= state.dataLowTempRadSys->ElecRadSys(Item).NumOfSurfaces; ++SurfNum) { - CheckSurfNum = state.dataLowTempRadSys->ElecRadSys(Item).SurfacePtr(SurfNum); - if (CheckSurfNum == 0) { - continue; - } - if (AssignedAsRadiantSurface(CheckSurfNum)) { - ShowSevereError(state, - EnergyPlus::format("Surface {} is referenced by more than one radiant system--this is not allowed", - Surface(CheckSurfNum).Name)); - ErrorsFound = true; - } else { - AssignedAsRadiantSurface(CheckSurfNum) = true; - } - // Also check the other side of interzone partitions - if ((Surface(CheckSurfNum).ExtBoundCond > 0) && (Surface(CheckSurfNum).ExtBoundCond != CheckSurfNum)) { - if (AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond)) { - ShowSevereError(state, - EnergyPlus::format("Interzone surface {} is referenced by more than one radiant system--this is not allowed", - Surface(Surface(CheckSurfNum).ExtBoundCond).Name)); - ErrorsFound = true; - } else { - AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond) = true; - } - } - } + auto &sys = state.dataLowTempRadSys->ElecRadSys(Item); + checkRadiantSurfaceAssignment(state, AssignedAsRadiantSurface, sys.NumOfSurfaces, sys.SurfacePtr, ErrorsFound); } AssignedAsRadiantSurface.deallocate(); diff --git a/src/EnergyPlus/Material.cc b/src/EnergyPlus/Material.cc index e290cc51f33..63f5a8e07f6 100644 --- a/src/EnergyPlus/Material.cc +++ b/src/EnergyPlus/Material.cc @@ -84,6 +84,271 @@ constexpr std::array gases = { constexpr std::array ecoRoofCalcMethodNamesUC = {"SIMPLE", "ADVANCED"}; +// Helper to check that the sum of two numeric input fields is less than 1.0. +// Sets ErrorsFound and emits "Illegal value combination" if the check fails. +// Helper to find a referenced epJSON object by case-insensitive name lookup. +// Searches for objectType in epJSON, then finds an entry whose key matches +// alphaFieldName (upper-cased). Marks it as used and returns a pointer to +// the JSON value, or nullptr if not found (after emitting errors). +static nlohmann::json const * +findReferencedEpJSONObject(EnergyPlusData &state, ErrorObjectHeader const &eoh, bool &ErrorsFound, std::string const &objectType, int alphaFieldIdx) +{ + auto &s_ip = state.dataInputProcessing->inputProcessor; + auto &s_ipsc = state.dataIPShortCut; + auto const itInstances = s_ip->epJSON.find(objectType); + if (itInstances == s_ip->epJSON.end()) { + ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(alphaFieldIdx), s_ipsc->cAlphaArgs(alphaFieldIdx)); + ErrorsFound = true; + return nullptr; + } + + auto const &instances = itInstances.value(); + // Can't use find here because epJSON keys are not upper-cased + for (auto itObj = instances.begin(); itObj != instances.end(); ++itObj) { + if (Util::makeUPPER(itObj.key()) == s_ipsc->cAlphaArgs(alphaFieldIdx)) { + s_ip->markObjectAsUsed(objectType, itObj.key()); + return &(itObj.value()); + } + } + + ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(alphaFieldIdx), s_ipsc->cAlphaArgs(alphaFieldIdx)); + ErrorsFound = true; + return nullptr; +} + +// Helper to check for duplicate material name. Returns true if duplicate found (caller should continue/skip). +static bool checkDupMaterialName(EnergyPlusData &state, ErrorObjectHeader const &eoh, bool &ErrorsFound) +{ + auto &s_mat = state.dataMaterial; + auto &s_ipsc = state.dataIPShortCut; + if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { + ShowSevereDuplicateName(state, eoh); + ErrorsFound = true; + return true; + } + return false; +} + +// Helper to register a newly-created material in the materials list and map. +static void registerMaterial(EnergyPlusData &state, MaterialBase *mat) +{ + auto &s_mat = state.dataMaterial; + s_mat->materials.push_back(mat); + mat->Num = s_mat->materials.isize(); + s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); +} + +static void checkFieldSumLessThan(EnergyPlusData &state, bool &ErrorsFound, int idx1, int idx2) +{ + auto &s_ipsc = state.dataIPShortCut; + if (s_ipsc->rNumericArgs(idx1) + s_ipsc->rNumericArgs(idx2) >= 1.0) { + ErrorsFound = true; + ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); + ShowContinueError(state, s_ipsc->cNumericFieldNames(idx1) + " + " + s_ipsc->cNumericFieldNames(idx2) + " not < 1.0"); + } +} + +// Helper to check that the sum of three numeric input fields is less than 1.0. +static void checkFieldSumLessThan3(EnergyPlusData &state, bool &ErrorsFound, int idx1, int idx2, int idx3) +{ + auto &s_ipsc = state.dataIPShortCut; + if (s_ipsc->rNumericArgs(idx1) + s_ipsc->rNumericArgs(idx2) + s_ipsc->rNumericArgs(idx3) >= 1.0) { + ErrorsFound = true; + ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); + ShowContinueError(state, + s_ipsc->cNumericFieldNames(idx1) + " + " + s_ipsc->cNumericFieldNames(idx2) + " + " + s_ipsc->cNumericFieldNames(idx3) + + "not < 1.0"); + } +} + +// Helper to check that two numeric input fields are equal (within tolerance). +static void checkFieldsEqual(EnergyPlusData &state, bool &ErrorsFound, int idx1, int idx2) +{ + auto &s_ipsc = state.dataIPShortCut; + if (std::abs(s_ipsc->rNumericArgs(idx1) - s_ipsc->rNumericArgs(idx2)) > 1.e-5) { + ErrorsFound = true; + ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); + ShowContinueError(state, s_ipsc->cNumericFieldNames(idx1) + " must equal " + s_ipsc->cNumericFieldNames(idx2)); + } +} + +// Helper to check that the sum of two numeric input fields does not exceed 1.0. +// Uses ShowSevereCustom with an ErrorObjectHeader (unlike checkFieldSumLessThan which uses ShowSevereError). +static void checkFieldPairSumNotExceedOne(EnergyPlusData &state, bool &ErrorsFound, ErrorObjectHeader const &eoh, int idx1, int idx2) +{ + auto &s_ipsc = state.dataIPShortCut; + if (s_ipsc->rNumericArgs(idx1) + s_ipsc->rNumericArgs(idx2) > 1.0) { + ErrorsFound = true; + ShowSevereCustom(state, eoh, EnergyPlus::format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(idx1), s_ipsc->cNumericFieldNames(idx2))); + } +} + +// Helper to check that a numeric input field is strictly positive (> 0). +static void checkFieldPositive(EnergyPlusData &state, bool &ErrorsFound, ErrorObjectHeader const &eoh, int idx) +{ + auto &s_ipsc = state.dataIPShortCut; + if (s_ipsc->rNumericArgs(idx) <= 0.0) { + ErrorsFound = true; + ShowSevereCustom( + state, eoh, EnergyPlus::format("{} must be > 0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(idx), s_ipsc->rNumericArgs(idx))); + } +} + +// Helper to check that a numeric input field is in the range [0, 1]. +static void checkFieldInRange01(EnergyPlusData &state, bool &ErrorsFound, ErrorObjectHeader const &eoh, int idx) +{ + auto &s_ipsc = state.dataIPShortCut; + if ((s_ipsc->rNumericArgs(idx) < 0.0) || (s_ipsc->rNumericArgs(idx) > 1.0)) { + ErrorsFound = true; + ShowSevereCustom( + state, + eoh, + EnergyPlus::format("{} must be >= 0 and <= 1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(idx), s_ipsc->rNumericArgs(idx))); + } +} + +// Helper to read a numeric input field into a given variable and validate it is in [0, 1]. +// Uses the legacy "Illegal value" two-line error format matching existing WindowMaterial:Screen messages. +static void readFieldAndValidateRange01(EnergyPlusData &state, Real64 &outVar, int fieldIdx) +{ + auto &s_ipsc = state.dataIPShortCut; + outVar = s_ipsc->rNumericArgs(fieldIdx); + if (outVar < 0.0 || outVar > 1.0) { + ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value."); + ShowContinueError(state, s_ipsc->cNumericFieldNames(fieldIdx) + " must be greater than or equal to 0 and less than or equal to 1."); + } +} + +// Helper to validate a SpectralAndAngle curve: checks that the curve +// exists, is 2-D, and has the required angle (0-90) and wavelength (0.1-4.0) ranges. +static void validateSpecAngCurve(EnergyPlusData &state, + bool &ErrorsFound, + ErrorObjectHeader const &eoh, + int alphaFieldIdx, + Curve::Curve *&curvePtr, + Curve::Curve *inputLimitsOverride = nullptr) +{ + auto &s_ipsc = state.dataIPShortCut; + if (s_ipsc->lAlphaFieldBlanks(alphaFieldIdx)) { + ErrorsFound = true; + ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(alphaFieldIdx), s_ipsc->cAlphaFieldNames(2), "SpectralAndAngle"); + } else if ((curvePtr = Curve::GetCurve(state, s_ipsc->cAlphaArgs(alphaFieldIdx))) == nullptr) { + ErrorsFound = true; + ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(alphaFieldIdx), s_ipsc->cAlphaArgs(alphaFieldIdx)); + } else if (curvePtr->numDims != 2) { + Curve::ShowSevereCurveDims(state, eoh, s_ipsc->cAlphaFieldNames(alphaFieldIdx), s_ipsc->cAlphaArgs(alphaFieldIdx), "2", curvePtr->numDims); + ErrorsFound = true; + } else { + Curve::Curve *limitsSource = (inputLimitsOverride != nullptr) ? inputLimitsOverride : curvePtr; + Real64 minAng = limitsSource->inputLimits[0].min; + Real64 maxAng = limitsSource->inputLimits[0].max; + Real64 minLam = limitsSource->inputLimits[1].min; + Real64 maxLam = limitsSource->inputLimits[1].max; + + if (minAng > 1.0e-6) { + ErrorsFound = true; + ShowSevereCustom(state, + eoh, + EnergyPlus::format("{} requires the minimum value = 0.0 in the entered table name={}", + s_ipsc->cAlphaFieldNames(alphaFieldIdx), + s_ipsc->cAlphaArgs(alphaFieldIdx))); + } + if (std::abs(maxAng - 90.0) > 1.0e-6) { + ErrorsFound = true; + ShowSevereCustom(state, + eoh, + EnergyPlus::format("{} requires the maximum value = 90.0 in the entered table name={}", + s_ipsc->cAlphaFieldNames(alphaFieldIdx), + s_ipsc->cAlphaArgs(alphaFieldIdx))); + } + if (minLam < 0.1) { + ErrorsFound = true; + ShowSevereCustom(state, + eoh, + EnergyPlus::format("{} requires the minimum value = 0.1 micron in the entered table name={}", + s_ipsc->cAlphaFieldNames(alphaFieldIdx), + s_ipsc->cAlphaArgs(alphaFieldIdx))); + } + if (maxLam > 4.0) { + ErrorsFound = true; + ShowSevereCustom(state, + eoh, + EnergyPlus::format("{} requires the maximum value = 4.0 microns in the entered table name={}", + s_ipsc->cAlphaFieldNames(alphaFieldIdx), + s_ipsc->cAlphaArgs(alphaFieldIdx))); + } + } +} + +// Helper to load custom gas properties from input fields and validate them. +// Loads conductivity, viscosity, specific heat coefficients (c0/c1/c2), molecular weight, +// and specific heat ratio from rNumericArgs(2..12), then checks vis.c0, cp.c0, wght > 0. +static void loadCustomGasProps(EnergyPlusData &state, MaterialGasMix *matGas, bool &ErrorsFound, ErrorObjectHeader const &eoh) +{ + auto &s_ipsc = state.dataIPShortCut; + matGas->gases[0].con.c0 = s_ipsc->rNumericArgs(2); + matGas->gases[0].con.c1 = s_ipsc->rNumericArgs(3); + matGas->gases[0].con.c2 = s_ipsc->rNumericArgs(4); + matGas->gases[0].vis.c0 = s_ipsc->rNumericArgs(5); + matGas->gases[0].vis.c1 = s_ipsc->rNumericArgs(6); + matGas->gases[0].vis.c2 = s_ipsc->rNumericArgs(7); + matGas->gases[0].cp.c0 = s_ipsc->rNumericArgs(8); + matGas->gases[0].cp.c1 = s_ipsc->rNumericArgs(9); + matGas->gases[0].cp.c2 = s_ipsc->rNumericArgs(10); + matGas->gases[0].wght = s_ipsc->rNumericArgs(11); + matGas->gases[0].specHeatRatio = s_ipsc->rNumericArgs(12); + + if (matGas->gases[0].vis.c0 <= 0.0) { + ErrorsFound = true; + ShowSevereCustom(state, eoh, EnergyPlus::format("{} not > 0.0", s_ipsc->cNumericFieldNames(5))); + } + if (matGas->gases[0].cp.c0 <= 0.0) { + ErrorsFound = true; + ShowSevereCustom(state, eoh, EnergyPlus::format("{} not > 0.0", s_ipsc->cNumericFieldNames(8))); + } + if (matGas->gases[0].wght <= 0.0) { + ErrorsFound = true; + ShowSevereCustom(state, eoh, EnergyPlus::format("{} not > 0.0", s_ipsc->cNumericFieldNames(11))); + } +} + +// Helper to compute the nominal resistance of a gas gap at room temperature. +static void calcGasNominalR(EnergyPlusData &state, MaterialGasMix *matGas, bool &ErrorsFound, ErrorObjectHeader const &eoh) +{ + if (!ErrorsFound) { + Real64 DenomRGas = (matGas->gases[0].con.c0 + matGas->gases[0].con.c1 * 300.0 + matGas->gases[0].con.c2 * 90000.0); + if (DenomRGas > 0.0) { + matGas->NominalR = matGas->Thickness / DenomRGas; + } else { + ShowSevereCustom( + state, + eoh, + EnergyPlus::format("Nominal resistance of gap at room temperature calculated at a negative Conductivity=[{:.3R}].", DenomRGas)); + ErrorsFound = true; + } + } +} + +// Helper to call getObjectItem with the standard set of material input arguments. +// Wraps the repetitive 12-argument call that appears for every material type. +static void getMaterialInput(EnergyPlusData &state, int Loop, int &NumAlphas, int &NumNums, int &IOStat) +{ + auto &s_ip = state.dataInputProcessing->inputProcessor; + auto &s_ipsc = state.dataIPShortCut; + s_ip->getObjectItem(state, + s_ipsc->cCurrentModuleObject, + Loop, + s_ipsc->cAlphaArgs, + NumAlphas, + s_ipsc->rNumericArgs, + NumNums, + IOStat, + s_ipsc->lNumericFieldBlanks, + s_ipsc->lAlphaFieldBlanks, + s_ipsc->cAlphaFieldNames, + s_ipsc->cNumericFieldNames); +} + int GetMaterialNum(EnergyPlusData const &state, std::string const &matName) { auto const &s_mat = state.dataMaterial; @@ -138,14 +403,12 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if int NumGas; // Index for loop over gap gases in a mixture int NumGases; // Number of gasses in a mixture GasType gasType = GasType::Invalid; // Gas type index: 1=air, 2=argon, 3=krypton, 4=xenon - int ICoeff; // Gas property coefficient index Real64 MinSlatAngGeom; // Minimum and maximum slat angle allowed by slat geometry (deg) Real64 MaxSlatAngGeom; Real64 ReflectivitySol; // Glass reflectivity, solar Real64 ReflectivityVis; // Glass reflectivity, visible Real64 TransmittivitySol; // Glass transmittivity, solar Real64 TransmittivityVis; // Glass transmittivity, visible - Real64 DenomRGas; // Denominator for WindowGas calculations of NominalR Real64 Openness; // insect screen openness fraction = (1-d/s)^2 // Added TH 1/9/2009 to read the thermochromic glazings @@ -250,24 +513,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumNoMasses; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -275,9 +525,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->group = Group::Regular; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->Roughness = static_cast(getEnumValue(surfaceRoughnessNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(2)))); @@ -332,24 +580,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumAirGaps; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -358,9 +593,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->group = Group::AirGap; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->Roughness = SurfaceRoughness::MediumRough; @@ -372,24 +605,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumIRTs; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -397,9 +617,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->group = Group::IRTransparent; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); // Load data for other properties that need defaults mat->ROnly = true; @@ -419,33 +637,18 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumW5Glazings; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } auto *mat = new MaterialGlass; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->Roughness = SurfaceRoughness::VerySmooth; mat->ROnly = true; @@ -495,35 +698,12 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if // Fixed CR 8413 - modeling spandrel panels as glazing systems } else if (mat->windowOpticalData == Window::OpticalDataModel::SpectralAverage) { - if (s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(3) > 1.0) { - ErrorsFound = true; - ShowSevereCustom(state, eoh, EnergyPlus::format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(2), s_ipsc->cNumericFieldNames(3))); - } - - if (s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(4) > 1.0) { - ErrorsFound = true; - ShowSevereCustom(state, eoh, EnergyPlus::format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(2), s_ipsc->cNumericFieldNames(4))); - } - - if (s_ipsc->rNumericArgs(5) + s_ipsc->rNumericArgs(6) > 1.0) { - ErrorsFound = true; - ShowSevereCustom(state, eoh, EnergyPlus::format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(5), s_ipsc->cNumericFieldNames(6))); - } - - if (s_ipsc->rNumericArgs(5) + s_ipsc->rNumericArgs(7) > 1.0) { - ErrorsFound = true; - ShowSevereCustom(state, eoh, EnergyPlus::format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(5), s_ipsc->cNumericFieldNames(7))); - } - - if (s_ipsc->rNumericArgs(8) + s_ipsc->rNumericArgs(9) > 1.0) { - ErrorsFound = true; - ShowSevereCustom(state, eoh, EnergyPlus::format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(8), s_ipsc->cNumericFieldNames(9))); - } - - if (s_ipsc->rNumericArgs(8) + s_ipsc->rNumericArgs(10) > 1.0) { - ErrorsFound = true; - ShowSevereCustom(state, eoh, EnergyPlus::format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(8), s_ipsc->cNumericFieldNames(10))); - } + checkFieldPairSumNotExceedOne(state, ErrorsFound, eoh, 2, 3); + checkFieldPairSumNotExceedOne(state, ErrorsFound, eoh, 2, 4); + checkFieldPairSumNotExceedOne(state, ErrorsFound, eoh, 5, 6); + checkFieldPairSumNotExceedOne(state, ErrorsFound, eoh, 5, 7); + checkFieldPairSumNotExceedOne(state, ErrorsFound, eoh, 8, 9); + checkFieldPairSumNotExceedOne(state, ErrorsFound, eoh, 8, 10); if (s_ipsc->rNumericArgs(2) < 0.0) { ShowSevereCustom(state, eoh, EnergyPlus::format("{} not >= 0.0", s_ipsc->cNumericFieldNames(2))); @@ -612,153 +792,10 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if // Get SpectralAndAngle table names if (mat->windowOpticalData == Window::OpticalDataModel::SpectralAndAngle) { - if (s_ipsc->lAlphaFieldBlanks(5)) { - ErrorsFound = true; - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaFieldNames(2), "SpectralAndAngle"); - } else if ((mat->GlassSpecAngTransCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(5))) == nullptr) { - ErrorsFound = true; - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5)); - } else if (mat->GlassSpecAngTransCurve->numDims != 2) { - Curve::ShowSevereCurveDims(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5), "2", mat->GlassSpecAngTransCurve->numDims); - ErrorsFound = true; - } else { - Real64 minAng = mat->GlassSpecAngTransCurve->inputLimits[0].min; - Real64 maxAng = mat->GlassSpecAngTransCurve->inputLimits[0].max; - Real64 minLam = mat->GlassSpecAngTransCurve->inputLimits[1].min; - Real64 maxLam = mat->GlassSpecAngTransCurve->inputLimits[1].max; - - if (minAng > 1.0e-6) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the minimum value = 0.0 in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - - if (std::abs(maxAng - 90.0) > 1.0e-6) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the maximum value = 90.0 in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - - if (minLam < 0.1) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the minimum value = 0.1 micron in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - - if (maxLam > 4.0) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the maximum value = 4.0 microns in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - } - - if (s_ipsc->lAlphaFieldBlanks(6)) { - ErrorsFound = true; - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaFieldNames(2), "SpectralAndAngle"); - } else if ((mat->GlassSpecAngFReflCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(6))) == nullptr) { - ErrorsFound = true; - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6)); - } else if (mat->GlassSpecAngFReflCurve->numDims != 2) { - Curve::ShowSevereCurveDims(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6), "2", mat->GlassSpecAngFReflCurve->numDims); - ErrorsFound = true; - } else { - Real64 minAng = mat->GlassSpecAngFReflCurve->inputLimits[0].min; - Real64 maxAng = mat->GlassSpecAngFReflCurve->inputLimits[0].max; - Real64 minLam = mat->GlassSpecAngFReflCurve->inputLimits[1].min; - Real64 maxLam = mat->GlassSpecAngFReflCurve->inputLimits[1].max; - if (minAng > 1.0e-6) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the minimum value = 0.0 in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - if (std::abs(maxAng - 90.0) > 1.0e-6) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the maximum value = 90.0 in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - if (minLam < 0.1) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the minimum value = 0.1 micron in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - if (maxLam > 4.0) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the maximum value = 4.0 microns in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - } - - if (s_ipsc->lAlphaFieldBlanks(7)) { - ErrorsFound = true; - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaFieldNames(2), "SpectralAndAngle"); - } else if ((mat->GlassSpecAngBReflCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(7))) == nullptr) { - ErrorsFound = true; - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7)); - } else if (mat->GlassSpecAngBReflCurve->numDims != 2) { - Curve::ShowSevereCurveDims(state, eoh, s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7), "2", mat->GlassSpecAngBReflCurve->numDims); - ErrorsFound = true; - } else { - Real64 minAng = mat->GlassSpecAngFReflCurve->inputLimits[0].min; - Real64 maxAng = mat->GlassSpecAngFReflCurve->inputLimits[0].max; - Real64 minLam = mat->GlassSpecAngFReflCurve->inputLimits[1].min; - Real64 maxLam = mat->GlassSpecAngFReflCurve->inputLimits[1].max; - if (minAng > 1.0e-6) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the minimum value = 0.0 in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - if (std::abs(maxAng - 90.0) > 1.0e-6) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the maximum value = 90.0 in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - if (minLam < 0.1) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the minimum value = 0.1 micron in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - if (maxLam > 4.0) { - ErrorsFound = true; - ShowSevereCustom(state, - eoh, - EnergyPlus::format("{} requires the maximum value = 4.0 microns in the entered table name={}", - s_ipsc->cAlphaFieldNames(5), - s_ipsc->cAlphaArgs(5))); - } - } + validateSpecAngCurve(state, ErrorsFound, eoh, 5, mat->GlassSpecAngTransCurve); + validateSpecAngCurve(state, ErrorsFound, eoh, 6, mat->GlassSpecAngFReflCurve); + // POSSIBLE BUG: original code validates BReflCurve using FReflCurve's inputLimits + validateSpecAngCurve(state, ErrorsFound, eoh, 7, mat->GlassSpecAngBReflCurve, mat->GlassSpecAngFReflCurve); } } @@ -769,24 +806,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumW5AltGlazings; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -794,9 +818,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->group = Group::Glass; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->Roughness = SurfaceRoughness::VerySmooth; mat->Thickness = s_ipsc->rNumericArgs(1); @@ -860,24 +882,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumEQLGlazings; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -885,9 +894,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->group = Group::GlassEQL; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->Roughness = SurfaceRoughness::VerySmooth; mat->ROnly = true; @@ -947,6 +954,21 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if } // W5GlsMatEQL loop + // Helper lambda to set up a single-gas material from input fields. + // Shared between WindowMaterial:Gas and WindowMaterial:Gap:EquivalentLayer. + auto initSingleGasMaterial = [&](MaterialGasMix *matGas) { + matGas->numGases = 1; + matGas->gasFracts[0] = 1.0; + matGas->gases[0].type = static_cast(getEnumValue(gasTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(2)))); + matGas->Roughness = SurfaceRoughness::MediumRough; + matGas->Thickness = s_ipsc->rNumericArgs(1); + matGas->ROnly = true; + GasType gt = matGas->gases[0].type; + if (gt != GasType::Custom) { + matGas->gases[0] = gases[(int)gt]; + } + }; + // Window gas materials (for gaps with a single gas) s_ipsc->cCurrentModuleObject = "WindowMaterial:Gas"; @@ -954,24 +976,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumW5Gases; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -979,78 +988,17 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if matGas->group = Group::Gas; matGas->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(matGas); - matGas->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(matGas->Name, matGas->Num); - - matGas->numGases = 1; - matGas->gasFracts[0] = 1.0; + registerMaterial(state, matGas); - // Load the material derived type from the input data. + initSingleGasMaterial(matGas); - matGas->gases[0].type = static_cast(getEnumValue(gasTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(2)))); - matGas->Roughness = SurfaceRoughness::MediumRough; - - matGas->Thickness = s_ipsc->rNumericArgs(1); - matGas->ROnly = true; - - gasType = matGas->gases[0].type; - if (gasType != GasType::Custom) { - matGas->gases[0] = gases[(int)gasType]; - } - - // Custom gas - - if (gasType == GasType::Custom) { - matGas->gases[0].con.c0 = s_ipsc->rNumericArgs(2); - matGas->gases[0].con.c1 = s_ipsc->rNumericArgs(3); - matGas->gases[0].con.c2 = s_ipsc->rNumericArgs(4); - matGas->gases[0].vis.c0 = s_ipsc->rNumericArgs(5); - matGas->gases[0].vis.c1 = s_ipsc->rNumericArgs(6); - matGas->gases[0].vis.c2 = s_ipsc->rNumericArgs(7); - matGas->gases[0].cp.c0 = s_ipsc->rNumericArgs(8); - matGas->gases[0].cp.c1 = s_ipsc->rNumericArgs(9); - matGas->gases[0].cp.c2 = s_ipsc->rNumericArgs(10); - matGas->gases[0].wght = s_ipsc->rNumericArgs(11); - matGas->gases[0].specHeatRatio = s_ipsc->rNumericArgs(12); - - // Check for errors in custom gas properties - // IF(dataMaterial.Material(MaterNum)%GasCon(1,1) <= 0.0) THEN - // ErrorsFound = .TRUE. - // CALL ShowSevereError(state, 'Conductivity Coefficient A for custom window gas='& - // //TRIM(s_ipsc->cAlphaArgs(1))//' should be > 0.') - // END IF - - if (matGas->gases[0].vis.c0 <= 0.0) { - ErrorsFound = true; - ShowSevereCustom(state, eoh, EnergyPlus::format("{} not > 0.0", s_ipsc->cNumericFieldNames(5))); - } - if (matGas->gases[0].cp.c0 <= 0.0) { - ErrorsFound = true; - ShowSevereCustom(state, eoh, EnergyPlus::format("{} not > 0.0", s_ipsc->cNumericFieldNames(8))); - } - if (matGas->gases[0].wght <= 0.0) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(11) + " not > 0.0"); - } + if (matGas->gases[0].type == GasType::Custom) { + loadCustomGasProps(state, matGas, ErrorsFound, eoh); } // Nominal resistance of gap at room temperature - if (!ErrorsFound) { - DenomRGas = (matGas->gases[0].con.c0 + matGas->gases[0].con.c1 * 300.0 + matGas->gases[0].con.c2 * 90000.0); - if (DenomRGas > 0.0) { - matGas->NominalR = matGas->Thickness / DenomRGas; - } else { - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value."); - ShowContinueError( - state, - EnergyPlus::format("Nominal resistance of gap at room temperature calculated at a negative Conductivity=[{:.3R}].", DenomRGas)); - ErrorsFound = true; - } - } + calcGasNominalR(state, matGas, ErrorsFound, eoh); } - // Window gap materials (for gaps with a single gas for EquivalentLayer) s_ipsc->cCurrentModuleObject = "WindowMaterial:Gap:EquivalentLayer"; @@ -1058,24 +1006,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumEQLGaps; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -1083,79 +1018,23 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if matGas->group = Group::WindowGapEQL; matGas->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(matGas); - matGas->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(matGas->Name, matGas->Num); - - matGas->numGases = 1; - matGas->gasFracts[0] = 1.0; - - // Load the material derived type from the input data. - - matGas->gases[0].type = static_cast(getEnumValue(gasTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(2)))); // Error check? + registerMaterial(state, matGas); - matGas->Roughness = SurfaceRoughness::MediumRough; - - matGas->Thickness = s_ipsc->rNumericArgs(1); - matGas->ROnly = true; - - gasType = matGas->gases[0].type; - if (gasType != GasType::Custom) { - matGas->gases[0] = gases[(int)gasType]; - } + initSingleGasMaterial(matGas); if (!s_ipsc->lAlphaFieldBlanks(2)) { // Get gap vent type matGas->gapVentType = static_cast(getEnumValue(gapVentTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(3)))); } - if (gasType == GasType::Custom) { - for (ICoeff = 1; ICoeff <= 3; ++ICoeff) { - matGas->gases[0].con.c0 = s_ipsc->rNumericArgs(2); - matGas->gases[0].con.c1 = s_ipsc->rNumericArgs(3); - matGas->gases[0].con.c2 = s_ipsc->rNumericArgs(4); - matGas->gases[0].vis.c0 = s_ipsc->rNumericArgs(5); - matGas->gases[0].vis.c1 = s_ipsc->rNumericArgs(6); - matGas->gases[0].vis.c2 = s_ipsc->rNumericArgs(7); - matGas->gases[0].cp.c0 = s_ipsc->rNumericArgs(8); - matGas->gases[0].cp.c1 = s_ipsc->rNumericArgs(9); - matGas->gases[0].cp.c2 = s_ipsc->rNumericArgs(10); - } - matGas->gases[0].wght = s_ipsc->rNumericArgs(11); - matGas->gases[0].specHeatRatio = s_ipsc->rNumericArgs(12); - - if (matGas->gases[0].vis.c0 <= 0.0) { - ErrorsFound = true; - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1))); - ShowContinueError(state, EnergyPlus::format("{} not > 0.0", s_ipsc->cNumericFieldNames(5))); - } - if (matGas->gases[0].cp.c0 <= 0.0) { - ErrorsFound = true; - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1))); - ShowContinueError(state, EnergyPlus::format("{} not > 0.0", s_ipsc->cNumericFieldNames(8))); - } - if (matGas->gases[0].wght <= 0.0) { - ErrorsFound = true; - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1))); - ShowContinueError(state, EnergyPlus::format("{} not > 0.0", s_ipsc->cNumericFieldNames(11))); - } + if (matGas->gases[0].type == GasType::Custom) { + loadCustomGasProps(state, matGas, ErrorsFound, eoh); } // Nominal resistance of gap at room temperature - if (!ErrorsFound) { - DenomRGas = (matGas->gases[0].con.c0 + matGas->gases[0].con.c1 * 300.0 + matGas->gases[0].con.c2 * 90000.0); - if (DenomRGas > 0.0) { - matGas->NominalR = matGas->Thickness / DenomRGas; - } else { - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1))); - ShowContinueError( - state, - EnergyPlus::format("Nominal resistance of gap at room temperature calculated at a negative Conductivity=[{:.3R}].", DenomRGas)); - ErrorsFound = true; - } - } - } // for (Loop : W5MatEQL) + calcGasNominalR(state, matGas, ErrorsFound, eoh); + } // for (Loop : W5MatEQL) // Window gas mixtures (for gaps with two or more gases) s_ipsc->cCurrentModuleObject = "WindowMaterial:GasMixture"; @@ -1163,23 +1042,10 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumW5GasMixtures; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -1187,9 +1053,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if matGas->group = Group::GasMixture; matGas->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(matGas); - matGas->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(matGas->Name, matGas->Num); + registerMaterial(state, matGas); matGas->gases[0].type = matGas->gases[1].type = matGas->gases[2].type = matGas->gases[3].type = matGas->gases[4].type = GasType::Invalid; @@ -1235,33 +1099,18 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumShades; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } auto *mat = new MaterialShade; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->Roughness = SurfaceRoughness::MediumRough; mat->Trans = s_ipsc->rNumericArgs(1); @@ -1289,23 +1138,9 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->NominalR = 1.0; } - if (s_ipsc->rNumericArgs(1) + s_ipsc->rNumericArgs(2) >= 1.0) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(1) + " + " + s_ipsc->cNumericFieldNames(2) + " not < 1.0"); - } - - if (s_ipsc->rNumericArgs(3) + s_ipsc->rNumericArgs(4) >= 1.0) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(3) + " + " + s_ipsc->cNumericFieldNames(4) + " not < 1.0"); - } - - if (s_ipsc->rNumericArgs(5) + s_ipsc->rNumericArgs(6) >= 1.0) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(5) + " + " + s_ipsc->cNumericFieldNames(6) + " not < 1.0"); - } + checkFieldSumLessThan(state, ErrorsFound, 1, 2); + checkFieldSumLessThan(state, ErrorsFound, 3, 4); + checkFieldSumLessThan(state, ErrorsFound, 5, 6); } // Window Shade Materials @@ -1317,24 +1152,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if s_ipsc->rNumericArgs = 0; // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -1342,9 +1164,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->group = Group::ShadeEQL; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->Roughness = SurfaceRoughness::MediumRough; mat->ROnly = true; @@ -1367,34 +1187,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->AbsorpThermalBack = mat->TAR.IR.Bk.Emi; mat->TransThermal = mat->TAR.IR.Ft.Tra; - if (s_ipsc->rNumericArgs(1) + s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(4) >= 1.0) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError( - state, s_ipsc->cNumericFieldNames(1) + " + " + s_ipsc->cNumericFieldNames(2) + " + " + s_ipsc->cNumericFieldNames(4) + "not < 1.0"); - } - if (s_ipsc->rNumericArgs(1) + s_ipsc->rNumericArgs(3) + s_ipsc->rNumericArgs(5) >= 1.0) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError( - state, s_ipsc->cNumericFieldNames(1) + " + " + s_ipsc->cNumericFieldNames(3) + " + " + s_ipsc->cNumericFieldNames(5) + "not < 1.0"); - } - if (s_ipsc->rNumericArgs(6) + s_ipsc->rNumericArgs(7) + s_ipsc->rNumericArgs(8) >= 1.0) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError( - state, s_ipsc->cNumericFieldNames(6) + " + " + s_ipsc->cNumericFieldNames(7) + " + " + s_ipsc->cNumericFieldNames(8) + "not < 1.0"); - } - if (s_ipsc->rNumericArgs(9) + s_ipsc->rNumericArgs(10) >= 1.0) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " + " + s_ipsc->cNumericFieldNames(10) + " not < 1.0"); - } - if (s_ipsc->rNumericArgs(9) + s_ipsc->rNumericArgs(11) >= 1.0) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " + " + s_ipsc->cNumericFieldNames(11) + " not < 1.0"); - } + checkFieldSumLessThan3(state, ErrorsFound, 1, 2, 4); + checkFieldSumLessThan3(state, ErrorsFound, 1, 3, 5); + checkFieldSumLessThan3(state, ErrorsFound, 6, 7, 8); + checkFieldSumLessThan(state, ErrorsFound, 9, 10); + checkFieldSumLessThan(state, ErrorsFound, 9, 11); } // TotShadesEQL loop @@ -1407,24 +1204,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if s_ipsc->rNumericArgs = 0; // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -1432,9 +1216,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->group = Group::DrapeEQL; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->Roughness = SurfaceRoughness::MediumRough; mat->ROnly = true; @@ -1468,12 +1250,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if } else { mat->isPleated = false; } - if (s_ipsc->rNumericArgs(1) + s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(4) >= 1.0) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError( - state, s_ipsc->cNumericFieldNames(1) + " + " + s_ipsc->cNumericFieldNames(2) + " + " + s_ipsc->cNumericFieldNames(4) + "not < 1.0"); - } + checkFieldSumLessThan3(state, ErrorsFound, 1, 2, 4); if (s_ipsc->rNumericArgs(6) + s_ipsc->rNumericArgs(7) + s_ipsc->rNumericArgs(8) >= 1.0) { ErrorsFound = true; ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); @@ -1495,33 +1272,18 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumScreens; ++Loop) { // Call GetObjectItem routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } auto *matScreen = new MaterialScreen; matScreen->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(matScreen); - matScreen->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(matScreen->Name, matScreen->Num); + registerMaterial(state, matScreen); // Load the material derived type from the input data. @@ -1592,29 +1354,10 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if ShowContinueError(state, s_ipsc->cNumericFieldNames(7) + " must be greater than or equal to 0.001 and less than or equal to 1."); } - matScreen->topOpeningMult = s_ipsc->rNumericArgs(8); - if (matScreen->topOpeningMult < 0.0 || matScreen->topOpeningMult > 1.0) { - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(8) + " must be greater than or equal to 0 and less than or equal to 1."); - } - - matScreen->bottomOpeningMult = s_ipsc->rNumericArgs(9); - if (matScreen->bottomOpeningMult < 0.0 || matScreen->bottomOpeningMult > 1.0) { - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " must be greater than or equal to 0 and less than or equal to 1."); - } - - matScreen->leftOpeningMult = s_ipsc->rNumericArgs(10); - if (matScreen->leftOpeningMult < 0.0 || matScreen->leftOpeningMult > 1.0) { - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(10) + " must be greater than or equal to 0 and less than or equal to 1."); - } - - matScreen->rightOpeningMult = s_ipsc->rNumericArgs(11); - if (matScreen->rightOpeningMult < 0.0 || matScreen->rightOpeningMult > 1.0) { - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(11) + " must be greater than or equal to 0 and less than or equal to 1."); - } + readFieldAndValidateRange01(state, matScreen->topOpeningMult, 8); + readFieldAndValidateRange01(state, matScreen->bottomOpeningMult, 9); + readFieldAndValidateRange01(state, matScreen->leftOpeningMult, 10); + readFieldAndValidateRange01(state, matScreen->rightOpeningMult, 11); matScreen->mapDegResolution = s_ipsc->rNumericArgs(12); if (matScreen->mapDegResolution < 0 || matScreen->mapDegResolution > 5 || matScreen->mapDegResolution == 4) { @@ -1675,25 +1418,12 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if s_ipsc->rNumericArgs = 0; - // Call GetObjectItem routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); - + // Call GetObjectItem routine to retrieve material data + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); + ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -1701,9 +1431,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if matScreen->group = Group::ScreenEQL; matScreen->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(matScreen); - matScreen->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(matScreen->Name, matScreen->Num); + registerMaterial(state, matScreen); // Load the material derived type from the input data. // WindowMaterial:Screen:EquivalentLayer, @@ -1809,33 +1537,18 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumBlinds; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } auto *matBlind = new MaterialBlind; matBlind->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(matBlind); - matBlind->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(matBlind->Name, matBlind->Num); + registerMaterial(state, matBlind); matBlind->Roughness = SurfaceRoughness::Rough; matBlind->ROnly = true; @@ -1888,27 +1601,10 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if ShowContinueError(state, "This will allow direct beam to be transmitted when Slat angle = 0."); } - if ((s_ipsc->rNumericArgs(6) + s_ipsc->rNumericArgs(7) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(6) + " + " + s_ipsc->cNumericFieldNames(7) + " not < 1.0"); - } - if ((s_ipsc->rNumericArgs(6) + s_ipsc->rNumericArgs(8) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(6) + " + " + s_ipsc->cNumericFieldNames(8) + " not < 1.0"); - } - - if ((s_ipsc->rNumericArgs(9) + s_ipsc->rNumericArgs(10) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " + " + s_ipsc->cNumericFieldNames(10) + " not < 1.0"); - } - if ((s_ipsc->rNumericArgs(9) + s_ipsc->rNumericArgs(11) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " + " + s_ipsc->cNumericFieldNames(11) + " not < 1.0"); - } + checkFieldSumLessThan(state, ErrorsFound, 6, 7); + checkFieldSumLessThan(state, ErrorsFound, 6, 8); + checkFieldSumLessThan(state, ErrorsFound, 9, 10); + checkFieldSumLessThan(state, ErrorsFound, 9, 11); if ((s_ipsc->rNumericArgs(12) + s_ipsc->rNumericArgs(13) >= 1.0) || (s_ipsc->rNumericArgs(12) + s_ipsc->rNumericArgs(14) >= 1.0)) { ErrorsFound = true; @@ -1917,75 +1613,21 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if ShowContinueError(state, s_ipsc->cNumericFieldNames(12) + " + " + s_ipsc->cNumericFieldNames(14) + " not < 1.0"); } - if ((s_ipsc->rNumericArgs(12) + s_ipsc->rNumericArgs(13) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(12) + " + " + s_ipsc->cNumericFieldNames(13) + " not < 1.0"); - } - if ((s_ipsc->rNumericArgs(12) + s_ipsc->rNumericArgs(14) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(12) + " + " + s_ipsc->cNumericFieldNames(14) + " not < 1.0"); - } - - if ((s_ipsc->rNumericArgs(15) + s_ipsc->rNumericArgs(16) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(15) + " + " + s_ipsc->cNumericFieldNames(16) + " not < 1.0"); - } - if ((s_ipsc->rNumericArgs(15) + s_ipsc->rNumericArgs(17) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(15) + " + " + s_ipsc->cNumericFieldNames(17) + " not < 1.0"); - } + checkFieldSumLessThan(state, ErrorsFound, 12, 13); + checkFieldSumLessThan(state, ErrorsFound, 12, 14); + checkFieldSumLessThan(state, ErrorsFound, 15, 16); + checkFieldSumLessThan(state, ErrorsFound, 15, 17); // Require that beam and diffuse properties be the same - if (std::abs(s_ipsc->rNumericArgs(9) - s_ipsc->rNumericArgs(6)) > 1.e-5) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(6) + " must equal " + s_ipsc->cNumericFieldNames(9)); - } - - if (std::abs(s_ipsc->rNumericArgs(10) - s_ipsc->rNumericArgs(7)) > 1.e-5) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(7) + " must equal " + s_ipsc->cNumericFieldNames(10)); - } - - if (std::abs(s_ipsc->rNumericArgs(11) - s_ipsc->rNumericArgs(8)) > 1.e-5) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(8) + " must equal " + s_ipsc->cNumericFieldNames(11)); - } - - if (std::abs(s_ipsc->rNumericArgs(15) - s_ipsc->rNumericArgs(12)) > 1.e-5) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(12) + " must equal " + s_ipsc->cNumericFieldNames(15)); - } - - if (std::abs(s_ipsc->rNumericArgs(16) - s_ipsc->rNumericArgs(13)) > 1.e-5) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(13) + " must equal " + s_ipsc->cNumericFieldNames(16)); - } - - if (std::abs(s_ipsc->rNumericArgs(17) - s_ipsc->rNumericArgs(14)) > 1.e-5) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(14) + " must equal " + s_ipsc->cNumericFieldNames(17)); - } + checkFieldsEqual(state, ErrorsFound, 6, 9); + checkFieldsEqual(state, ErrorsFound, 7, 10); + checkFieldsEqual(state, ErrorsFound, 8, 11); + checkFieldsEqual(state, ErrorsFound, 12, 15); + checkFieldsEqual(state, ErrorsFound, 13, 16); + checkFieldsEqual(state, ErrorsFound, 14, 17); - if ((s_ipsc->rNumericArgs(18) + s_ipsc->rNumericArgs(19) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(18) + " + " + s_ipsc->cNumericFieldNames(19) + " not < 1.0"); - } - if ((s_ipsc->rNumericArgs(18) + s_ipsc->rNumericArgs(20) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination."); - ShowContinueError(state, s_ipsc->cNumericFieldNames(18) + " + " + s_ipsc->cNumericFieldNames(20) + " not < 1.0"); - } + checkFieldSumLessThan(state, ErrorsFound, 18, 19); + checkFieldSumLessThan(state, ErrorsFound, 18, 20); if (matBlind->toGlassDist < 0.5 * matBlind->SlatWidth) { ErrorsFound = true; @@ -2075,24 +1717,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumEQLBlinds; ++Loop) { // Call Input Get routine to retrieve material data - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -2100,9 +1729,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->group = Group::BlindEQL; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->Roughness = SurfaceRoughness::Rough; mat->ROnly = true; @@ -2199,26 +1826,10 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->SlatAngle = 0.0; } - if ((s_ipsc->rNumericArgs(5) + s_ipsc->rNumericArgs(7) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", Illegal value combination.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1))); - ShowContinueError(state, EnergyPlus::format("{} + {} not < 1.0", s_ipsc->cNumericFieldNames(5), s_ipsc->cNumericFieldNames(7))); - } - if ((s_ipsc->rNumericArgs(6) + s_ipsc->rNumericArgs(8) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", Illegal value combination.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1))); - ShowContinueError(state, EnergyPlus::format("{} + {} not < 1.0", s_ipsc->cNumericFieldNames(6), s_ipsc->cNumericFieldNames(8))); - } - if ((s_ipsc->rNumericArgs(9) + s_ipsc->rNumericArgs(11) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", Illegal value combination.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1))); - ShowContinueError(state, EnergyPlus::format("{} + {} not < 1.0", s_ipsc->cNumericFieldNames(9), s_ipsc->cNumericFieldNames(11))); - } - if ((s_ipsc->rNumericArgs(10) + s_ipsc->rNumericArgs(12) >= 1.0)) { - ErrorsFound = true; - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", Illegal value combination.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1))); - ShowContinueError(state, EnergyPlus::format("{} + {} not < 1.0", s_ipsc->cNumericFieldNames(10), s_ipsc->cNumericFieldNames(12))); - } + checkFieldSumLessThan(state, ErrorsFound, 5, 7); + checkFieldSumLessThan(state, ErrorsFound, 6, 8); + checkFieldSumLessThan(state, ErrorsFound, 9, 11); + checkFieldSumLessThan(state, ErrorsFound, 10, 12); } // TotBlindsEQL loop @@ -2229,24 +1840,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumEcoRoofs; ++Loop) { // Call Input Get Routine to retrieve material data from ecoroof - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -2256,9 +1854,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->group = Group::EcoRoof; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->HeightOfPlants = s_ipsc->rNumericArgs(1); mat->LAI = s_ipsc->rNumericArgs(2); @@ -2317,18 +1913,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if for (int Loop = 1; Loop <= s_mat->NumTCGlazings; ++Loop) { // Get each TCGlazings from the input processor - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; std::string nameUC = Util::makeUPPER(s_ipsc->cAlphaArgs(1)); @@ -2390,24 +1975,11 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if s_mat->NumSimpleWindows = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); for (int Loop = 1; Loop <= s_mat->NumSimpleWindows; ++Loop) { - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } @@ -2415,9 +1987,7 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->group = Group::GlassSimple; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->SimpleWindowUfactor = s_ipsc->rNumericArgs(1); mat->SimpleWindowSHGC = s_ipsc->rNumericArgs(2); @@ -2436,33 +2006,18 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if s_mat->NumW7Gaps = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); // ALLOCATE(DeflectionState(W7DeflectionStates)) for (int Loop = 1; Loop <= s_mat->NumW7Gaps; ++Loop) { - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } auto *mat = new Material::MaterialComplexWindowGap; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->group = Material::Group::ComplexWindowGap; mat->Roughness = Material::SurfaceRoughness::Rough; @@ -2500,66 +2055,25 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if // Find referenced DeflectionState object and copy field (i.e., deflected thickness) from it if (!s_ipsc->lAlphaFieldBlanks(3)) { - std::string deflectionState = "WindowGap:DeflectionState"; - auto const itInstances = s_ip->epJSON.find(deflectionState); - if (itInstances == s_ip->epJSON.end()) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)); - ErrorsFound = true; - continue; - } - - auto const &instances2 = itInstances.value(); - auto itObj = instances2.begin(); - // Can't use find here because epJSON keys are not upper-cased - for (; itObj != instances2.end(); ++itObj) { - if (Util::makeUPPER(itObj.key()) == s_ipsc->cAlphaArgs(3)) { - break; - } - } - - if (itObj == instances2.end()) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)); - ErrorsFound = true; + std::string const deflectionState = "WindowGap:DeflectionState"; + auto const *obj = findReferencedEpJSONObject(state, eoh, ErrorsFound, deflectionState, 3); + if (obj == nullptr) { continue; } - - s_ip->markObjectAsUsed(deflectionState, itObj.key()); - auto const &obj = itObj.value(); auto const &objSchemaProps = s_ip->getObjectSchemaProps(state, deflectionState); - mat->deflectedThickness = s_ip->getRealFieldValue(obj, objSchemaProps, "deflected_thickness"); + mat->deflectedThickness = s_ip->getRealFieldValue(*obj, objSchemaProps, "deflected_thickness"); } - // Find referenced SupportPillar obect and copy fields (i.e., spacing, radius) from it + // Find referenced SupportPillar object and copy fields (i.e., spacing, radius) from it if (!s_ipsc->lAlphaFieldBlanks(4)) { - std::string supportPillar = "WindowGap:SupportPillar"; - auto const itInstances = s_ip->epJSON.find(supportPillar); - if (itInstances == s_ip->epJSON.end()) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)); - ErrorsFound = true; - continue; - } - - auto const &instances3 = itInstances.value(); - - auto itObj = instances3.begin(); - // Can't use find here because epJSON keys are not upper-cased - for (; itObj != instances3.end(); ++itObj) { - if (Util::makeUPPER(itObj.key()) == s_ipsc->cAlphaArgs(4)) { - break; - } - } - - if (itObj == instances3.end()) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)); - ErrorsFound = true; + std::string const supportPillar = "WindowGap:SupportPillar"; + auto const *obj = findReferencedEpJSONObject(state, eoh, ErrorsFound, supportPillar, 4); + if (obj == nullptr) { continue; } - - s_ip->markObjectAsUsed(supportPillar, itObj.key()); - auto const &obj = itObj.value(); auto const &objSchemaProps = s_ip->getObjectSchemaProps(state, supportPillar); - mat->pillarSpacing = s_ip->getRealFieldValue(obj, objSchemaProps, "spacing"); - mat->pillarRadius = s_ip->getRealFieldValue(obj, objSchemaProps, "radius"); + mat->pillarSpacing = s_ip->getRealFieldValue(*obj, objSchemaProps, "spacing"); + mat->pillarRadius = s_ip->getRealFieldValue(*obj, objSchemaProps, "radius"); } } @@ -2567,33 +2081,18 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if s_ipsc->cCurrentModuleObject = "WindowMaterial:ComplexShade"; int TotComplexShades = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); for (int Loop = 1; Loop <= TotComplexShades; ++Loop) { - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; + if (checkDupMaterialName(state, eoh, ErrorsFound)) { continue; } auto *mat = new Material::MaterialComplexShade; mat->Name = s_ipsc->cAlphaArgs(1); - s_mat->materials.push_back(mat); - mat->Num = s_mat->materials.isize(); - s_mat->materialMap.insert_or_assign(mat->Name, mat->Num); + registerMaterial(state, mat); mat->Roughness = Material::SurfaceRoughness::Rough; mat->ROnly = true; @@ -2626,104 +2125,16 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if mat->SlatConductivity = s_ipsc->rNumericArgs(15); mat->SlatCurve = s_ipsc->rNumericArgs(16); - if (s_ipsc->rNumericArgs(1) <= 0.0) { - ErrorsFound = true; - ShowSevereCustom( - state, eoh, EnergyPlus::format("{} must be > 0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1))); - } - - if (s_ipsc->rNumericArgs(2) <= 0.0) { - ErrorsFound = true; - ShowSevereCustom( - state, eoh, EnergyPlus::format("{} must be > 0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(2), s_ipsc->rNumericArgs(2))); - } - - if ((s_ipsc->rNumericArgs(3) < 0.0) || (s_ipsc->rNumericArgs(3) > 1.0)) { - ErrorsFound = true; - ShowSevereCustom( - state, - eoh, - EnergyPlus::format("{} value must be >= 0 and <= 1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(3), s_ipsc->rNumericArgs(3))); - } - - if ((s_ipsc->rNumericArgs(4) <= 0.0) || (s_ipsc->rNumericArgs(4) > 1.0)) { - ErrorsFound = true; - ShowSevereCustom( - state, - eoh, - EnergyPlus::format("{} value must be >= 0 and <= 1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(4), s_ipsc->rNumericArgs(4))); - } - - if ((s_ipsc->rNumericArgs(5) <= 0.0) || (s_ipsc->rNumericArgs(5) > 1.0)) { - ErrorsFound = true; - ShowSevereCustom( - state, - eoh, - EnergyPlus::format("{} value must be >= 0 and <= 1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(5), s_ipsc->rNumericArgs(5))); - } - - if ((s_ipsc->rNumericArgs(6) < 0.0) || (s_ipsc->rNumericArgs(6) > 1.0)) { - ErrorsFound = true; - ShowSevereCustom( - state, - eoh, - EnergyPlus::format("{} must be >= 0 or <= 1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(6), s_ipsc->rNumericArgs(6))); - } - - if ((s_ipsc->rNumericArgs(7) < 0.0) || (s_ipsc->rNumericArgs(7) > 1.0)) { - ErrorsFound = true; - ShowSevereCustom( - state, eoh, EnergyPlus::format("{} must be >=0 or <=1, entered {:.2R}", s_ipsc->cNumericFieldNames(7), s_ipsc->rNumericArgs(7))); - } - - if ((s_ipsc->rNumericArgs(8) < 0.0) || (s_ipsc->rNumericArgs(8) > 1.0)) { - ErrorsFound = true; - ShowSevereCustom( - state, - eoh, - EnergyPlus::format("{} must be >=0 or <=1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(8), s_ipsc->rNumericArgs(8))); - } - - if ((s_ipsc->rNumericArgs(9) < 0.0) || (s_ipsc->rNumericArgs(9) > 1.0)) { - ErrorsFound = true; - ShowSevereCustom( - state, - eoh, - EnergyPlus::format("{} must be >=0 or <=1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(9), s_ipsc->rNumericArgs(9))); - } - - if ((s_ipsc->rNumericArgs(10) < 0.0) || (s_ipsc->rNumericArgs(10) > 1.0)) { - ErrorsFound = true; - ShowSevereCustom( - state, - eoh, - EnergyPlus::format("{} must be >=0 or <=1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(10), s_ipsc->rNumericArgs(10))); + checkFieldPositive(state, ErrorsFound, eoh, 1); + checkFieldPositive(state, ErrorsFound, eoh, 2); + for (int idx = 3; idx <= 10; ++idx) { + checkFieldInRange01(state, ErrorsFound, eoh, idx); } if ((mat->LayerType == TARCOGParams::TARCOGLayerType::VENETBLIND_HORIZ) || (mat->LayerType == TARCOGParams::TARCOGLayerType::VENETBLIND_VERT)) { - if (s_ipsc->rNumericArgs(11) <= 0.0) { - ErrorsFound = true; - ShowSevereCustom( - state, - eoh, - EnergyPlus::format("{} must be >0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(11), s_ipsc->rNumericArgs(11))); - } - - if (s_ipsc->rNumericArgs(12) <= 0.0) { - ErrorsFound = true; - ShowSevereCustom( - state, - eoh, - EnergyPlus::format("{} must be >0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(12), s_ipsc->rNumericArgs(12))); - } - - if (s_ipsc->rNumericArgs(13) <= 0.0) { - ErrorsFound = true; - ShowSevereCustom( - state, - eoh, - EnergyPlus::format("{} must be >0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(13), s_ipsc->rNumericArgs(13))); + for (int idx : {11, 12, 13, 15}) { + checkFieldPositive(state, ErrorsFound, eoh, idx); } if ((s_ipsc->rNumericArgs(14) < -90.0) || (s_ipsc->rNumericArgs(14) > 90.0)) { @@ -2734,14 +2145,6 @@ void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if "{} must be >=-90 and <=90, entered value = {:.2R}", s_ipsc->cNumericFieldNames(14), s_ipsc->rNumericArgs(14))); } - if (s_ipsc->rNumericArgs(15) <= 0.0) { - ErrorsFound = true; - ShowSevereCustom( - state, - eoh, - EnergyPlus::format("{} must be >0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(15), s_ipsc->rNumericArgs(15))); - } - if ((s_ipsc->rNumericArgs(16) < 0.0) || ((s_ipsc->rNumericArgs(16) > 0.0) && (s_ipsc->rNumericArgs(16) < (s_ipsc->rNumericArgs(11) / 2)))) { ErrorsFound = true; @@ -2987,18 +2390,7 @@ void GetWindowGlassSpectralData(EnergyPlusData &state, bool &ErrorsFound) // set // Name is followed by up to 450 sets of normal-incidence measured values of // [wavelength (microns), transmittance, front reflectance, back reflectance] for // wavelengths covering the short-wave solar spectrum (from about 0.25 to 2.5 microns) - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - Loop, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); + getMaterialInput(state, Loop, NumAlphas, NumNums, IOStat); ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; diff --git a/src/EnergyPlus/OutputReportTabular.cc b/src/EnergyPlus/OutputReportTabular.cc index adb4eaad58c..7e9910c1d15 100644 --- a/src/EnergyPlus/OutputReportTabular.cc +++ b/src/EnergyPlus/OutputReportTabular.cc @@ -7767,6 +7767,95 @@ void WriteTimeBinTables(EnergyPlusData &state) } } +// Fuel-source mapping entry: fuelFactorIndex into fuelfactorsused/gatherTotalsSource, +// bepsIndex into gatherTotalsBEPS, and the corresponding default source factor. +struct FuelSourceEntry +{ + int fuelFactorIdx; // index into fuelfactorsused / gatherTotalsSource + int bepsIdx; // index into gatherTotalsBEPS + Real64 OutputReportTabularData::*sourceFactor; // pointer-to-member for the default source factor +}; + +// Table of fuel-to-source mappings used by totalSourceEnergyUse / netSourceEnergyUse. +// Electricity is first so callers that skip it can start at index 1. +static constexpr int kNumFuelSourceEntries = 10; + +// Helper: accumulate source energy for fuels in the fuelSourceMap from startIdx..end. +// For each fuel, uses gatherTotalsSource when a fuel-factor schedule was used, +// otherwise falls back to gatherTotalsBEPS * default source factor. +static Real64 accumulateSourceEnergy(OutputReportTabularData const &ort, FuelSourceEntry const *map, int startIdx, int endIdx) +{ + Real64 total = 0.0; + for (int i = startIdx; i < endIdx; ++i) { + auto const &e = map[i]; + if (ort.fuelfactorsused(e.fuelFactorIdx)) { + total += ort.gatherTotalsSource(e.fuelFactorIdx); + } else { + total += ort.gatherTotalsBEPS(e.bepsIdx) * (ort.*(e.sourceFactor)); + } + } + return total; +} + +// Helper: populate a site-to-source conversion factor cell in the tableBody. +// Uses the schedule-based effective factor when a fuel factor schedule is in use, +// the default source factor otherwise, or "N/A" when the BEPS total is negligible. +static void fillSourceConversionCell(OutputReportTabularData const &ort, + Array2D_string &tableBody, + bool formatReals, + int ffSchedIdx, + int bepsIdx, + int tableRow, + Real64 defaultFactor, + Real64 SmallValue) +{ + if (!ort.ffSchedUsed(ffSchedIdx)) { + tableBody(1, tableRow) = RealToStr(formatReals, defaultFactor, 3); + } else if (ort.gatherTotalsBEPS(bepsIdx) > SmallValue) { + tableBody(1, tableRow) = + "Effective Factor = " + RealToStr(formatReals, ort.gatherTotalsBySourceBEPS(bepsIdx) / ort.gatherTotalsBEPS(bepsIdx), 3) + + " (calculated using schedule \"" + ort.ffScheds(bepsIdx)->Name + "\")"; + } else { + tableBody(1, tableRow) = "N/A"; + } +} + +// Helper: emit a BEPS sub-table to all active output targets (tabular, SQLite, JSON). +// When subtitle is non-empty WriteSubtitle is called before WriteTable. +static void writeBEPSSubtable(EnergyPlusData &state, + Array2D_string &tableBody, + Array1D_string &rowHead, + Array1D_string &columnHead, + Array1D_int &columnWidth, + tabularReportStyle const ¤tStyle, + std::string const &subtitle, + bool transposeXML = false, + std::string_view footnote = {}) +{ + auto const &ort = state.dataOutRptTab; + if (!ort->displayTabularBEPS) { + return; + } + if (currentStyle.produceTabular) { + if (!subtitle.empty()) { + WriteSubtitle(state, subtitle); + } + WriteTable(state, tableBody, rowHead, columnHead, columnWidth, transposeXML, footnote); + } + if (currentStyle.produceSQLite) { + if (state.dataSQLiteProcedures->sqlite) { + state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords( + tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", subtitle); + } + } + if (currentStyle.produceJSON) { + if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) { + state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable( + tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", subtitle); + } + } +} + void WriteBEPSTable(EnergyPlusData &state) { // SUBROUTINE INFORMATION: @@ -7856,38 +7945,21 @@ void WriteBEPSTable(EnergyPlusData &state) // determine building floor areas DetermineBuildingFloorArea(state); + // Resource index mapping: collapsed display index (1-14) -> gather BEPS source index. + // Order: electricity, natural gas, gasoline, diesel, coal, fuel oil 1, fuel oil 2, + // propane, otherfuel1, otherfuel2, dist cooling, dist heat water, dist heat steam, water + static constexpr std::array gatherIdx = {1, 2, 6, 8, 9, 10, 11, 12, 13, 14, 3, 4, 5, 7}; + // collapse the gatherEndUseBEPS array to the resource groups displayed for (int jEndUse = 1; jEndUse <= static_cast(Constant::EndUse::Num); ++jEndUse) { - collapsedEndUse(1, jEndUse) = ort->gatherEndUseBEPS(1, jEndUse); // electricity - collapsedEndUse(2, jEndUse) = ort->gatherEndUseBEPS(2, jEndUse); // natural gas - collapsedEndUse(3, jEndUse) = ort->gatherEndUseBEPS(6, jEndUse); // gasoline - collapsedEndUse(4, jEndUse) = ort->gatherEndUseBEPS(8, jEndUse); // diesel - collapsedEndUse(5, jEndUse) = ort->gatherEndUseBEPS(9, jEndUse); // coal - collapsedEndUse(6, jEndUse) = ort->gatherEndUseBEPS(10, jEndUse); // Fuel Oil No1 - collapsedEndUse(7, jEndUse) = ort->gatherEndUseBEPS(11, jEndUse); // Fuel Oil No2 - collapsedEndUse(8, jEndUse) = ort->gatherEndUseBEPS(12, jEndUse); // propane - collapsedEndUse(9, jEndUse) = ort->gatherEndUseBEPS(13, jEndUse); // otherfuel1 - collapsedEndUse(10, jEndUse) = ort->gatherEndUseBEPS(14, jEndUse); // otherfuel2 - collapsedEndUse(11, jEndUse) = ort->gatherEndUseBEPS(3, jEndUse); // district cooling <- purchased cooling - collapsedEndUse(12, jEndUse) = ort->gatherEndUseBEPS(4, jEndUse); // district heating water <- purchased heating - collapsedEndUse(13, jEndUse) = ort->gatherEndUseBEPS(5, jEndUse); // district heating steam <- purchased heating - collapsedEndUse(14, jEndUse) = ort->gatherEndUseBEPS(7, jEndUse); // water + for (int iRes = 0; iRes < 14; ++iRes) { + collapsedEndUse(iRes + 1, jEndUse) = ort->gatherEndUseBEPS(gatherIdx[iRes], jEndUse); + } } // repeat with totals - collapsedTotal(1) = ort->gatherTotalsBEPS(1); // electricity - collapsedTotal(2) = ort->gatherTotalsBEPS(2); // natural gas - collapsedTotal(3) = ort->gatherTotalsBEPS(6); // gasoline - collapsedTotal(4) = ort->gatherTotalsBEPS(8); // diesel - collapsedTotal(5) = ort->gatherTotalsBEPS(9); // coal - collapsedTotal(6) = ort->gatherTotalsBEPS(10); // Fuel Oil No1 - collapsedTotal(7) = ort->gatherTotalsBEPS(11); // Fuel Oil No2 - collapsedTotal(8) = ort->gatherTotalsBEPS(12); // propane - collapsedTotal(9) = ort->gatherTotalsBEPS(13); // other fuel 1 - collapsedTotal(10) = ort->gatherTotalsBEPS(14); // other fuel 2 - collapsedTotal(11) = ort->gatherTotalsBEPS(3); // district cooling <- purchased cooling - collapsedTotal(12) = ort->gatherTotalsBEPS(4); // district heating water <- purchased heating - collapsedTotal(13) = ort->gatherTotalsBEPS(5); // district heating steam <- purchased heating - collapsedTotal(14) = ort->gatherTotalsBEPS(7); // water + for (int iRes = 0; iRes < 14; ++iRes) { + collapsedTotal(iRes + 1) = ort->gatherTotalsBEPS(gatherIdx[iRes]); + } if (currentStyle.produceTabular) { if (state.dataGlobal->createPerfLog) { @@ -7919,42 +7991,15 @@ void WriteBEPSTable(EnergyPlusData &state) } for (int jEndUse = 1; jEndUse <= static_cast(Constant::EndUse::Num); ++jEndUse) { for (int kEndUseSub = 1; kEndUseSub <= op->EndUseCategory(jEndUse).NumSubcategories; ++kEndUseSub) { - collapsedEndUseSub(kEndUseSub, jEndUse, 1) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 1); // electricity - collapsedEndUseSub(kEndUseSub, jEndUse, 2) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 2); // natural gas - collapsedEndUseSub(kEndUseSub, jEndUse, 3) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 6); // gasoline - collapsedEndUseSub(kEndUseSub, jEndUse, 4) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 8); // diesel - collapsedEndUseSub(kEndUseSub, jEndUse, 5) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 9); // coal - collapsedEndUseSub(kEndUseSub, jEndUse, 6) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 10); // Fuel Oil No1 - collapsedEndUseSub(kEndUseSub, jEndUse, 7) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 11); // Fuel Oil No2 - collapsedEndUseSub(kEndUseSub, jEndUse, 8) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 12); // propane - collapsedEndUseSub(kEndUseSub, jEndUse, 9) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 13); // otherfuel1 - collapsedEndUseSub(kEndUseSub, jEndUse, 10) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 14); // otherfuel2 - collapsedEndUseSub(kEndUseSub, jEndUse, 11) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 3); // district cooling <- purch cooling - collapsedEndUseSub(kEndUseSub, jEndUse, 12) = - ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 4); // district heating water <- purch heating - collapsedEndUseSub(kEndUseSub, jEndUse, 13) = - ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 5); // district heating steam <- purch heating - collapsedEndUseSub(kEndUseSub, jEndUse, 14) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, 7); // water + for (int iRes = 0; iRes < 14; ++iRes) { + collapsedEndUseSub(kEndUseSub, jEndUse, iRes + 1) = ort->gatherEndUseSubBEPS(kEndUseSub, jEndUse, gatherIdx[iRes]); + } } for (int kEndUseSpType = 1; kEndUseSpType <= op->EndUseCategory(jEndUse).numSpaceTypes; ++kEndUseSpType) { - collapsedEndUseSpType(kEndUseSpType, jEndUse, 1) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 1); // electricity - collapsedEndUseSpType(kEndUseSpType, jEndUse, 2) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 2); // natural gas - collapsedEndUseSpType(kEndUseSpType, jEndUse, 3) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 6); // gasoline - collapsedEndUseSpType(kEndUseSpType, jEndUse, 4) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 8); // diesel - collapsedEndUseSpType(kEndUseSpType, jEndUse, 5) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 9); // coal - collapsedEndUseSpType(kEndUseSpType, jEndUse, 6) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 10); // Fuel Oil No1 - collapsedEndUseSpType(kEndUseSpType, jEndUse, 7) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 11); // Fuel Oil No2 - collapsedEndUseSpType(kEndUseSpType, jEndUse, 8) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 12); // propane - collapsedEndUseSpType(kEndUseSpType, jEndUse, 9) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 13); // otherfuel1 - collapsedEndUseSpType(kEndUseSpType, jEndUse, 10) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 14); // otherfuel2 - collapsedEndUseSpType(kEndUseSpType, jEndUse, 11) = - ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 3); // district cooling <- purch cooling - collapsedEndUseSpType(kEndUseSpType, jEndUse, 12) = - ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 4); // district heating water <- purch heating - collapsedEndUseSpType(kEndUseSpType, jEndUse, 13) = - ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 5); // district heating steam <- purch heating - collapsedEndUseSpType(kEndUseSpType, jEndUse, 14) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, 7); // water + for (int iRes = 0; iRes < 14; ++iRes) { + collapsedEndUseSpType(kEndUseSpType, jEndUse, iRes + 1) = ort->gatherEndUseSpTypeBEPS(kEndUseSpType, jEndUse, gatherIdx[iRes]); + } } } // unit conversion - all values are used as divisors @@ -8136,67 +8181,22 @@ void WriteBEPSTable(EnergyPlusData &state) } // source emissions already have the source factors included in the calcs. - Real64 totalSourceEnergyUse = 0.0; - // electricity - if (ort->fuelfactorsused(1)) { - totalSourceEnergyUse += ort->gatherTotalsSource(1); - } else { - totalSourceEnergyUse += ort->gatherTotalsBEPS(1) * ort->sourceFactorElectric; - } - // natural gas - if (ort->fuelfactorsused(2)) { - totalSourceEnergyUse += ort->gatherTotalsSource(2); - } else { - totalSourceEnergyUse += ort->gatherTotalsBEPS(2) * ort->sourceFactorNaturalGas; - } - // gasoline - if (ort->fuelfactorsused(3)) { - totalSourceEnergyUse += ort->gatherTotalsSource(3); - } else { - totalSourceEnergyUse += ort->gatherTotalsBEPS(6) * ort->sourceFactorGasoline; - } - // diesel - if (ort->fuelfactorsused(4)) { - totalSourceEnergyUse += ort->gatherTotalsSource(4); - } else { - totalSourceEnergyUse += ort->gatherTotalsBEPS(8) * ort->sourceFactorDiesel; - } - // coal - if (ort->fuelfactorsused(5)) { - totalSourceEnergyUse += ort->gatherTotalsSource(5); - } else { - totalSourceEnergyUse += ort->gatherTotalsBEPS(9) * ort->sourceFactorCoal; - } - // Fuel Oil No1 - if (ort->fuelfactorsused(6)) { - totalSourceEnergyUse += ort->gatherTotalsSource(6); - } else { - totalSourceEnergyUse += ort->gatherTotalsBEPS(10) * ort->sourceFactorFuelOil1; - } - // Fuel Oil No2 - if (ort->fuelfactorsused(7)) { - totalSourceEnergyUse += ort->gatherTotalsSource(7); - } else { - totalSourceEnergyUse += ort->gatherTotalsBEPS(11) * ort->sourceFactorFuelOil2; - } - // propane - if (ort->fuelfactorsused(8)) { - totalSourceEnergyUse += ort->gatherTotalsSource(8); - } else { - totalSourceEnergyUse += ort->gatherTotalsBEPS(12) * ort->sourceFactorPropane; - } - // otherfuel1 - if (ort->fuelfactorsused(11)) { - totalSourceEnergyUse += ort->gatherTotalsSource(11); - } else { - totalSourceEnergyUse += ort->gatherTotalsBEPS(13) * ort->sourceFactorOtherFuel1; - } - // otherfuel2 - if (ort->fuelfactorsused(12)) { - totalSourceEnergyUse += ort->gatherTotalsSource(12); - } else { - totalSourceEnergyUse += ort->gatherTotalsBEPS(14) * ort->sourceFactorOtherFuel2; - } + // Fuel-source mapping: {fuelFactorIdx, bepsIdx, &sourceFactor}. + // Electricity is index 0; callers that skip it start at index 1. + static const FuelSourceEntry fuelSourceMap[kNumFuelSourceEntries] = { + {1, 1, &OutputReportTabularData::sourceFactorElectric}, + {2, 2, &OutputReportTabularData::sourceFactorNaturalGas}, + {3, 6, &OutputReportTabularData::sourceFactorGasoline}, + {4, 8, &OutputReportTabularData::sourceFactorDiesel}, + {5, 9, &OutputReportTabularData::sourceFactorCoal}, + {6, 10, &OutputReportTabularData::sourceFactorFuelOil1}, + {7, 11, &OutputReportTabularData::sourceFactorFuelOil2}, + {8, 12, &OutputReportTabularData::sourceFactorPropane}, + {11, 13, &OutputReportTabularData::sourceFactorOtherFuel1}, + {12, 14, &OutputReportTabularData::sourceFactorOtherFuel2}, + }; + // totalSourceEnergyUse: all 10 fuels (electricity through otherfuel2) + Real64 totalSourceEnergyUse = accumulateSourceEnergy(*ort, fuelSourceMap, 0, kNumFuelSourceEntries); totalSourceEnergyUse = (totalSourceEnergyUse + ort->gatherTotalsBEPS(3) * ort->sourceFactorElectric / ort->efficiencyDistrictCooling + ort->gatherTotalsBEPS(4) * ort->sourceFactorNaturalGas / ort->efficiencyDistrictHeatingWater + @@ -8212,61 +8212,8 @@ void WriteBEPSTable(EnergyPlusData &state) netSourceElecPurchasedSold = netElecPurchasedSold * ort->sourceFactorElectric * largeConversionFactor; // back to J } - Real64 netSourceEnergyUse = 0.0; - // natural gas - if (ort->fuelfactorsused(2)) { - netSourceEnergyUse += ort->gatherTotalsSource(2); - } else { - netSourceEnergyUse += ort->gatherTotalsBEPS(2) * ort->sourceFactorNaturalGas; - } - // gasoline - if (ort->fuelfactorsused(3)) { - netSourceEnergyUse += ort->gatherTotalsSource(3); - } else { - netSourceEnergyUse += ort->gatherTotalsBEPS(6) * ort->sourceFactorGasoline; - } - // diesel - if (ort->fuelfactorsused(4)) { - netSourceEnergyUse += ort->gatherTotalsSource(4); - } else { - netSourceEnergyUse += ort->gatherTotalsBEPS(8) * ort->sourceFactorDiesel; - } - // coal - if (ort->fuelfactorsused(5)) { - netSourceEnergyUse += ort->gatherTotalsSource(5); - } else { - netSourceEnergyUse += ort->gatherTotalsBEPS(9) * ort->sourceFactorCoal; - } - // Fuel Oil No1 - if (ort->fuelfactorsused(6)) { - netSourceEnergyUse += ort->gatherTotalsSource(6); - } else { - netSourceEnergyUse += ort->gatherTotalsBEPS(10) * ort->sourceFactorFuelOil1; - } - // Fuel Oil No2 - if (ort->fuelfactorsused(7)) { - netSourceEnergyUse += ort->gatherTotalsSource(7); - } else { - netSourceEnergyUse += ort->gatherTotalsBEPS(11) * ort->sourceFactorFuelOil2; - } - // propane - if (ort->fuelfactorsused(8)) { - netSourceEnergyUse += ort->gatherTotalsSource(8); - } else { - netSourceEnergyUse += ort->gatherTotalsBEPS(12) * ort->sourceFactorPropane; - } - // otherfuel1 - if (ort->fuelfactorsused(11)) { - netSourceEnergyUse += ort->gatherTotalsSource(11); - } else { - netSourceEnergyUse += ort->gatherTotalsBEPS(13) * ort->sourceFactorOtherFuel1; - } - // otherfuel2 - if (ort->fuelfactorsused(12)) { - netSourceEnergyUse += ort->gatherTotalsSource(12); - } else { - netSourceEnergyUse += ort->gatherTotalsBEPS(14) * ort->sourceFactorOtherFuel2; - } + // netSourceEnergyUse: fuels 2-10 (skip electricity, which is handled via netSourceElecPurchasedSold) + Real64 netSourceEnergyUse = accumulateSourceEnergy(*ort, fuelSourceMap, 1, kNumFuelSourceEntries); netSourceEnergyUse = (netSourceEnergyUse + netSourceElecPurchasedSold + ort->gatherTotalsBEPS(3) * ort->sourceFactorElectric / ort->efficiencyDistrictCooling + @@ -8301,24 +8248,7 @@ void WriteBEPSTable(EnergyPlusData &state) } // heading for the entire sub-table - if (ort->displayTabularBEPS) { - if (currentStyle.produceTabular) { - WriteSubtitle(state, "Site and Source Energy"); - WriteTable(state, tableBody, rowHead, columnHead, columnWidth); - } - if (currentStyle.produceSQLite) { - if (state.dataSQLiteProcedures->sqlite) { - state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "Site and Source Energy"); - } - } - if (currentStyle.produceJSON) { - if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) { - state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "Site and Source Energy"); - } - } - } + writeBEPSSubtable(state, tableBody, rowHead, columnHead, columnWidth, currentStyle, "Site and Source Energy"); //---- Source and Site Energy Sub-Table rowHead.allocate(13); @@ -8359,140 +8289,25 @@ void WriteBEPSTable(EnergyPlusData &state) // tableBody(10,1) = TRIM(RealToStr(currentStyle.formatReals, sourceFactorFuelOil2 ,3)) // tableBody(11,1) = TRIM(RealToStr(currentStyle.formatReals, sourceFactorPropane ,3)) - if (!ort->ffSchedUsed(1)) { - tableBody(1, 1) = RealToStr(currentStyle.formatReals, ort->sourceFactorElectric, 3); - } else if (ort->gatherTotalsBEPS(1) > SmallValue) { - tableBody(1, 1) = - "Effective Factor = " + RealToStr(currentStyle.formatReals, ort->gatherTotalsBySourceBEPS(1) / ort->gatherTotalsBEPS(1), 3) + - " (calculated using schedule \"" + ort->ffScheds(1)->Name + "\")"; - } else { - tableBody(1, 1) = "N/A"; - } - - if (!ort->ffSchedUsed(2)) { - tableBody(1, 2) = RealToStr(currentStyle.formatReals, ort->sourceFactorNaturalGas, 3); - } else if (ort->gatherTotalsBEPS(2) > SmallValue) { - tableBody(1, 2) = - "Effective Factor = " + RealToStr(currentStyle.formatReals, ort->gatherTotalsBySourceBEPS(2) / ort->gatherTotalsBEPS(2), 3) + - " (calculated using schedule \"" + ort->ffScheds(2)->Name + "\")"; - } else { - tableBody(1, 2) = "N/A"; - } + fillSourceConversionCell(*ort, tableBody, currentStyle.formatReals, 1, 1, 1, ort->sourceFactorElectric, SmallValue); + fillSourceConversionCell(*ort, tableBody, currentStyle.formatReals, 2, 2, 2, ort->sourceFactorNaturalGas, SmallValue); tableBody(1, 3) = RealToStr(currentStyle.formatReals, ort->sourceFactorElectric / ort->efficiencyDistrictCooling, 3); // District Cooling - tableBody(1, 4) = RealToStr(currentStyle.formatReals, ort->sourceFactorNaturalGas / ort->efficiencyDistrictHeatingWater, 3); // District Heating Water + tableBody(1, 5) = RealToStr(currentStyle.formatReals, ort->sourceFactorDistrictHeatingSteam, 3); // District Heating Steam - tableBody(1, 5) = RealToStr(currentStyle.formatReals, ort->sourceFactorDistrictHeatingSteam, 3); // District Heating Steam - - if (!ort->ffSchedUsed(6)) { - tableBody(1, 6) = RealToStr(currentStyle.formatReals, ort->sourceFactorGasoline, 3); - } else if (ort->gatherTotalsBEPS(6) > SmallValue) { - tableBody(1, 6) = - "Effective Factor = " + RealToStr(currentStyle.formatReals, ort->gatherTotalsBySourceBEPS(6) / ort->gatherTotalsBEPS(6), 3) + - " (calculated using schedule \"" + ort->ffScheds(6)->Name + "\")"; - } else { - tableBody(1, 6) = "N/A"; - } - - if (!ort->ffSchedUsed(8)) { - tableBody(1, 7) = RealToStr(currentStyle.formatReals, ort->sourceFactorDiesel, 3); - } else if (ort->gatherTotalsBEPS(8) > SmallValue) { - tableBody(1, 7) = - "Effective Factor = " + RealToStr(currentStyle.formatReals, ort->gatherTotalsBySourceBEPS(8) / ort->gatherTotalsBEPS(8), 3) + - " (calculated using schedule \"" + ort->ffScheds(8)->Name + "\")"; - } else { - tableBody(1, 7) = "N/A"; - } - - if (!ort->ffSchedUsed(9)) { - tableBody(1, 8) = RealToStr(currentStyle.formatReals, ort->sourceFactorCoal, 3); - } else if (ort->gatherTotalsBEPS(9) > SmallValue) { - tableBody(1, 8) = - "Effective Factor = " + RealToStr(currentStyle.formatReals, ort->gatherTotalsBySourceBEPS(9) / ort->gatherTotalsBEPS(9), 3) + - " (calculated using schedule \"" + ort->ffScheds(9)->Name + "\")"; - } else { - tableBody(1, 8) = "N/A"; - } - - if (!ort->ffSchedUsed(10)) { - tableBody(1, 9) = RealToStr(currentStyle.formatReals, ort->sourceFactorFuelOil1, 3); - } else if (ort->gatherTotalsBEPS(10) > SmallValue) { - tableBody(1, 9) = - "Effective Factor = " + RealToStr(currentStyle.formatReals, ort->gatherTotalsBySourceBEPS(10) / ort->gatherTotalsBEPS(10), 3) + - " (calculated using schedule \"" + ort->ffScheds(10)->Name + "\")"; - } else { - tableBody(1, 9) = "N/A"; - } - - if (!ort->ffSchedUsed(11)) { - tableBody(1, 10) = RealToStr(currentStyle.formatReals, ort->sourceFactorFuelOil2, 3); - } else if (ort->gatherTotalsBEPS(11) > SmallValue) { - tableBody(1, 10) = - "Effective Factor = " + RealToStr(currentStyle.formatReals, ort->gatherTotalsBySourceBEPS(11) / ort->gatherTotalsBEPS(11), 3) + - " (calculated using schedule \"" + ort->ffScheds(11)->Name + "\")"; - } else { - tableBody(1, 10) = "N/A"; - } - - if (!ort->ffSchedUsed(12)) { - tableBody(1, 11) = RealToStr(currentStyle.formatReals, ort->sourceFactorPropane, 3); - } else if (ort->gatherTotalsBEPS(12) > SmallValue) { - tableBody(1, 11) = - "Effective Factor = " + RealToStr(currentStyle.formatReals, ort->gatherTotalsBySourceBEPS(12) / ort->gatherTotalsBEPS(12), 3) + - " (calculated using schedule \"" + ort->ffScheds(12)->Name + "\")"; - } else { - tableBody(1, 11) = "N/A"; - } - - if (!ort->ffSchedUsed(13)) { - tableBody(1, 12) = RealToStr(currentStyle.formatReals, ort->sourceFactorOtherFuel1, 3); - } else if (ort->gatherTotalsBEPS(13) > SmallValue) { - tableBody(1, 12) = - "Effective Factor = " + RealToStr(currentStyle.formatReals, ort->gatherTotalsBySourceBEPS(13) / ort->gatherTotalsBEPS(13), 3) + - " (calculated using schedule \"" + ort->ffScheds(13)->Name + "\")"; - } else { - tableBody(1, 12) = "N/A"; - } - - if (!ort->ffSchedUsed(14)) { - tableBody(1, 13) = RealToStr(currentStyle.formatReals, ort->sourceFactorOtherFuel2, 3); - } else if (ort->gatherTotalsBEPS(14) > SmallValue) { - tableBody(1, 13) = - "Effective Factor = " + RealToStr(currentStyle.formatReals, ort->gatherTotalsBySourceBEPS(14) / ort->gatherTotalsBEPS(14), 3) + - " (calculated using schedule \"" + ort->ffScheds(14)->Name + "\")"; - } else { - tableBody(1, 13) = "N/A"; - } + fillSourceConversionCell(*ort, tableBody, currentStyle.formatReals, 6, 6, 6, ort->sourceFactorGasoline, SmallValue); + fillSourceConversionCell(*ort, tableBody, currentStyle.formatReals, 8, 8, 7, ort->sourceFactorDiesel, SmallValue); + fillSourceConversionCell(*ort, tableBody, currentStyle.formatReals, 9, 9, 8, ort->sourceFactorCoal, SmallValue); + fillSourceConversionCell(*ort, tableBody, currentStyle.formatReals, 10, 10, 9, ort->sourceFactorFuelOil1, SmallValue); + fillSourceConversionCell(*ort, tableBody, currentStyle.formatReals, 11, 11, 10, ort->sourceFactorFuelOil2, SmallValue); + fillSourceConversionCell(*ort, tableBody, currentStyle.formatReals, 12, 12, 11, ort->sourceFactorPropane, SmallValue); + fillSourceConversionCell(*ort, tableBody, currentStyle.formatReals, 13, 13, 12, ort->sourceFactorOtherFuel1, SmallValue); + fillSourceConversionCell(*ort, tableBody, currentStyle.formatReals, 14, 14, 13, ort->sourceFactorOtherFuel2, SmallValue); // heading for the entire sub-table - if (ort->displayTabularBEPS) { - if (currentStyle.produceTabular) { - WriteSubtitle(state, "Site to Source Energy Conversion Factors"); - WriteTable(state, tableBody, rowHead, columnHead, columnWidth); - } - if (currentStyle.produceSQLite) { - if (state.dataSQLiteProcedures->sqlite) { - state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(tableBody, - rowHead, - columnHead, - "AnnualBuildingUtilityPerformanceSummary", - "Entire Facility", - "Site to Source Energy Conversion Factors"); - } - } - if (currentStyle.produceJSON) { - if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) { - state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(tableBody, - rowHead, - columnHead, - "AnnualBuildingUtilityPerformanceSummary", - "Entire Facility", - "Site to Source Energy Conversion Factors"); - } - } - } + writeBEPSSubtable(state, tableBody, rowHead, columnHead, columnWidth, currentStyle, "Site to Source Energy Conversion Factors"); //---- Building Area Sub-Table rowHead.allocate(3); @@ -8544,24 +8359,7 @@ void WriteBEPSTable(EnergyPlusData &state) tableBody(1, 3) = RealToStr(currentStyle.formatReals, convBldgGrossFloorArea - convBldgCondFloorArea, 2); // heading for the entire sub-table - if (ort->displayTabularBEPS) { - if (currentStyle.produceTabular) { - WriteSubtitle(state, "Building Area"); - WriteTable(state, tableBody, rowHead, columnHead, columnWidth); - } - if (currentStyle.produceSQLite) { - if (state.dataSQLiteProcedures->sqlite) { - state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "Building Area"); - } - } - if (currentStyle.produceJSON) { - if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) { - state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "Building Area"); - } - } - } + writeBEPSSubtable(state, tableBody, rowHead, columnHead, columnWidth, currentStyle, "Building Area"); //---- End Use Sub-Table rowHead.allocate(16); @@ -8957,24 +8755,7 @@ void WriteBEPSTable(EnergyPlusData &state) } break; } // heading for the entire sub-table - if (ort->displayTabularBEPS) { - if (currentStyle.produceTabular) { - WriteSubtitle(state, "End Uses"); - WriteTable(state, tableBody, rowHead, columnHead, columnWidth, false, footnote); - } - if (currentStyle.produceSQLite) { - if (state.dataSQLiteProcedures->sqlite) { - state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "End Uses"); - } - } - if (currentStyle.produceJSON) { - if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) { - state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "End Uses"); - } - } - } + writeBEPSSubtable(state, tableBody, rowHead, columnHead, columnWidth, currentStyle, "End Uses", false, footnote); //---- End Uses By Subcategory Sub-Table writeBEPSEndUseBySubCatOrSpaceType( @@ -9163,32 +8944,7 @@ void WriteBEPSTable(EnergyPlusData &state) } } // heading for the entire sub-table - if (ort->displayTabularBEPS) { - if (currentStyle.produceTabular) { - WriteSubtitle(state, "Utility Use Per Conditioned Floor Area"); - WriteTable(state, tableBody, rowHead, columnHead, columnWidth); - } - if (currentStyle.produceSQLite) { - if (state.dataSQLiteProcedures->sqlite) { - state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(tableBody, - rowHead, - columnHead, - "AnnualBuildingUtilityPerformanceSummary", - "Entire Facility", - "Utility Use Per Conditioned Floor Area"); - } - } - if (currentStyle.produceJSON) { - if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) { - state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(tableBody, - rowHead, - columnHead, - "AnnualBuildingUtilityPerformanceSummary", - "Entire Facility", - "Utility Use Per Conditioned Floor Area"); - } - } - } + writeBEPSSubtable(state, tableBody, rowHead, columnHead, columnWidth, currentStyle, "Utility Use Per Conditioned Floor Area"); //---- Normalized by Total Area Sub-Table tableBody = ""; if (convBldgGrossFloorArea > 0) { @@ -9199,32 +8955,7 @@ void WriteBEPSTable(EnergyPlusData &state) } } // heading for the entire sub-table - if (ort->displayTabularBEPS) { - if (currentStyle.produceTabular) { - WriteSubtitle(state, "Utility Use Per Total Floor Area"); - WriteTable(state, tableBody, rowHead, columnHead, columnWidth); - } - if (currentStyle.produceSQLite) { - if (state.dataSQLiteProcedures->sqlite) { - state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(tableBody, - rowHead, - columnHead, - "AnnualBuildingUtilityPerformanceSummary", - "Entire Facility", - "Utility Use Per Total Floor Area"); - } - } - if (currentStyle.produceJSON) { - if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) { - state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(tableBody, - rowHead, - columnHead, - "AnnualBuildingUtilityPerformanceSummary", - "Entire Facility", - "Utility Use Per Total Floor Area"); - } - } - } + writeBEPSSubtable(state, tableBody, rowHead, columnHead, columnWidth, currentStyle, "Utility Use Per Total Floor Area"); //---- Electric Loads Satisfied Sub-Table rowHead.allocate(14); @@ -9307,24 +9038,7 @@ void WriteBEPSTable(EnergyPlusData &state) } // heading for the entire sub-table - if (ort->displayTabularBEPS) { - if (currentStyle.produceTabular) { - WriteSubtitle(state, "Electric Loads Satisfied"); - WriteTable(state, tableBody, rowHead, columnHead, columnWidth); - } - if (currentStyle.produceSQLite) { - if (state.dataSQLiteProcedures->sqlite) { - state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "Electric Loads Satisfied"); - } - } - if (currentStyle.produceJSON) { - if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) { - state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "Electric Loads Satisfied"); - } - } - } + writeBEPSSubtable(state, tableBody, rowHead, columnHead, columnWidth, currentStyle, "Electric Loads Satisfied"); //---- On-Site Thermal Sources Sub-Table rowHead.allocate(7); @@ -9408,24 +9122,7 @@ void WriteBEPSTable(EnergyPlusData &state) } // heading for the entire sub-table - if (ort->displayTabularBEPS) { - if (currentStyle.produceTabular) { - WriteSubtitle(state, "On-Site Thermal Sources"); - WriteTable(state, tableBody, rowHead, columnHead, columnWidth); - } - if (currentStyle.produceSQLite) { - if (state.dataSQLiteProcedures->sqlite) { - state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "On-Site Thermal Sources"); - } - } - if (currentStyle.produceJSON) { - if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) { - state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "On-Site Thermal Sources"); - } - } - } + writeBEPSSubtable(state, tableBody, rowHead, columnHead, columnWidth, currentStyle, "On-Site Thermal Sources"); //---- Water Loads Sub-Table // As of 12/8/2003 decided to not include this sub-table to wait @@ -9513,24 +9210,9 @@ void WriteBEPSTable(EnergyPlusData &state) } // ! heading for the entire sub-table - if (ort->displayTabularBEPS) { - if (currentStyle.produceTabular) { - WriteSubtitle(state, "Water Source Summary"); - WriteTable(state, tableBody, rowHead, columnHead, columnWidth); - } - if (currentStyle.produceSQLite) { - if (state.dataSQLiteProcedures->sqlite) { - state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "Water Source Summary"); - } - } - if (currentStyle.produceJSON) { - if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) { - state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable( - tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "Water Source Summary"); - } - } + writeBEPSSubtable(state, tableBody, rowHead, columnHead, columnWidth, currentStyle, "Water Source Summary"); + if (ort->displayTabularBEPS) { //---- Comfort and Setpoint Not Met Sub-Table rowHead.allocate(2); columnHead.allocate(1); @@ -9571,6 +9253,7 @@ void WriteBEPSTable(EnergyPlusData &state) currentStyle.formatReals, ConvertIPdelta(state, indexUnitConv, state.dataHVACGlobal->deviationFromSetPtThresholdClg), 2); } + // subtitle already written above; pass empty to skip, but use proper name for SQLite/JSON if (currentStyle.produceTabular) { WriteTable(state, tableBody, rowHead, columnHead, columnWidth); } diff --git a/src/EnergyPlus/PackagedThermalStorageCoil.cc b/src/EnergyPlus/PackagedThermalStorageCoil.cc index 6419c17df47..17f353b52db 100644 --- a/src/EnergyPlus/PackagedThermalStorageCoil.cc +++ b/src/EnergyPlus/PackagedThermalStorageCoil.cc @@ -186,6 +186,50 @@ void SimTESCoil(EnergyPlusData &state, } } +// Helper: look up a performance curve by alpha index, report errors if missing, and validate dimensions. +// Returns the curve index (0 if not found). Sets errorsFound on failure. +static int getAndValidateCurve(EnergyPlusData &state, + int alphaIndex, + std::initializer_list validDims, + std::string_view routineName, + std::string_view objectType, + std::string_view objectName, + bool &errorsFound) +{ + auto &ip = state.dataIPShortCut; + int curveIndex = GetCurveIndex(state, ip->cAlphaArgs(alphaIndex)); + if (curveIndex == 0) { + if (ip->lAlphaFieldBlanks(alphaIndex)) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", routineName, objectType, objectName)); + ShowContinueError(state, EnergyPlus::format("Required {}is blank.", ip->cAlphaFieldNames(alphaIndex))); + } else { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", routineName, objectType, objectName)); + ShowContinueError(state, EnergyPlus::format("Not found {}=\"{}\".", ip->cAlphaFieldNames(alphaIndex), ip->cAlphaArgs(alphaIndex))); + } + errorsFound = true; + } else { + errorsFound |= + EnergyPlus::Curve::CheckCurveDims(state, curveIndex, validDims, routineName, objectType, objectName, ip->cAlphaFieldNames(alphaIndex)); + } + return curveIndex; +} + +// Helper: parse a Yes/No alpha field into a bool, reporting an error if the value is invalid. +static bool parseModeAvailability( + EnergyPlusData &state, int alphaIndex, std::string_view routineName, std::string_view objectType, std::string_view objectName, bool &errorsFound) +{ + auto &ip = state.dataIPShortCut; + BooleanSwitch const answer = getYesNoValue(ip->cAlphaArgs(alphaIndex)); + if (answer == BooleanSwitch::Yes || answer == BooleanSwitch::No) { + return static_cast(answer); + } + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", routineName, objectType, objectName)); + ShowContinueError(state, EnergyPlus::format("...{}=\"{}\".", ip->cAlphaFieldNames(alphaIndex), ip->cAlphaArgs(alphaIndex))); + ShowContinueError(state, "Available choices are Yes or No."); + errorsFound = true; + return false; +} + void GetTESCoilInput(EnergyPlusData &state) { @@ -378,20 +422,7 @@ void GetTESCoilInput(EnergyPlusData &state) state.dataIPShortCut->cAlphaArgs(9), "Air Nodes"); - BooleanSwitch const answer = getYesNoValue(state.dataIPShortCut->cAlphaArgs(10)); - switch (answer) { - case BooleanSwitch::Yes: - case BooleanSwitch::No: - thisTESCoil.CoolingOnlyModeIsAvailable = static_cast(answer); - break; - default: - thisTESCoil.CoolingOnlyModeIsAvailable = false; - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(10), state.dataIPShortCut->cAlphaArgs(10))); - ShowContinueError(state, "Available choices are Yes or No."); - ErrorsFound = true; - } + thisTESCoil.CoolingOnlyModeIsAvailable = parseModeAvailability(state, 10, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); thisTESCoil.CoolingOnlyRatedTotCap = state.dataIPShortCut->rNumericArgs(7); if (thisTESCoil.CoolingOnlyModeIsAvailable) { // get input data for this mode @@ -399,182 +430,24 @@ void GetTESCoilInput(EnergyPlusData &state) thisTESCoil.CoolingOnlyRatedSHR = state.dataIPShortCut->rNumericArgs(8); thisTESCoil.CoolingOnlyRatedCOP = state.dataIPShortCut->rNumericArgs(9); - thisTESCoil.CoolingOnlyCapFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(11)); - if (thisTESCoil.CoolingOnlyCapFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(11)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(11))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(11), state.dataIPShortCut->cAlphaArgs(11))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingOnlyCapFTempCurve, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(11)); // Field Name - } - - thisTESCoil.CoolingOnlyCapFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(12)); - if (thisTESCoil.CoolingOnlyCapFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(12)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(12))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(12), state.dataIPShortCut->cAlphaArgs(12))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingOnlyCapFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(12)); // Field Name - } - - thisTESCoil.CoolingOnlyEIRFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(13)); - if (thisTESCoil.CoolingOnlyEIRFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(13)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(13))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(13), state.dataIPShortCut->cAlphaArgs(13))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingOnlyEIRFTempCurve, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(13)); // Field Name - } - - thisTESCoil.CoolingOnlyEIRFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(14)); - if (thisTESCoil.CoolingOnlyEIRFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(14)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(14))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(14), state.dataIPShortCut->cAlphaArgs(14))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingOnlyEIRFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(14)); // Field Name - } - - thisTESCoil.CoolingOnlyPLFFPLRCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(15)); - if (thisTESCoil.CoolingOnlyPLFFPLRCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(15)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(15))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(15), state.dataIPShortCut->cAlphaArgs(15))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingOnlyPLFFPLRCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(15)); // Field Name - } - - thisTESCoil.CoolingOnlySHRFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(16)); - if (thisTESCoil.CoolingOnlySHRFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(16)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(16))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(16), state.dataIPShortCut->cAlphaArgs(16))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingOnlySHRFTempCurve, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(16)); // Field Name - } - - thisTESCoil.CoolingOnlySHRFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(17)); - if (thisTESCoil.CoolingOnlySHRFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(17)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(17))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(17), state.dataIPShortCut->cAlphaArgs(17))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingOnlySHRFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(17)); // Field Name - } - } - - BooleanSwitch const answer2 = getYesNoValue(state.dataIPShortCut->cAlphaArgs(18)); - switch (answer2) { - case BooleanSwitch::Yes: - case BooleanSwitch::No: - thisTESCoil.CoolingAndChargeModeAvailable = static_cast(answer2); - break; - default: - thisTESCoil.CoolingAndChargeModeAvailable = false; - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(18), state.dataIPShortCut->cAlphaArgs(18))); - ShowContinueError(state, "Available choices are Yes or No."); - ErrorsFound = true; - } + thisTESCoil.CoolingOnlyCapFTempCurve = + getAndValidateCurve(state, 11, {2}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingOnlyCapFFlowCurve = + getAndValidateCurve(state, 12, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingOnlyEIRFTempCurve = + getAndValidateCurve(state, 13, {2}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingOnlyEIRFFlowCurve = + getAndValidateCurve(state, 14, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingOnlyPLFFPLRCurve = + getAndValidateCurve(state, 15, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingOnlySHRFTempCurve = + getAndValidateCurve(state, 16, {2}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingOnlySHRFFlowCurve = + getAndValidateCurve(state, 17, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + } + + thisTESCoil.CoolingAndChargeModeAvailable = + parseModeAvailability(state, 18, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); if (thisTESCoil.CoolingAndChargeModeAvailable) { @@ -589,297 +462,35 @@ void GetTESCoilInput(EnergyPlusData &state) thisTESCoil.CoolingAndChargeCoolingRatedCOP = state.dataIPShortCut->rNumericArgs(15); // Coefficient of performance , for cooling [W/W] thisTESCoil.CoolingAndChargeChargingRatedCOP = state.dataIPShortCut->rNumericArgs(16); // Coefficient of performance , for charging [W/W] - thisTESCoil.CoolingAndChargeCoolingCapFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(19)); - if (thisTESCoil.CoolingAndChargeCoolingCapFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(19)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(19))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(19), state.dataIPShortCut->cAlphaArgs(19))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeCoolingCapFTempCurve, // Curve index - {3}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(19)); // Field Name - } - - thisTESCoil.CoolingAndChargeCoolingCapFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(20)); - if (thisTESCoil.CoolingAndChargeCoolingCapFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(20)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(20))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(20), state.dataIPShortCut->cAlphaArgs(20))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeCoolingCapFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(20)); // Field Name - } - thisTESCoil.CoolingAndChargeCoolingEIRFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(21)); - if (thisTESCoil.CoolingAndChargeCoolingEIRFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(21)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(21))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(21), state.dataIPShortCut->cAlphaArgs(21))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeCoolingEIRFTempCurve, // Curve index - {3}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(21)); // Field Name - } - - thisTESCoil.CoolingAndChargeCoolingEIRFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(22)); - if (thisTESCoil.CoolingAndChargeCoolingEIRFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(22)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(22))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(22), state.dataIPShortCut->cAlphaArgs(22))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeCoolingEIRFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(22)); // Field Name - } - - thisTESCoil.CoolingAndChargeCoolingPLFFPLRCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(23)); - if (thisTESCoil.CoolingAndChargeCoolingPLFFPLRCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(23)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(23))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(23), state.dataIPShortCut->cAlphaArgs(23))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeCoolingPLFFPLRCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(23)); // Field Name - } - - thisTESCoil.CoolingAndChargeChargingCapFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(24)); - if (thisTESCoil.CoolingAndChargeChargingCapFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(24)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(24))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(24), state.dataIPShortCut->cAlphaArgs(24))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeChargingCapFTempCurve, // Curve index - {3}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(24)); // Field Name - } - - thisTESCoil.CoolingAndChargeChargingCapFEvapPLRCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(25)); - if (thisTESCoil.CoolingAndChargeChargingCapFEvapPLRCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(25)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(25))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(25), state.dataIPShortCut->cAlphaArgs(25))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeChargingCapFEvapPLRCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(25)); // Field Name - } - - thisTESCoil.CoolingAndChargeChargingEIRFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(26)); - if (thisTESCoil.CoolingAndChargeChargingEIRFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(26)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(26))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(26), state.dataIPShortCut->cAlphaArgs(26))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeChargingEIRFTempCurve, // Curve index - {3}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(26)); // Field Name - } - - thisTESCoil.CoolingAndChargeChargingEIRFFLowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(27)); - if (thisTESCoil.CoolingAndChargeChargingEIRFFLowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(27)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(27))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(27), state.dataIPShortCut->cAlphaArgs(27))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeChargingEIRFFLowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(27)); // Field Name - } - - thisTESCoil.CoolingAndChargeChargingPLFFPLRCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(28)); - if (thisTESCoil.CoolingAndChargeChargingPLFFPLRCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(28)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(28))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(28), state.dataIPShortCut->cAlphaArgs(28))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeChargingPLFFPLRCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(28)); // Field Name - } - - thisTESCoil.CoolingAndChargeSHRFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(29)); - if (thisTESCoil.CoolingAndChargeSHRFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(29)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(29))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(29), state.dataIPShortCut->cAlphaArgs(29))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeSHRFTempCurve, // Curve index - {2, 3}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(29)); // Field Name - } - - thisTESCoil.CoolingAndChargeSHRFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(30)); - if (thisTESCoil.CoolingAndChargeSHRFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(30)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(30))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(30), state.dataIPShortCut->cAlphaArgs(30))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndChargeSHRFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(30)); // Field Name - } + thisTESCoil.CoolingAndChargeCoolingCapFTempCurve = + getAndValidateCurve(state, 19, {3}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndChargeCoolingCapFFlowCurve = + getAndValidateCurve(state, 20, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndChargeCoolingEIRFTempCurve = + getAndValidateCurve(state, 21, {3}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndChargeCoolingEIRFFlowCurve = + getAndValidateCurve(state, 22, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndChargeCoolingPLFFPLRCurve = + getAndValidateCurve(state, 23, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndChargeChargingCapFTempCurve = + getAndValidateCurve(state, 24, {3}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndChargeChargingCapFEvapPLRCurve = + getAndValidateCurve(state, 25, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndChargeChargingEIRFTempCurve = + getAndValidateCurve(state, 26, {3}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndChargeChargingEIRFFLowCurve = + getAndValidateCurve(state, 27, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndChargeChargingPLFFPLRCurve = + getAndValidateCurve(state, 28, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndChargeSHRFTempCurve = + getAndValidateCurve(state, 29, {2, 3}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndChargeSHRFFlowCurve = + getAndValidateCurve(state, 30, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); } // Cooling and Charge Mode available - BooleanSwitch answer3 = getYesNoValue(state.dataIPShortCut->cAlphaArgs(31)); - switch (answer3) { - case BooleanSwitch::Yes: - case BooleanSwitch::No: - thisTESCoil.CoolingAndDischargeModeAvailable = static_cast(answer3); - break; - default: - thisTESCoil.CoolingAndDischargeModeAvailable = false; - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(31), state.dataIPShortCut->cAlphaArgs(31))); - ShowContinueError(state, "Available choices are Yes or No."); - ErrorsFound = true; - } + thisTESCoil.CoolingAndDischargeModeAvailable = + parseModeAvailability(state, 31, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); if (thisTESCoil.CoolingAndDischargeModeAvailable) { @@ -894,321 +505,37 @@ void GetTESCoilInput(EnergyPlusData &state) thisTESCoil.CoolingAndDischargeDischargingRatedCOP = state.dataIPShortCut->rNumericArgs(23); // Coefficient of performance , for charging [W/W] - thisTESCoil.CoolingAndDischargeCoolingCapFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(32)); - if (thisTESCoil.CoolingAndDischargeCoolingCapFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(32)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(32))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(32), state.dataIPShortCut->cAlphaArgs(32))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeCoolingCapFTempCurve, // Curve index - {3}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(32)); // Field Name - } - - thisTESCoil.CoolingAndDischargeCoolingCapFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(33)); - if (thisTESCoil.CoolingAndDischargeCoolingCapFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(33)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(33))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(33), state.dataIPShortCut->cAlphaArgs(33))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeCoolingCapFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(33)); // Field Name - } - - thisTESCoil.CoolingAndDischargeCoolingEIRFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(34)); - if (thisTESCoil.CoolingAndDischargeCoolingEIRFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(34)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(34))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(34), state.dataIPShortCut->cAlphaArgs(34))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeCoolingEIRFTempCurve, // Curve index - {3}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(34)); // Field Name - } - - thisTESCoil.CoolingAndDischargeCoolingEIRFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(35)); - if (thisTESCoil.CoolingAndDischargeCoolingEIRFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(35)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(35))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(35), state.dataIPShortCut->cAlphaArgs(35))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeCoolingEIRFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(35)); // Field Name - } - - thisTESCoil.CoolingAndDischargeCoolingPLFFPLRCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(36)); - if (thisTESCoil.CoolingAndDischargeCoolingPLFFPLRCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(36)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(36))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(36), state.dataIPShortCut->cAlphaArgs(36))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeCoolingPLFFPLRCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(36)); // Field Name - } - - thisTESCoil.CoolingAndDischargeDischargingCapFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(37)); - if (thisTESCoil.CoolingAndDischargeDischargingCapFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(37)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(37))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(37), state.dataIPShortCut->cAlphaArgs(37))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeDischargingCapFTempCurve, // Curve index - {3}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(37)); // Field Name - } - - thisTESCoil.CoolingAndDischargeDischargingCapFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(38)); - if (thisTESCoil.CoolingAndDischargeDischargingCapFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(38)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(38))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(38), state.dataIPShortCut->cAlphaArgs(38))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeDischargingCapFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(38)); // Field Name - } - - thisTESCoil.CoolingAndDischargeDischargingCapFEvapPLRCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(39)); - if (thisTESCoil.CoolingAndDischargeDischargingCapFEvapPLRCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(39)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(39))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(39), state.dataIPShortCut->cAlphaArgs(39))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeDischargingCapFEvapPLRCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(39)); // Field Name - } - - thisTESCoil.CoolingAndDischargeDischargingEIRFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(40)); - if (thisTESCoil.CoolingAndDischargeDischargingEIRFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(40)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(40))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(40), state.dataIPShortCut->cAlphaArgs(40))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeDischargingEIRFTempCurve, // Curve index - {3}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(40)); // Field Name - } - - thisTESCoil.CoolingAndDischargeDischargingEIRFFLowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(41)); - if (thisTESCoil.CoolingAndDischargeDischargingEIRFFLowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(41)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(41))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(41), state.dataIPShortCut->cAlphaArgs(41))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeDischargingEIRFFLowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(41)); // Field Name - } - - thisTESCoil.CoolingAndDischargeDischargingPLFFPLRCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(42)); - if (thisTESCoil.CoolingAndDischargeDischargingPLFFPLRCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(42)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(42))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(42), state.dataIPShortCut->cAlphaArgs(42))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeDischargingPLFFPLRCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(42)); // Field Name - } - - thisTESCoil.CoolingAndDischargeSHRFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(43)); - if (thisTESCoil.CoolingAndDischargeSHRFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(43)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(43))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(43), state.dataIPShortCut->cAlphaArgs(43))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeSHRFTempCurve, // Curve index - {2, 3}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(43)); // Field Name - } - - thisTESCoil.CoolingAndDischargeSHRFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(44)); - if (thisTESCoil.CoolingAndDischargeSHRFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(44)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(44))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(44), state.dataIPShortCut->cAlphaArgs(44))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.CoolingAndDischargeSHRFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(44)); // Field Name - } + thisTESCoil.CoolingAndDischargeCoolingCapFTempCurve = + getAndValidateCurve(state, 32, {3}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndDischargeCoolingCapFFlowCurve = + getAndValidateCurve(state, 33, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndDischargeCoolingEIRFTempCurve = + getAndValidateCurve(state, 34, {3}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndDischargeCoolingEIRFFlowCurve = + getAndValidateCurve(state, 35, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + + thisTESCoil.CoolingAndDischargeCoolingPLFFPLRCurve = + getAndValidateCurve(state, 36, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndDischargeDischargingCapFTempCurve = + getAndValidateCurve(state, 37, {3}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndDischargeDischargingCapFFlowCurve = + getAndValidateCurve(state, 38, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndDischargeDischargingCapFEvapPLRCurve = + getAndValidateCurve(state, 39, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndDischargeDischargingEIRFTempCurve = + getAndValidateCurve(state, 40, {3}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndDischargeDischargingEIRFFLowCurve = + getAndValidateCurve(state, 41, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndDischargeDischargingPLFFPLRCurve = + getAndValidateCurve(state, 42, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndDischargeSHRFTempCurve = + getAndValidateCurve(state, 43, {2, 3}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.CoolingAndDischargeSHRFFlowCurve = + getAndValidateCurve(state, 44, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); } // cooling and discharge mode available - BooleanSwitch answer4 = getYesNoValue(state.dataIPShortCut->cAlphaArgs(45)); - switch (answer4) { - case BooleanSwitch::Yes: - case BooleanSwitch::No: - thisTESCoil.ChargeOnlyModeAvailable = static_cast(answer4); - break; - default: - thisTESCoil.ChargeOnlyModeAvailable = false; - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(45), state.dataIPShortCut->cAlphaArgs(45))); - ShowContinueError(state, "Available choices are Yes or No."); - ErrorsFound = true; - } + thisTESCoil.ChargeOnlyModeAvailable = parseModeAvailability(state, 45, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); if (thisTESCoil.ChargeOnlyModeAvailable) { @@ -1216,68 +543,14 @@ void GetTESCoilInput(EnergyPlusData &state) thisTESCoil.ChargeOnlyRatedCapacitySizingFactor = state.dataIPShortCut->rNumericArgs(25); // sizing factor for charging capacity [] thisTESCoil.ChargeOnlyRatedCOP = state.dataIPShortCut->rNumericArgs(26); // coefficient of performance at rating conditions [W/W] - thisTESCoil.ChargeOnlyChargingCapFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(46)); - if (thisTESCoil.ChargeOnlyChargingCapFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(46)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(46))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(46), state.dataIPShortCut->cAlphaArgs(46))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.ChargeOnlyChargingCapFTempCurve, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(46)); // Field Name - } - - thisTESCoil.ChargeOnlyChargingEIRFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(47)); - if (thisTESCoil.ChargeOnlyChargingEIRFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(47)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(47))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(47), state.dataIPShortCut->cAlphaArgs(47))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.ChargeOnlyChargingEIRFTempCurve, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(47)); // Field Name - } + thisTESCoil.ChargeOnlyChargingCapFTempCurve = + getAndValidateCurve(state, 46, {2}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.ChargeOnlyChargingEIRFTempCurve = + getAndValidateCurve(state, 47, {2}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); } // Charge only mode available - BooleanSwitch answer5 = getYesNoValue(state.dataIPShortCut->cAlphaArgs(48)); - switch (answer5) { - case BooleanSwitch::Yes: - case BooleanSwitch::No: - thisTESCoil.DischargeOnlyModeAvailable = static_cast(answer5); - break; - default: - thisTESCoil.DischargeOnlyModeAvailable = false; - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(48), state.dataIPShortCut->cAlphaArgs(48))); - ShowContinueError(state, "Available choices are Yes or No."); - ErrorsFound = true; - } + thisTESCoil.DischargeOnlyModeAvailable = parseModeAvailability(state, 48, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); if (thisTESCoil.DischargeOnlyModeAvailable) { thisTESCoil.DischargeOnlyRatedDischargeCap = state.dataIPShortCut->rNumericArgs(27); // gross total evaporator cooling capacity [W] @@ -1285,166 +558,20 @@ void GetTESCoilInput(EnergyPlusData &state) thisTESCoil.DischargeOnlyRatedSHR = state.dataIPShortCut->rNumericArgs(29); // sensible heat ratio (sens cap/total cap) thisTESCoil.DischargeOnlyRatedCOP = state.dataIPShortCut->rNumericArgs(30); // coefficient of performance for discharging [W/W] - thisTESCoil.DischargeOnlyCapFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(49)); - if (thisTESCoil.DischargeOnlyCapFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(49)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(49))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(49), state.dataIPShortCut->cAlphaArgs(49))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.DischargeOnlyCapFTempCurve, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(49)); // Field Name - } - - thisTESCoil.DischargeOnlyCapFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(50)); - if (thisTESCoil.DischargeOnlyCapFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(50)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(50))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(50), state.dataIPShortCut->cAlphaArgs(50))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.DischargeOnlyCapFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(50)); // Field Name - } - - thisTESCoil.DischargeOnlyEIRFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(51)); - if (thisTESCoil.DischargeOnlyEIRFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(51)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(51))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(51), state.dataIPShortCut->cAlphaArgs(51))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.DischargeOnlyEIRFTempCurve, // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(51)); // Field Name - } - - thisTESCoil.DischargeOnlyEIRFFlowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(52)); - if (thisTESCoil.DischargeOnlyEIRFFlowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(52)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(52))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(52), state.dataIPShortCut->cAlphaArgs(52))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.DischargeOnlyEIRFFlowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(52)); // Field Name - } - - thisTESCoil.DischargeOnlyPLFFPLRCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(53)); - if (thisTESCoil.DischargeOnlyPLFFPLRCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(53)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(53))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(53), state.dataIPShortCut->cAlphaArgs(53))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.DischargeOnlyPLFFPLRCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(53)); // Field Name - } - - thisTESCoil.DischargeOnlySHRFTempCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(54)); - if (thisTESCoil.DischargeOnlySHRFTempCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(54)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(54))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(54), state.dataIPShortCut->cAlphaArgs(54))); - } - ErrorsFound = true; - } else { - // Verify Curve Object - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.DischargeOnlySHRFTempCurve, // Curve index - {2, 3}, // Valid dimensions // MULTIPLECURVEDIMS - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(54)); // Field Name - } - - thisTESCoil.DischargeOnlySHRFFLowCurve = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(55)); - if (thisTESCoil.DischargeOnlySHRFFLowCurve == 0) { - if (state.dataIPShortCut->lAlphaFieldBlanks(55)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError(state, EnergyPlus::format("Required {}is blank.", state.dataIPShortCut->cAlphaFieldNames(55))); - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, cCurrentModuleObject, thisTESCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("Not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(55), state.dataIPShortCut->cAlphaArgs(55))); - } - ErrorsFound = true; - } else { - // Verify Curve Object, any curve with just x as single independent variable - ErrorsFound |= EnergyPlus::Curve::CheckCurveDims(state, - thisTESCoil.DischargeOnlySHRFFLowCurve, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisTESCoil.Name, // Object Name - state.dataIPShortCut->cAlphaFieldNames(55)); // Field Name - } + thisTESCoil.DischargeOnlyCapFTempCurve = + getAndValidateCurve(state, 49, {2}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.DischargeOnlyCapFFlowCurve = + getAndValidateCurve(state, 50, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.DischargeOnlyEIRFTempCurve = + getAndValidateCurve(state, 51, {2}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.DischargeOnlyEIRFFlowCurve = + getAndValidateCurve(state, 52, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.DischargeOnlyPLFFPLRCurve = + getAndValidateCurve(state, 53, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.DischargeOnlySHRFTempCurve = + getAndValidateCurve(state, 54, {2, 3}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); + thisTESCoil.DischargeOnlySHRFFLowCurve = + getAndValidateCurve(state, 55, {1}, RoutineName, cCurrentModuleObject, thisTESCoil.Name, ErrorsFound); } // Discharge Only mode available diff --git a/src/EnergyPlus/Pumps.cc b/src/EnergyPlus/Pumps.cc index b1a02554800..dfc3b5c754b 100644 --- a/src/EnergyPlus/Pumps.cc +++ b/src/EnergyPlus/Pumps.cc @@ -104,6 +104,91 @@ namespace EnergyPlus::Pumps { using HVAC::SmallWaterVolFlow; using Node::ObjectIsNotParent; +// Parse zone skin loss fields common to all pump types. +static void parsePumpZoneSkinLosses( + EnergyPlusData &state, PumpSpecs &thisPump, std::string_view cCurrentModuleObject, int alphaZoneIdx, int numSkinLossIdx, bool &ErrorsFound) +{ + auto &thisInput = state.dataIPShortCut; + if (!thisInput->lAlphaFieldBlanks(alphaZoneIdx)) { + thisPump.ZoneNum = Util::FindItemInList(thisInput->cAlphaArgs(alphaZoneIdx), state.dataHeatBal->Zone); + if (thisPump.ZoneNum > 0) { + thisPump.HeatLossesToZone = true; + if (!thisInput->lNumericFieldBlanks(numSkinLossIdx)) { + thisPump.SkinLossRadFraction = thisInput->rNumericArgs(numSkinLossIdx); + } + } else { + ShowSevereError(state, + EnergyPlus::format("{}=\"{}\" invalid {}=\"{}\" not found.", + cCurrentModuleObject, + thisPump.Name, + thisInput->cAlphaFieldNames(alphaZoneIdx), + thisInput->cAlphaArgs(alphaZoneIdx))); + ErrorsFound = true; + } + } +} + +// Parse power sizing method and scaling factors common to all pump types. +static void parsePumpPowerSizing(EnergyPlusData &state, + PumpSpecs &thisPump, + std::string_view cCurrentModuleObject, + int alphaSizingIdx, + int numFlowIdx, + int numFlowPressIdx, + bool &ErrorsFound) +{ + static constexpr std::string_view RoutineName("GetPumpInput: "); + static constexpr std::array(PowerSizingMethod::Num)> powerSizingMethodNamesUC{"POWERPERFLOW", + "POWERPERFLOWPERPRESSURE"}; + auto &thisInput = state.dataIPShortCut; + if (!thisInput->lAlphaFieldBlanks(alphaSizingIdx)) { + thisPump.powerSizingMethod = + static_cast(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(alphaSizingIdx)))); + if (thisPump.powerSizingMethod == PowerSizingMethod::Invalid) { + ShowSevereError(state, + EnergyPlus::format("{}{}=\"{}\", sizing method type entered is invalid. Use one of the key choice entries.", + RoutineName, + cCurrentModuleObject, + thisPump.Name)); + ErrorsFound = true; + } + } + if (!thisInput->lNumericFieldBlanks(numFlowIdx)) { + thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(numFlowIdx); + } + if (!thisInput->lNumericFieldBlanks(numFlowPressIdx)) { + thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(numFlowPressIdx); + } +} + +// Parse pressure curve input for VarSpeed and ConSpeed pumps. +static void +parsePumpPressureCurve(EnergyPlusData &state, PumpSpecs &thisPump, std::string_view cCurrentModuleObject, int alphaCurveIdx, bool &ErrorsFound) +{ + static constexpr std::string_view RoutineName("GetPumpInput: "); + auto &thisInput = state.dataIPShortCut; + if (thisInput->cAlphaArgs(alphaCurveIdx).empty()) { + thisPump.PressureCurve_Index = -1; + } else { + int TempCurveIndex = Curve::GetCurveIndex(state, thisInput->cAlphaArgs(alphaCurveIdx)); + if (TempCurveIndex == 0) { + thisPump.PressureCurve_Index = -1; + } else { + ErrorsFound |= Curve::CheckCurveDims(state, + TempCurveIndex, // Curve index + {1}, // Valid dimensions + RoutineName, // Routine name + cCurrentModuleObject, // Object Type + thisPump.Name, // Object Name + thisInput->cAlphaFieldNames(alphaCurveIdx)); // Field Name + + if (!ErrorsFound) { + thisPump.PressureCurve_Index = TempCurveIndex; + Curve::GetCurveMinMaxValues(state, TempCurveIndex, thisPump.MinPhiValue, thisPump.MaxPhiValue); + } + } + } +} static constexpr std::array(PumpType::Num)> pumpTypeIDFNames = { "Pump:VariableSpeed", "Pump:ConstantSpeed", "Pump:VariableSpeed:Condensate", "HeaderedPumps:VariableSpeed", "HeaderedPumps:ConstantSpeed"}; @@ -224,8 +309,6 @@ void GetPumpInput(EnergyPlusData &state) static constexpr std::array(PumpControlType::Num)> pumpCtrlTypeNamesUC{"CONTINUOUS", "INTERMITTENT"}; static constexpr std::array(ControlTypeVFD::Num)> controlTypeVFDNamesUC{"MANUALCONTROL", "PRESSURESETPOINTCONTROL"}; - static constexpr std::array(PowerSizingMethod::Num)> powerSizingMethodNamesUC{"POWERPERFLOW", - "POWERPERFLOWPERPRESSURE"}; // SUBROUTINE LOCAL VARIABLE DECLARATIONS: int PumpNum; @@ -233,7 +316,6 @@ void GetPumpInput(EnergyPlusData &state) int NumNums; // Number of elements in the numeric array int IOStat; // IO Status when calling get input subroutine bool ErrorsFound; - int TempCurveIndex; int NumVarSpeedPumps = 0; int NumConstSpeedPumps = 0; int NumCondensatePumps = 0; @@ -368,28 +450,7 @@ void GetPumpInput(EnergyPlusData &state) // Probably the following two lines will be used if the team agrees on changing the F10 value from min flow rate to // minimum flow as a fraction of nominal flow. - // Input pressure related data such as pressure curve and impeller size/rotational speed - if (thisInput->cAlphaArgs(6).empty()) { - thisPump.PressureCurve_Index = -1; - } else { - TempCurveIndex = GetCurveIndex(state, thisInput->cAlphaArgs(6)); - if (TempCurveIndex == 0) { - thisPump.PressureCurve_Index = -1; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - TempCurveIndex, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisPump.Name, // Object Name - thisInput->cAlphaFieldNames(6)); // Field Name - - if (!ErrorsFound) { - thisPump.PressureCurve_Index = TempCurveIndex; - GetCurveMinMaxValues(state, TempCurveIndex, thisPump.MinPhiValue, thisPump.MaxPhiValue); - } - } - } + parsePumpPressureCurve(state, thisPump, cCurrentModuleObject, 6, ErrorsFound); // read in the rest of the pump pressure characteristics thisPump.ImpellerDiameter = thisInput->rNumericArgs(11); @@ -465,44 +526,9 @@ void GetPumpInput(EnergyPlusData &state) } } - if (!thisInput->lAlphaFieldBlanks(13)) { // zone named for pump skin losses - thisPump.ZoneNum = Util::FindItemInList(thisInput->cAlphaArgs(13), state.dataHeatBal->Zone); - if (thisPump.ZoneNum > 0) { - thisPump.HeatLossesToZone = true; - if (!thisInput->lNumericFieldBlanks(12)) { - thisPump.SkinLossRadFraction = thisInput->rNumericArgs(12); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}=\"{}\" invalid {}=\"{}\" not found.", - cCurrentModuleObject, - thisPump.Name, - thisInput->cAlphaFieldNames(13), - thisInput->cAlphaArgs(13))); - ErrorsFound = true; - } - } + parsePumpZoneSkinLosses(state, thisPump, cCurrentModuleObject, 13, 12, ErrorsFound); - if (!thisInput->lAlphaFieldBlanks(14)) { - thisPump.powerSizingMethod = - static_cast(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(14)))); - if (thisPump.powerSizingMethod == PowerSizingMethod::Invalid) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", sizing method type entered is invalid. Use one of the key choice entries.", - RoutineName, - cCurrentModuleObject, - thisPump.Name)); - ErrorsFound = true; - } - } - - if (!thisInput->lNumericFieldBlanks(13)) { - thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(13); - } - - if (!thisInput->lNumericFieldBlanks(14)) { - thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(14); - } + parsePumpPowerSizing(state, thisPump, cCurrentModuleObject, 14, 13, 14, ErrorsFound); if (!thisInput->lNumericFieldBlanks(15)) { thisPump.MinVolFlowRateFrac = thisInput->rNumericArgs(15); @@ -607,72 +633,16 @@ void GetPumpInput(EnergyPlusData &state) ShowWarningItemNotFound(state, eoh, thisInput->cAlphaFieldNames(5), thisInput->cAlphaArgs(5), ""); } - // Input pressure related data such as pressure curve and impeller size/rotational speed - if (thisInput->cAlphaArgs(6).empty()) { - thisPump.PressureCurve_Index = -1; - } else { - TempCurveIndex = GetCurveIndex(state, thisInput->cAlphaArgs(6)); - if (TempCurveIndex == 0) { - thisPump.PressureCurve_Index = -1; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - TempCurveIndex, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - cCurrentModuleObject, // Object Type - thisPump.Name, // Object Name - thisInput->cAlphaFieldNames(6)); // Field Name - - if (!ErrorsFound) { - thisPump.PressureCurve_Index = TempCurveIndex; - GetCurveMinMaxValues(state, TempCurveIndex, thisPump.MinPhiValue, thisPump.MaxPhiValue); - } - } - } + parsePumpPressureCurve(state, thisPump, cCurrentModuleObject, 6, ErrorsFound); // read in the rest of the pump pressure characteristics thisPump.ImpellerDiameter = thisInput->rNumericArgs(6); thisPump.RotSpeed_RPM = thisInput->rNumericArgs(7); // retrieve the input rotational speed, in revs/min thisPump.RotSpeed = thisPump.RotSpeed_RPM / 60.0; // convert input[rpm] to calculation units[rps] - if (!thisInput->lAlphaFieldBlanks(7)) { // zone named for pump skin losses - thisPump.ZoneNum = Util::FindItemInList(thisInput->cAlphaArgs(7), state.dataHeatBal->Zone); - if (thisPump.ZoneNum > 0) { - thisPump.HeatLossesToZone = true; - if (!thisInput->lNumericFieldBlanks(8)) { - thisPump.SkinLossRadFraction = thisInput->rNumericArgs(8); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}=\"{}\" invalid {}=\"{}\" not found.", - cCurrentModuleObject, - thisPump.Name, - thisInput->cAlphaFieldNames(7), - thisInput->cAlphaArgs(7))); - ErrorsFound = true; - } - } + parsePumpZoneSkinLosses(state, thisPump, cCurrentModuleObject, 7, 8, ErrorsFound); - if (!thisInput->lAlphaFieldBlanks(8)) { - thisPump.powerSizingMethod = - static_cast(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8)))); - if (thisPump.powerSizingMethod == PowerSizingMethod::Invalid) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", sizing method type entered is invalid. Use one of the key choice entries.", - RoutineName, - cCurrentModuleObject, - thisPump.Name)); - ErrorsFound = true; - } - } - - if (!thisInput->lNumericFieldBlanks(9)) { - thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(9); - } - - if (!thisInput->lNumericFieldBlanks(10)) { - thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(10); - } + parsePumpPowerSizing(state, thisPump, cCurrentModuleObject, 8, 9, 10, ErrorsFound); if (NumAlphas > 8) { thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(9); @@ -753,23 +723,7 @@ void GetPumpInput(EnergyPlusData &state) thisPump.PartLoadCoef[2] = thisInput->rNumericArgs(8); thisPump.PartLoadCoef[3] = thisInput->rNumericArgs(9); - if (!thisInput->lAlphaFieldBlanks(5)) { // zone named for pump skin losses - thisPump.ZoneNum = Util::FindItemInList(thisInput->cAlphaArgs(5), state.dataHeatBal->Zone); - if (thisPump.ZoneNum > 0) { - thisPump.HeatLossesToZone = true; - if (!thisInput->lNumericFieldBlanks(10)) { - thisPump.SkinLossRadFraction = thisInput->rNumericArgs(10); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}=\"{}\" invalid {}=\"{}\" not found.", - cCurrentModuleObject, - thisPump.Name, - thisInput->cAlphaFieldNames(5), - thisInput->cAlphaArgs(5))); - ErrorsFound = true; - } - } + parsePumpZoneSkinLosses(state, thisPump, cCurrentModuleObject, 5, 10, ErrorsFound); thisPump.MinVolFlowRate = 0.0; thisPump.Energy = 0.0; @@ -785,26 +739,7 @@ void GetPumpInput(EnergyPlusData &state) thisPump.NomVolFlowRate = (thisPump.NomSteamVolFlowRate * SteamDensity) / TempWaterDensity; } - if (!thisInput->lAlphaFieldBlanks(6)) { - thisPump.powerSizingMethod = - static_cast(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(6)))); - if (thisPump.powerSizingMethod == PowerSizingMethod::Invalid) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", sizing method type entered is invalid. Use one of the key choice entries.", - RoutineName, - cCurrentModuleObject, - thisPump.Name)); - ErrorsFound = true; - } - } - - if (!thisInput->lNumericFieldBlanks(11)) { - thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(11); - } - - if (!thisInput->lNumericFieldBlanks(12)) { - thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(12); - } + parsePumpPowerSizing(state, thisPump, cCurrentModuleObject, 6, 11, 12, ErrorsFound); if (NumAlphas > 6) { thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(7); @@ -915,44 +850,9 @@ void GetPumpInput(EnergyPlusData &state) thisPump.MinVolFlowRateFrac = thisInput->rNumericArgs(11); thisPump.MinVolFlowRate = thisPump.NomVolFlowRate * thisPump.MinVolFlowRateFrac; - if (!thisInput->lAlphaFieldBlanks(7)) { // zone named for pump skin losses - thisPump.ZoneNum = Util::FindItemInList(thisInput->cAlphaArgs(7), state.dataHeatBal->Zone); - if (thisPump.ZoneNum > 0) { - thisPump.HeatLossesToZone = true; - if (!thisInput->lNumericFieldBlanks(12)) { - thisPump.SkinLossRadFraction = thisInput->rNumericArgs(12); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}=\"{}\" invalid {}=\"{}\" not found.", - cCurrentModuleObject, - thisPump.Name, - thisInput->cAlphaFieldNames(7), - thisInput->cAlphaArgs(7))); - ErrorsFound = true; - } - } - - if (!thisInput->lAlphaFieldBlanks(8)) { - thisPump.powerSizingMethod = - static_cast(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8)))); - if (thisPump.powerSizingMethod == PowerSizingMethod::Invalid) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", sizing method type entered is invalid. Use one of the key choice entries.", - RoutineName, - cCurrentModuleObject, - thisPump.Name)); - ErrorsFound = true; - } - } + parsePumpZoneSkinLosses(state, thisPump, cCurrentModuleObject, 7, 12, ErrorsFound); - if (!thisInput->lNumericFieldBlanks(13)) { - thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(13); - } - - if (!thisInput->lNumericFieldBlanks(14)) { - thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(14); - } + parsePumpPowerSizing(state, thisPump, cCurrentModuleObject, 8, 13, 14, ErrorsFound); if (NumAlphas > 8) { thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(9); @@ -1062,43 +962,8 @@ void GetPumpInput(EnergyPlusData &state) thisPump.PartLoadCoef[2] = 0.0; thisPump.PartLoadCoef[3] = 0.0; - if (!thisInput->lAlphaFieldBlanks(7)) { // zone named for pump skin losses - thisPump.ZoneNum = Util::FindItemInList(thisInput->cAlphaArgs(7), state.dataHeatBal->Zone); - if (thisPump.ZoneNum > 0) { - thisPump.HeatLossesToZone = true; - if (!thisInput->lNumericFieldBlanks(7)) { - thisPump.SkinLossRadFraction = thisInput->rNumericArgs(7); - } - } else { - ShowSevereError(state, - EnergyPlus::format("{}=\"{}\" invalid {}=\"{}\" not found.", - cCurrentModuleObject, - thisPump.Name, - thisInput->cAlphaFieldNames(7), - thisInput->cAlphaArgs(7))); - ErrorsFound = true; - } - } - if (!thisInput->lAlphaFieldBlanks(8)) { - thisPump.powerSizingMethod = - static_cast(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8)))); - if (thisPump.powerSizingMethod == PowerSizingMethod::Invalid) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", sizing method type entered is invalid. Use one of the key choice entries.", - RoutineName, - cCurrentModuleObject, - thisPump.Name)); - ErrorsFound = true; - } - } - - if (!thisInput->lNumericFieldBlanks(8)) { - thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(8); - } - - if (!thisInput->lNumericFieldBlanks(9)) { - thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(9); - } + parsePumpZoneSkinLosses(state, thisPump, cCurrentModuleObject, 7, 7, ErrorsFound); + parsePumpPowerSizing(state, thisPump, cCurrentModuleObject, 8, 8, 9, ErrorsFound); if (NumAlphas > 8) { thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(9); @@ -1287,55 +1152,19 @@ void GetPumpInput(EnergyPlusData &state) thisPump.Name); // setup internal gains - switch (thisPump.pumpType) { - case PumpType::VarSpeed: { - SetupZoneInternalGain(state, - thisPump.ZoneNum, - thisPump.Name, - DataHeatBalance::IntGainType::Pump_VarSpeed, - &thisPumpRep.ZoneConvGainRate, - nullptr, - &thisPumpRep.ZoneRadGainRate); - } break; - case PumpType::ConSpeed: { - SetupZoneInternalGain(state, - thisPump.ZoneNum, - thisPump.Name, - DataHeatBalance::IntGainType::Pump_ConSpeed, - &thisPumpRep.ZoneConvGainRate, - nullptr, - &thisPumpRep.ZoneRadGainRate); - } break; - case PumpType::Cond: { - SetupZoneInternalGain(state, - thisPump.ZoneNum, - thisPump.Name, - DataHeatBalance::IntGainType::Pump_Cond, - &thisPumpRep.ZoneConvGainRate, - nullptr, - &thisPumpRep.ZoneRadGainRate); - } break; - case PumpType::Bank_VarSpeed: { - SetupZoneInternalGain(state, - thisPump.ZoneNum, - thisPump.Name, - DataHeatBalance::IntGainType::PumpBank_VarSpeed, - &thisPumpRep.ZoneConvGainRate, - nullptr, - &thisPumpRep.ZoneRadGainRate); - } break; - case PumpType::Bank_ConSpeed: { - SetupZoneInternalGain(state, - thisPump.ZoneNum, - thisPump.Name, - DataHeatBalance::IntGainType::PumpBank_ConSpeed, - &thisPumpRep.ZoneConvGainRate, - nullptr, - &thisPumpRep.ZoneRadGainRate); - } break; - default: - break; - } + static constexpr std::array(PumpType::Num)> pumpIntGainTypes = { + DataHeatBalance::IntGainType::Pump_VarSpeed, + DataHeatBalance::IntGainType::Pump_ConSpeed, + DataHeatBalance::IntGainType::Pump_Cond, + DataHeatBalance::IntGainType::PumpBank_VarSpeed, + DataHeatBalance::IntGainType::PumpBank_ConSpeed}; + SetupZoneInternalGain(state, + thisPump.ZoneNum, + thisPump.Name, + pumpIntGainTypes[static_cast(thisPump.pumpType)], + &thisPumpRep.ZoneConvGainRate, + nullptr, + &thisPumpRep.ZoneRadGainRate); } } } diff --git a/src/EnergyPlus/RefrigeratedCase.cc b/src/EnergyPlus/RefrigeratedCase.cc index df26acfdab5..0ee004e3d2f 100644 --- a/src/EnergyPlus/RefrigeratedCase.cc +++ b/src/EnergyPlus/RefrigeratedCase.cc @@ -385,6 +385,635 @@ void ManageRefrigeratedCaseRacks(EnergyPlusData &state) } } +// Helper: look up a load name in the Case, WalkIn, CaseAndWalkInList, and optionally +// WarehouseCoil arrays. Returns {CaseAndWalkInListNum, CaseNum, WalkInNum, CoilNum} (0 = not found). +static std::tuple findLoadNames(EnergyPlusData &state, const std::string &loadName, bool includeCoil = true) +{ + int listNum = 0, caseNum = 0, walkInNum = 0, coilNum = 0; + if (state.dataRefrigCase->NumSimulationCaseAndWalkInLists > 0) { + listNum = Util::FindItemInList(loadName, state.dataRefrigCase->CaseAndWalkInList); + } + if (state.dataRefrigCase->NumSimulationCases > 0) { + caseNum = Util::FindItemInList(loadName, state.dataRefrigCase->RefrigCase); + } + if (state.dataRefrigCase->NumSimulationWalkIns > 0) { + walkInNum = Util::FindItemInList(loadName, state.dataRefrigCase->WalkIn); + } + if (includeCoil && state.dataRefrigCase->NumSimulationRefrigAirChillers > 0) { + coilNum = Util::FindItemInList(loadName, state.dataRefrigCase->WarehouseCoil); + } + return {listNum, caseNum, walkInNum, coilNum}; +} + +// Helper: report the standard "invalid name" / "non-unique name" errors when +// a load-list name lookup yields NumNameMatches != 1. Sets ErrorsFound = true. +static void reportNameMatchError(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view RoutineName, + std::string_view CurrentModuleObject, + const std::string &objName, + int numMatches, + const std::string &alphaFieldName, + const std::string &alphaValue) +{ + ErrorsFound = true; + if (numMatches == 0) { + ShowSevereError( + state, EnergyPlus::format("{}{}=\"{}\", has an invalid {}: {}", RoutineName, CurrentModuleObject, objName, alphaFieldName, alphaValue)); + } else { + ShowSevereError(state, + EnergyPlus::format("{}{}=\"{}\", has a non-unique name that could be either a {}: {}", + RoutineName, + CurrentModuleObject, + objName, + alphaFieldName, + alphaValue)); + } +} + +namespace { + + // Helper: given already-resolved listNum and compNum, populate count variables and + // the destination compressor-index array. + template + void assignCompressors( + const Array1D &CompressorLists, int listNum, int compNum, int &localCount, int &memberCount, ArrayType &destArray) + { + if (listNum != 0) { + localCount = memberCount = CompressorLists(listNum).NumCompressors; + if (!allocated(destArray)) { + destArray.allocate(localCount); + } + destArray({1, localCount}) = CompressorLists(listNum).CompItemNum({1, localCount}); + } else if (compNum != 0) { + localCount = memberCount = 1; + if (!allocated(destArray)) { + destArray.allocate(1); + } + destArray(1) = compNum; + } + } + + // Helper: look up a compressor-or-list name, validate that it resolves to exactly one item, + // report errors for missing or non-unique names, and delegate to assignCompressors. + template + bool lookupAndAssignCompressors(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view RoutineName, + std::string_view CurrentModuleObject, + const Array1D_string &Alphas, + const Array1D_string &cAlphaFieldNames, + const Array1D &CompressorLists, + const Array1D &Compressor, + int alphaNum, + int &numCompressorsSys, + int &memberCount, + ArrayType &destArray) + { + int ListNum = Util::FindItemInList(Alphas(alphaNum), CompressorLists); + int CompNum = Util::FindItemInList(Alphas(alphaNum), Compressor); + if ((ListNum == 0) && (CompNum == 0)) { + ShowSevereError(state, + EnergyPlus::format(R"({}{}, "{}", has an invalid or undefined value="{}".)", + RoutineName, + CurrentModuleObject, + cAlphaFieldNames(alphaNum), + Alphas(alphaNum))); + ErrorsFound = true; + return false; + } else if ((ListNum != 0) && (CompNum != 0)) { + ShowSevereError(state, + EnergyPlus::format("{}{} {}, has a non-unique name used for both Compressor and CompressorList name: \"{}\".", + RoutineName, + CurrentModuleObject, + cAlphaFieldNames(alphaNum), + Alphas(alphaNum))); + ErrorsFound = true; + return false; + } + assignCompressors(CompressorLists, ListNum, CompNum, numCompressorsSys, memberCount, destArray); + return true; + } + + // Helper: resolve a CaseAndWalkInList/Case/WalkIn name (no coils) for one temperature + // level of a TranscriticalSystem and fill the destination arrays. + template + void resolveTransSysLoads(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view RoutineName, + std::string_view CurrentModuleObject, + const Array1D_string &Alphas, + const Array1D_bool &lAlphaBlanks, + const Array1D_string &cAlphaFieldNames, + int alphaNum, + const std::string &sysName, + int &numCasesOut, + int &numWalkInsOut, + CaseArrayType &caseNumArray, + WalkInArrayType &walkInNumArray) + { + if (lAlphaBlanks(alphaNum)) { + return; + } + auto [CaseAndWalkInListNum, CaseNum, WalkInNum, CoilNum] = findLoadNames(state, Alphas(alphaNum), /*includeCoil=*/false); + int NumNameMatches = (CaseAndWalkInListNum != 0) + (CaseNum != 0) + (WalkInNum != 0); + if (NumNameMatches != 1) { + reportNameMatchError( + state, ErrorsFound, RoutineName, CurrentModuleObject, sysName, NumNameMatches, cAlphaFieldNames(alphaNum), Alphas(alphaNum)); + } else if (CaseAndWalkInListNum != 0) { + auto &CaseAndWalkInList = state.dataRefrigCase->CaseAndWalkInList; + numCasesOut = CaseAndWalkInList(CaseAndWalkInListNum).NumCases; + numWalkInsOut = CaseAndWalkInList(CaseAndWalkInListNum).NumWalkIns; + if (numCasesOut > 0) { + if (!allocated(caseNumArray)) { + caseNumArray.allocate(numCasesOut); + } + caseNumArray({1, numCasesOut}) = CaseAndWalkInList(CaseAndWalkInListNum).CaseItemNum({1, numCasesOut}); + } + if (numWalkInsOut > 0) { + if (!allocated(walkInNumArray)) { + walkInNumArray.allocate(numWalkInsOut); + } + walkInNumArray({1, numWalkInsOut}) = CaseAndWalkInList(CaseAndWalkInListNum).WalkInItemNum({1, numWalkInsOut}); + } + } else if (CaseNum != 0) { + numCasesOut = 1; + if (!allocated(caseNumArray)) { + caseNumArray.allocate(1); + } + caseNumArray(1) = CaseNum; + } else if (WalkInNum != 0) { + numWalkInsOut = 1; + if (!allocated(walkInNumArray)) { + walkInNumArray.allocate(1); + } + walkInNumArray(1) = WalkInNum; + } + } + + // Helper: resolve a CaseAndWalkInList/Case/WalkIn/Coil name (with coil support) + // for one load-assignment alpha field and populate the destination arrays. + template + bool resolveLoadsWithCoils(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view RoutineName, + std::string_view CurrentModuleObject, + const Array1D_string &Alphas, + const Array1D_bool &lAlphaBlanks, + const Array1D_string &cAlphaFieldNames, + int alphaNum, + const std::string &objName, + int &numCasesOut, + int &numWalkInsOut, + int &numCoilsOut, + CaseArrayType &caseNumArray, + WalkInArrayType &walkInNumArray, + CoilArrayType &coilNumArray) + { + if (lAlphaBlanks(alphaNum)) { + return true; // blank is allowed; caller handles the check + } + auto [CaseAndWalkInListNum, CaseNum, WalkInNum, CoilNum] = findLoadNames(state, Alphas(alphaNum)); + int NumNameMatches = (CaseAndWalkInListNum != 0) + (CaseNum != 0) + (WalkInNum != 0) + (CoilNum != 0); + if (NumNameMatches != 1) { + reportNameMatchError( + state, ErrorsFound, RoutineName, CurrentModuleObject, objName, NumNameMatches, cAlphaFieldNames(alphaNum), Alphas(alphaNum)); + return false; + } + if (CaseAndWalkInListNum != 0) { + auto &CaseAndWalkInList = state.dataRefrigCase->CaseAndWalkInList; + numCasesOut = CaseAndWalkInList(CaseAndWalkInListNum).NumCases; + numWalkInsOut = CaseAndWalkInList(CaseAndWalkInListNum).NumWalkIns; + numCoilsOut = CaseAndWalkInList(CaseAndWalkInListNum).NumCoils; + if (numCasesOut > 0) { + if (!allocated(caseNumArray)) { + caseNumArray.allocate(numCasesOut); + } + caseNumArray({1, numCasesOut}) = CaseAndWalkInList(CaseAndWalkInListNum).CaseItemNum({1, numCasesOut}); + } + if (numWalkInsOut > 0) { + if (!allocated(walkInNumArray)) { + walkInNumArray.allocate(numWalkInsOut); + } + walkInNumArray({1, numWalkInsOut}) = CaseAndWalkInList(CaseAndWalkInListNum).WalkInItemNum({1, numWalkInsOut}); + } + if (numCoilsOut > 0) { + if (!allocated(coilNumArray)) { + coilNumArray.allocate(numCoilsOut); + } + coilNumArray({1, numCoilsOut}) = CaseAndWalkInList(CaseAndWalkInListNum).CoilItemNum({1, numCoilsOut}); + } + } else if (CaseNum != 0) { + numCasesOut = 1; + if (!allocated(caseNumArray)) { + caseNumArray.allocate(1); + } + caseNumArray(1) = CaseNum; + } else if (WalkInNum != 0) { + numWalkInsOut = 1; + if (!allocated(walkInNumArray)) { + walkInNumArray.allocate(1); + } + walkInNumArray(1) = WalkInNum; + } else if (CoilNum != 0) { + numCoilsOut = 1; + if (!allocated(coilNumArray)) { + coilNumArray.allocate(1); + } + coilNumArray(1) = CoilNum; + } + return true; + } + +} // anonymous namespace + +// Helper: compute capacity curve slope and minimum condenser load from rated capacity. +static void computeCapCurveSlopeAndMin(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view RoutineName, + std::string_view CurrentModuleObject, + int capCurvePtr, + const std::string &objName, + const Real64 &ratedCapacity, + Real64 &tempSlopeOut, + Real64 &minCondLoadOut) +{ + if (ratedCapacity > 0.0) { + Real64 DelTempMin, DelTempMax; + Curve::GetCurveMinMaxValues(state, capCurvePtr, DelTempMin, DelTempMax); + Real64 elevFactor = 1.0 - 7.17e-5 * state.dataEnvrn->Elevation; + Real64 Capmin = Curve::CurveValue(state, capCurvePtr, DelTempMin) * elevFactor; + Real64 Capmax = Curve::CurveValue(state, capCurvePtr, DelTempMax) * elevFactor; + tempSlopeOut = (DelTempMax - DelTempMin) / (Capmax - Capmin); + minCondLoadOut = Capmax - DelTempMax / tempSlopeOut; + } else { + ShowSevereError(state, + EnergyPlus::format( + "{}{}=\"{}\" Capacity curve must be input and must be greater than 0 Watts.", RoutineName, CurrentModuleObject, objName)); + ErrorsFound = true; + } +} + +// Helper: read defrost capacity and optional defrost energy fraction for walk-in and air-chiller coil objects. +static void readDefrostCapAndEnergyFraction(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view RoutineName, + std::string_view CurrentModuleObject, + const Array1D &Numbers, + const Array1D_bool &lNumericBlanks, + const Array1D_string &cNumericFieldNames, + const Array1D_string &cAlphaFieldNames, + const Array1D_string &Alphas, + DefrostType defrostType, + const std::string &objName, + int capFieldNum, + int fracFieldNum, + int defTypeAlphaNum, + Real64 &defrostCapacity, + Real64 &defEnergyFraction) +{ + if (defrostType == DefrostType::OffCycle || defrostType == DefrostType::None) { + defrostCapacity = 0.0; + } else { // have electric or hot gas/brine defrost + if ((lNumericBlanks(capFieldNum)) || (Numbers(capFieldNum) <= 0.0)) { + ShowSevereError(state, + EnergyPlus::format("{}{}=\"{}\", {} must be input and greater than or equal to 0 W for {} {}", + RoutineName, + CurrentModuleObject, + objName, + cNumericFieldNames(capFieldNum), + cAlphaFieldNames(defTypeAlphaNum), + Alphas(defTypeAlphaNum))); + ErrorsFound = true; + } else { + defrostCapacity = Numbers(capFieldNum); + } + if (defrostType == DefrostType::Elec) { + defEnergyFraction = 0.7; + } + if (defrostType == DefrostType::Fluid) { + defEnergyFraction = 0.3; + } + if (!lNumericBlanks(fracFieldNum)) { + if ((Numbers(fracFieldNum) > 1.0) || (Numbers(fracFieldNum) < 0.0)) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\", {} must be between 0 and 1, default values will be used.", + RoutineName, + CurrentModuleObject, + objName, + cNumericFieldNames(fracFieldNum))); + } else { + defEnergyFraction = Numbers(fracFieldNum); + } + } + } +} + +// Helper: read a walk-in door (glass or stock) for one zone. +// NStart and AStart are the numeric/alpha field offset for the current zone. +static bool readWalkInDoor(EnergyPlusData &state, + bool &ErrorsFound, + const ErrorObjectHeader &eoh, + const Array1D &Numbers, + const Array1D_bool &lNumericBlanks, + const Array1D_string &Alphas, + const Array1D_bool &lAlphaBlanks, + const Array1D_string &cAlphaFieldNames, + int NStart, + int AStart, + int nArea, + int nHeight, + int nUValue, + int aSchedule, + Real64 defaultHeight, + Real64 defaultUValue, + Real64 &area, + Real64 &height, + Real64 &uvalue, + Sched::Schedule *&schedOut) +{ + area = 0.0; + height = 0.0; + uvalue = 0.0; + if (lNumericBlanks(NStart + nArea)) { + return false; + } + area = Numbers(NStart + nArea); + height = defaultHeight; + if (!lNumericBlanks(NStart + nHeight)) { + height = Numbers(NStart + nHeight); + } + uvalue = defaultUValue; + if (!lNumericBlanks(NStart + nUValue)) { + uvalue = Numbers(NStart + nUValue); + } + if (!lAlphaBlanks(AStart + aSchedule)) { + if ((schedOut = Sched::GetSchedule(state, Alphas(AStart + aSchedule))) == nullptr) { + ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AStart + aSchedule), Alphas(AStart + aSchedule)); + ErrorsFound = true; + } else if (!schedOut->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { + Sched::ShowSevereBadMinMax( + state, eoh, cAlphaFieldNames(AStart + aSchedule), Alphas(AStart + aSchedule), Clusive::In, 0.0, Clusive::In, 1.0); + ErrorsFound = true; + } + } + return true; +} + +// Helper: read suction piping UA and zone heat-gain inputs (optional). +static void readSuctionPiping(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view RoutineName, + std::string_view CurrentModuleObject, + const Array1D &Numbers, + const Array1D_bool &lNumericBlanks, + const Array1D_string &Alphas, + const Array1D_bool &lAlphaBlanks, + const Array1D_string &cAlphaFieldNames, + const Array1D_string &cNumericFieldNames, + int alphaFieldNum, + int numericFieldNum, + const std::string &objName, + Real64 &sumUASuctionPiping, + int &suctionPipeActualZoneNum, + int &suctionPipeZoneNodeNum, + std::string_view tempLevelLabel = "") +{ + sumUASuctionPiping = 0.0; + std::string levelPrefix = tempLevelLabel.empty() ? std::string("S") : EnergyPlus::format(" The {} s", tempLevelLabel); + if (!lNumericBlanks(numericFieldNum) && !lAlphaBlanks(alphaFieldNum)) { + sumUASuctionPiping = Numbers(numericFieldNum); + suctionPipeActualZoneNum = Util::FindItemInList(Alphas(alphaFieldNum), state.dataHeatBal->Zone); + suctionPipeZoneNodeNum = DataZoneEquipment::GetSystemNodeNumberForZone(state, suctionPipeActualZoneNum); + if (suctionPipeZoneNodeNum == 0) { + ShowSevereError(state, + EnergyPlus::format("{}{}=\"{}\", System Node Number not found for {} = {} even though {} is greater than zero.", + RoutineName, + CurrentModuleObject, + objName, + cAlphaFieldNames(alphaFieldNum), + Alphas(alphaFieldNum), + cNumericFieldNames(numericFieldNum))); + ShowContinueError(state, + EnergyPlus::format("{}uction piping heat gain cannot be calculated unless a Zone is defined to " + "determine the environmental temperature surrounding the piping.", + levelPrefix)); + ErrorsFound = true; + } else { + state.dataRefrigCase->RefrigPresentInZone(suctionPipeActualZoneNum) = true; + } + } else if (!lNumericBlanks(numericFieldNum) && lAlphaBlanks(alphaFieldNum)) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\" {} not found even though {} is greater than zero.", + RoutineName, + CurrentModuleObject, + objName, + cAlphaFieldNames(alphaFieldNum), + cNumericFieldNames(numericFieldNum))); + ShowContinueError(state, + EnergyPlus::format("{}uction piping heat gain will not be calculated unless a Zone is defined to " + "determine the environmental temperature surrounding the piping.", + levelPrefix)); + } else if (lNumericBlanks(numericFieldNum) && !lAlphaBlanks(alphaFieldNum)) { + ShowWarningError( + state, + EnergyPlus::format("{}{}=\"{}\" {} will not be used and suction piping heat gain will not be calculated because {} was blank.", + RoutineName, + CurrentModuleObject, + objName, + cAlphaFieldNames(alphaFieldNum), + cNumericFieldNames(numericFieldNum))); + } +} + +// Helper: read the optional air-inlet node field for an air-cooled condenser or gas cooler. +static void readAirInletNodeField(EnergyPlusData &state, + bool &ErrorsFound, + const ErrorObjectHeader &eoh, + const Array1D_string &Alphas, + const Array1D_bool &lAlphaBlanks, + const Array1D_string &cAlphaFieldNames, + int alphaNum, + Node::ConnectionObjectType connObjType, + int &inletAirNodeNum, + int &inletAirZoneNum, + bool &rejectHeatToZone) +{ + rejectHeatToZone = false; + if (lAlphaBlanks(alphaNum)) { + inletAirNodeNum = 0; + return; + } + inletAirZoneNum = Util::FindItemInList(Alphas(alphaNum), state.dataHeatBal->Zone); + if (inletAirZoneNum != 0) { + inletAirNodeNum = DataZoneEquipment::GetSystemNodeNumberForZone(state, inletAirZoneNum); + rejectHeatToZone = true; + state.dataRefrigCase->RefrigPresentInZone(inletAirZoneNum) = true; + } else { + inletAirNodeNum = Node::GetOnlySingleNode(state, + Alphas(alphaNum), + ErrorsFound, + connObjType, + Alphas(1), + Node::FluidType::Air, + Node::ConnectionType::OutsideAirReference, + Node::CompFluidStream::Primary, + Node::ObjectIsParent); + if (!OutAirNodeManager::CheckOutAirNodeNumber(state, inletAirNodeNum)) { + ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(alphaNum), Alphas(alphaNum)); + ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node or as a Zone."); + ErrorsFound = true; + } + } +} + +// Helper: read distribution piping or receiver UA and zone heat-gain inputs (optional) for secondary systems. +static void readSecondaryPipingOrReceiver(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view RoutineName, + std::string_view CurrentModuleObject, + const std::string &objName, + const Array1D &Numbers, + const Array1D_bool &lNumericBlanks, + const Array1D_string &Alphas, + const Array1D_bool &lAlphaBlanks, + const Array1D_string &cAlphaFieldNames, + const Array1D_string &cNumericFieldNames, + int alphaFieldNum, + int numericFieldNum, + Real64 &sumUA, + int &zoneNum, + int &zoneNodeNum, + std::string_view heatGainLabel, + std::string_view surroundingLabel) +{ + sumUA = 0.0; + if (!lNumericBlanks(numericFieldNum) && !lAlphaBlanks(alphaFieldNum)) { + sumUA = Numbers(numericFieldNum); + zoneNum = Util::FindItemInList(Alphas(alphaFieldNum), state.dataHeatBal->Zone); + zoneNodeNum = DataZoneEquipment::GetSystemNodeNumberForZone(state, zoneNum); + if (zoneNum == 0) { + ShowSevereError(state, + EnergyPlus::format("{}{}=\"{}\", invalid {} not valid: {}", + RoutineName, + CurrentModuleObject, + objName, + cAlphaFieldNames(alphaFieldNum), + Alphas(alphaFieldNum))); + ErrorsFound = true; + } else { + state.dataRefrigCase->RefrigPresentInZone(zoneNum) = true; + } + if (zoneNodeNum == 0) { + ShowSevereError( + state, + EnergyPlus::format("{}{}=\"{}\" System Node Number not found for {} = {} even though {} is greater than zero. {} heat gain " + "cannot be calculated unless a controlled Zone (appear in a ZoneHVAC:EquipmentConnections object.) is " + "defined to determine the environmental temperature surrounding the {}.", + RoutineName, + CurrentModuleObject, + objName, + cAlphaFieldNames(alphaFieldNum), + Alphas(alphaFieldNum), + cNumericFieldNames(numericFieldNum), + heatGainLabel, + surroundingLabel)); + ErrorsFound = true; + } + } else if (!lNumericBlanks(numericFieldNum) && lAlphaBlanks(alphaFieldNum)) { + ShowWarningError( + state, + EnergyPlus::format("{}{}=\"{}\", {} not found even though {} is greater than zero. {} heat gain will not be calculated unless " + "a Zone is defined to determine the environmental temperature surrounding the {}.", + RoutineName, + CurrentModuleObject, + objName, + cAlphaFieldNames(alphaFieldNum), + cNumericFieldNames(numericFieldNum), + heatGainLabel, + surroundingLabel)); + } else if (lNumericBlanks(numericFieldNum) && !lAlphaBlanks(alphaFieldNum)) { + ShowWarningError(state, + EnergyPlus::format("{}{}=\"{}\", {} will not be used and {} heat gain will not be calculated because {} was blank.", + RoutineName, + CurrentModuleObject, + objName, + cAlphaFieldNames(alphaFieldNum), + heatGainLabel, + cNumericFieldNames(numericFieldNum))); + } +} + +// Helper: exactly one of two numeric fields must be supplied for compressor rating. +static void readOneOfTwoRatingFields(EnergyPlusData &state, + bool &ErrorsFound, + std::string_view RoutineName, + std::string_view CurrentModuleObject, + const std::string &compName, + const Array1D &Numbers, + const Array1D_bool &lNumericBlanks, + const Array1D_string &cNumericFieldNames, + int n1, + int n2, + CompRatingType type1, + CompRatingType type2, + CompRatingType &ratingType, + Real64 &ratedValue) +{ + if (((!lNumericBlanks(n1)) && (!lNumericBlanks(n2))) || (lNumericBlanks(n1) && lNumericBlanks(n2))) { + ShowSevereError(state, + EnergyPlus::format("{}{}=\"{}\"One, and Only One of {} or {}", + RoutineName, + CurrentModuleObject, + compName, + cNumericFieldNames(n1), + cNumericFieldNames(n2))); + ShowContinueError(state, "Must Be Entered. Check input value choices."); + ErrorsFound = true; + } else if (!lNumericBlanks(n1)) { + ratingType = type1; + ratedValue = Numbers(n1); + } else { + ratingType = type2; + ratedValue = Numbers(n2); + } +} + +namespace { + + // Helper: iterate a 1-based collection checking NumSysAttach, counting unused components. + template + void checkUnusedComponents(EnergyPlusData &state, + std::string_view RoutineName, + CollectionType &collection, + int numItems, + int &unusedCount, + std::string_view idfType, + OnMultipleFn onMultiple, + WarnSummaryFn warnSummary) + { + unusedCount = 0; + for (int i = 1; i <= numItems; ++i) { + if (collection(i).NumSysAttach == 1) { + continue; + } + if (collection(i).NumSysAttach < 1) { + ++unusedCount; + if (state.dataGlobal->DisplayExtraWarnings) { + ShowWarningError(state, EnergyPlus::format("{}: {}=\"{}\" unused. ", RoutineName, idfType, collection(i).Name)); + } + } + if (collection(i).NumSysAttach > 1) { + onMultiple(i); + } + } + if (unusedCount > 0 && !state.dataGlobal->DisplayExtraWarnings) { + warnSummary(unusedCount); + } + } + +} // anonymous namespace + void GetRefrigerationInput(EnergyPlusData &state) { @@ -479,8 +1108,6 @@ void GetRefrigerationInput(EnergyPlusData &state) int NumWalkIns(0); // Number of walk ins int RefrigSysNum(0); Real64 DeltaHPhaseChange(0.0); // Secondary loop enthalpy change in condenser w overfeed system (J/g) - Real64 DelTempMin(0.0); // min temperature for heat rej curve for air cooled condenser (C) - Real64 DelTempMax(0.0); // max temperature for heat rej curve for air cooled condenser (C) Real64 DensityBrineRated(0.0); // density of circ fluid in secondary loop Real64 DensityPhaseChange(0.0); // Secondary loop density at condensing temperature w overfeed system (g/m3) Real64 NominalTotalCompCapLP(0.0); // Total of nominal low pressure compressor capacities, used for rough input check (W) (Transcritical CO2) @@ -691,42 +1318,206 @@ void GetRefrigerationInput(EnergyPlusData &state) cNumericFieldNames.allocate(MaxNumNumbersAll); lAlphaBlanks.dimension(MaxNumAlphasAll, true); lNumericBlanks.dimension(MaxNumNumbersAll, true); + + // Helper lambda to read the three optional refrigerant-inventory fields that appear on every + // condenser and gas-cooler object. Zeros each field first, then overwrites from Numbers if + // the corresponding input field is not blank. + auto readRefrigInventory = [&](Real64 &refOpCharge, Real64 &refReceiverInv, Real64 &refPipingInv, int n1, int n2, int n3) { + refOpCharge = 0.0; + refReceiverInv = 0.0; + refPipingInv = 0.0; + if (!lNumericBlanks(n1)) { + refOpCharge = Numbers(n1); + } + if (!lNumericBlanks(n2)) { + refReceiverInv = Numbers(n2); + } + if (!lNumericBlanks(n3)) { + refPipingInv = Numbers(n3); + } + }; + + // Helper lambda that wraps the repeated 11-argument getObjectItem call. The + // CurrentModuleObject string is captured by reference so each call site only + // needs to supply the 1-based item number. + auto getItem = [&](int itemNum) { + state.dataInputProcessing->inputProcessor->getObjectItem(state, + CurrentModuleObject, + itemNum, + Alphas, + NumAlphas, + Numbers, + NumNumbers, + IOStatus, + lNumericBlanks, + lAlphaBlanks, + cAlphaFieldNames, + cNumericFieldNames); + }; + + // Helper lambda to initialise the NumSysAttach counter and pre-allocate the SysNum + // array on each condenser / gas-cooler object. Uses an abbreviated-function-template + // (C++20 auto parameter) so it works for both RefrigCondenserData and GasCoolerData + // without code duplication. + auto initSysAttach = [&](auto &obj, int numSystems) { + obj.NumSysAttach = 0; + if (!allocated(obj.SysNum)) { + obj.SysNum.allocate(numSystems); + } + }; + + // Helper lambda used in the System / TranscriticalSystem WalkIn assignment loops. + // For detailed systems, a DefrostCapacity of -99 is a sentinel meaning the field was + // left blank; blank input is only a warning for compressor racks but an error for + // detailed systems that need capacity for both fluid and electric defrost types. + auto checkWalkInDefrostCap = [&](int walkInID) { + if (WalkIn(walkInID).DefrostCapacity <= -98.0) { + ShowSevereError(state, + EnergyPlus::format("{}Refrigeration:WalkIn=\"{}\", Defrost capacity must be greater than or equal to 0 W for " + "electric and hotfluid defrost types", + RoutineName, + WalkIn(walkInID).Name)); + ErrorsFound = true; + } + }; + + // Helper lambda: accumulate case loads for one temperature level of a TranscriticalSystem. + // Iterates the supplied caseNumArray (1-based, length numCases), increments NumSysAttach, + // adds to nomCapAccum and to the system's RefInventory, and tracks the running minimum + // design evaporating temperature in TEvapDesign. + auto accumTransSysCases = [&](const auto &caseNumArray, int numCases, Real64 &nomCapAccum, Real64 &TEvapDesign, Real64 &refInventory) { + for (int caseIndex = 1; caseIndex <= numCases; ++caseIndex) { + int cn = caseNumArray(caseIndex); + ++RefrigCase(cn).NumSysAttach; + nomCapAccum += RefrigCase(cn).DesignRatedCap; + refInventory += RefrigCase(cn).DesignRefrigInventory; + if (caseIndex == 1) { + TEvapDesign = RefrigCase(cn).EvapTempDesign; + } else { + TEvapDesign = min(RefrigCase(cn).EvapTempDesign, TEvapDesign); + } + } + }; + + // Helper lambda: accumulate walkin loads for one temperature level of a TranscriticalSystem. + // numCasesOnLevel is the number of cases already assigned at this temperature level; when it + // is 0 and WalkInIndex == 1 the first walkin sets TEvapDesign rather than taking the min. + auto accumTransSysWalkIns = + [&](const auto &walkInNumArray, int numWalkIns, Real64 &nomCapAccum, Real64 &TEvapDesign, int numCasesOnLevel, Real64 &refInventory) { + for (int wi = 1; wi <= numWalkIns; ++wi) { + int wid = walkInNumArray(wi); + ++WalkIn(wid).NumSysAttach; + nomCapAccum += WalkIn(wid).DesignRatedCap; + refInventory += WalkIn(wid).DesignRefrigInventory; + checkWalkInDefrostCap(wid); + if ((wi == 1) && (numCasesOnLevel == 0)) { + TEvapDesign = WalkIn(wid).TEvapDesign; + } else { + TEvapDesign = min(WalkIn(wid).TEvapDesign, TEvapDesign); + } + } + }; + + // Helper lambda: look up and assign one subcooler slot for a detailed refrigeration system. + // alphaIdx is the 1-based index into Alphas[] for this subcooler field; subcoolerSlot is + // the 1-based slot in System(RefrigSysNum).SubcoolerNum to fill. Does nothing when the + // alpha field is blank. Sets ErrorsFound on a bad name; on a good name, copies the system's + // CoilFlag to the subcooler. The RefrigSysNum variable is captured by reference so the lambda + // always operates on the current system being processed. + auto assignSubcoolerToSystem = [&](int alphaIdx, int subcoolerSlot) { + if (lAlphaBlanks(alphaIdx)) { + return; + } + System(RefrigSysNum).SubcoolerNum(subcoolerSlot) = + state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Refrigeration:Subcooler", Alphas(alphaIdx)); + if (System(RefrigSysNum).SubcoolerNum(subcoolerSlot) <= 0) { + ShowSevereError(state, + EnergyPlus::format(R"({}{}="{}", has an invalid {} defined as "{}".)", + RoutineName, + CurrentModuleObject, + System(RefrigSysNum).Name, + cAlphaFieldNames(alphaIdx), + Alphas(alphaIdx))); + ErrorsFound = true; + } else { + Subcooler(System(RefrigSysNum).SubcoolerNum(subcoolerSlot)).CoilFlag = System(RefrigSysNum).CoilFlag; + } + }; + + // Helper lambda: if alpha field n is blank assign the always-on schedule, otherwise look up the + // schedule by name, report a severe error if not found, and validate the 0-1 min/max range. + // eoh must be the ErrorObjectHeader for the current object being read (passed by const-ref so + // the lambda does not need to be redefined on each loop iteration). + auto getScheduleOrAlwaysOn = [&](const ErrorObjectHeader &eoh, int alphaNum, Sched::Schedule *&schedOut) { + if (lAlphaBlanks(alphaNum)) { + schedOut = Sched::GetScheduleAlwaysOn(state); + } else if ((schedOut = Sched::GetSchedule(state, Alphas(alphaNum))) == nullptr) { + ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(alphaNum), Alphas(alphaNum)); + ErrorsFound = true; + } else if (!schedOut->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { + Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(alphaNum), Alphas(alphaNum), Clusive::In, 0.0, Clusive::In, 1.0); + ErrorsFound = true; + } + }; + + // Helper lambda: required schedule field – blank is an error (ShowSevereEmptyField), otherwise look up by + // name, error if not found, and validate the 0-1 min/max range. + auto getRequiredSchedule = [&](const ErrorObjectHeader &eoh, int alphaNum, Sched::Schedule *&schedOut) { + if (lAlphaBlanks(alphaNum)) { + ShowSevereEmptyField(state, eoh, cAlphaFieldNames(alphaNum)); + ErrorsFound = true; + } else if ((schedOut = Sched::GetSchedule(state, Alphas(alphaNum))) == nullptr) { + ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(alphaNum), Alphas(alphaNum)); + ErrorsFound = true; + } else if (!schedOut->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { + Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(alphaNum), Alphas(alphaNum), Clusive::In, 0.0, Clusive::In, 1.0); + ErrorsFound = true; + } + }; + + // Helper lambda: drip-down schedule field – if blank, reuse the defrost schedule pointer; otherwise look up by + // name, error if not found, and validate the 0-1 min/max range. + auto getDripDownScheduleOrDefault = [&](const ErrorObjectHeader &eoh, int alphaNum, Sched::Schedule *defrostSched, Sched::Schedule *&schedOut) { + if (lAlphaBlanks(alphaNum)) { + schedOut = defrostSched; + } else if ((schedOut = Sched::GetSchedule(state, Alphas(alphaNum))) == nullptr) { + ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(alphaNum), Alphas(alphaNum)); + ErrorsFound = true; + } else if (!schedOut->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { + Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(alphaNum), Alphas(alphaNum), Clusive::In, 0.0, Clusive::In, 1.0); + ErrorsFound = true; + } + }; + // bbb stovall note for future - for all curve entries, see if need fail on type or if can allow table input if (state.dataRefrigCase->NumSimulationCases > 0) { CurrentModuleObject = "Refrigeration:Case"; int NumDisplayCases(0); // Counter for refrigerated cases in GetInput do loop for (int CaseNum = 1; CaseNum <= state.dataRefrigCase->NumSimulationCases; ++CaseNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CaseNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(CaseNum); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; ++NumDisplayCases; + // Lambda for the repeated "must be >= 0 " error in this loop. + auto showCaseRangeError = [&](int numNum, std::string_view units = "W/m") { + ShowSevereError(state, + EnergyPlus::format("{}{}=\"{}\", {} must be greater than or equal to 0 {}", + RoutineName, + CurrentModuleObject, + RefrigCase(CaseNum).Name, + cNumericFieldNames(numNum), + units)); + ErrorsFound = true; + }; + AlphaNum = 1; RefrigCase(CaseNum).Name = Alphas(AlphaNum); AlphaNum = 2; - if (lAlphaBlanks(AlphaNum)) { - RefrigCase(CaseNum).availSched = Sched::GetScheduleAlwaysOn(state); - } else if ((RefrigCase(CaseNum).availSched = Sched::GetSchedule(state, Alphas(AlphaNum))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum)); - ErrorsFound = true; - } else if (!RefrigCase(CaseNum).availSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } + getScheduleOrAlwaysOn(eoh, AlphaNum, RefrigCase(CaseNum).availSched); // Get the Zone node number from the zone name entered by the user RefrigCase(CaseNum).ZoneName = Alphas(3); @@ -852,13 +1643,7 @@ void GetRefrigerationInput(EnergyPlusData &state) if (!lNumericBlanks(NumNum)) { RefrigCase(CaseNum).STDFanPower = Numbers(NumNum); if (Numbers(NumNum) < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be greater than or equal to 0 W/m", - RoutineName, - CurrentModuleObject, - RefrigCase(CaseNum).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; + showCaseRangeError(NumNum); } } else { // blank use default of 75 W/m RefrigCase(CaseNum).STDFanPower = 75.0; @@ -868,13 +1653,7 @@ void GetRefrigerationInput(EnergyPlusData &state) if (!lNumericBlanks(NumNum)) { RefrigCase(CaseNum).OperatingFanPower = Numbers(NumNum); if (Numbers(NumNum) < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be greater than or equal to 0 W/m", - RoutineName, - CurrentModuleObject, - RefrigCase(CaseNum).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; + showCaseRangeError(NumNum); } } else { // if blank set = to std fan power RefrigCase(CaseNum).OperatingFanPower = RefrigCase(CaseNum).STDFanPower; @@ -884,13 +1663,7 @@ void GetRefrigerationInput(EnergyPlusData &state) if (!lNumericBlanks(NumNum)) { RefrigCase(CaseNum).RatedLightingPower = Numbers(NumNum); if (Numbers(NumNum) < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be greater than or equal to 0 W/m", - RoutineName, - CurrentModuleObject, - RefrigCase(CaseNum).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; + showCaseRangeError(NumNum); } } else { // blank input - use default of 90 W/m RefrigCase(CaseNum).RatedLightingPower = 90.0; @@ -900,27 +1673,13 @@ void GetRefrigerationInput(EnergyPlusData &state) if (!lNumericBlanks(NumNum)) { RefrigCase(CaseNum).LightingPower = Numbers(NumNum); if (Numbers(NumNum) < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be greater than or equal to 0 W/m", - RoutineName, - CurrentModuleObject, - RefrigCase(CaseNum).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; + showCaseRangeError(NumNum); } } else { // blank input so set lighting power equal to rated/std lighting power RefrigCase(CaseNum).LightingPower = RefrigCase(CaseNum).RatedLightingPower; } // blank input - if (lAlphaBlanks(6)) { - RefrigCase(CaseNum).lightingSched = Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but defaults to constant-1.0 - } else if ((RefrigCase(CaseNum).lightingSched = Sched::GetSchedule(state, Alphas(6))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(6), Alphas(6)); - ErrorsFound = true; - } else if (!RefrigCase(CaseNum).lightingSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(6), Alphas(6), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } + getScheduleOrAlwaysOn(eoh, 6, RefrigCase(CaseNum).lightingSched); NumNum = 12; RefrigCase(CaseNum).LightingFractionToCase = 1.0; // default value @@ -942,25 +1701,13 @@ void GetRefrigerationInput(EnergyPlusData &state) NumNum = 13; RefrigCase(CaseNum).AntiSweatPower = Numbers(NumNum); if (Numbers(NumNum) < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be greater than or equal to 0 W/m", - RoutineName, - CurrentModuleObject, - RefrigCase(CaseNum).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; + showCaseRangeError(NumNum); } NumNum = 14; RefrigCase(CaseNum).MinimumASPower = Numbers(NumNum); if (Numbers(NumNum) < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be greater than or equal to 0 W/m", - RoutineName, - CurrentModuleObject, - RefrigCase(CaseNum).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; + showCaseRangeError(NumNum); } RefrigCase(CaseNum).AntiSweatControlType = static_cast(getEnumValue(asHtrCtrlTypeNamesUC, Alphas(7))); @@ -1005,13 +1752,7 @@ void GetRefrigerationInput(EnergyPlusData &state) NumNum = 16; RefrigCase(CaseNum).Height = Numbers(NumNum); if (Numbers(NumNum) < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be greater than or equal to 0 m", - RoutineName, - CurrentModuleObject, - RefrigCase(CaseNum).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; + showCaseRangeError(NumNum, "m"); } if (RefrigCase(CaseNum).Height <= 0.0 && RefrigCase(CaseNum).AntiSweatControlType == ASHtrCtrlType::HeatBalance) { @@ -1084,13 +1825,7 @@ void GetRefrigerationInput(EnergyPlusData &state) if (!lNumericBlanks(NumNum)) { RefrigCase(CaseNum).DefrostPower = Numbers(NumNum); if (Numbers(NumNum) < 0.0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be greater than or equal to 0 W/m", - RoutineName, - CurrentModuleObject, - RefrigCase(CaseNum).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; + showCaseRangeError(NumNum); } // disregard defrost power for Off-Cycle or None defrost types if ((DefType == RefCaseDefrostType::OffCycle || DefType == RefCaseDefrostType::None) && (RefrigCase(CaseNum).DefrostPower > 0.0)) { @@ -1121,16 +1856,8 @@ void GetRefrigerationInput(EnergyPlusData &state) ErrorsFound = true; } - if (RefrigCase(CaseNum).defrostType == RefCaseDefrostType::None) { - } else if (lAlphaBlanks(9)) { - ShowSevereEmptyField(state, eoh, cAlphaFieldNames(9)); - ErrorsFound = true; - } else if ((RefrigCase(CaseNum).defrostSched = Sched::GetSchedule(state, Alphas(9))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(9), Alphas(9)); - ErrorsFound = true; - } else if (!RefrigCase(CaseNum).defrostSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(9), Alphas(9), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; + if (RefrigCase(CaseNum).defrostType != RefCaseDefrostType::None) { + getRequiredSchedule(eoh, 9, RefrigCase(CaseNum).defrostSched); } // Note that next section counting number cycles and setting maxkgfrost not used now, but may be in the future. @@ -1163,15 +1890,7 @@ void GetRefrigerationInput(EnergyPlusData &state) } // some defrost types do not use drip-down schedules, use same defrost schedule pointer in that case - if (lAlphaBlanks(10)) { - RefrigCase(CaseNum).defrostDripDownSched = RefrigCase(CaseNum).defrostSched; - } else if ((RefrigCase(CaseNum).defrostDripDownSched = Sched::GetSchedule(state, Alphas(10))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(10), Alphas(10)); - ErrorsFound = true; - } else if (!RefrigCase(CaseNum).defrostDripDownSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(10), Alphas(10), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } + getDripDownScheduleOrDefault(eoh, 10, RefrigCase(CaseNum).defrostSched, RefrigCase(CaseNum).defrostDripDownSched); RefrigCase(CaseNum).DefrostEnergyCurveType = static_cast(getEnumValue(energyEqnFormNamesUC, Alphas(11))); if (RefrigCase(CaseNum).DefrostEnergyCurveType == EnergyEqnForm::Invalid) { @@ -1375,32 +2094,13 @@ void GetRefrigerationInput(EnergyPlusData &state) if (state.dataRefrigCase->NumSimulationWalkIns > 0) { CurrentModuleObject = "Refrigeration:WalkIn"; for (int WalkInID = 1; WalkInID <= state.dataRefrigCase->NumSimulationWalkIns; ++WalkInID) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - WalkInID, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(WalkInID); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; WalkIn(WalkInID).Name = Alphas(1); - if (lAlphaBlanks(2)) { - WalkIn(WalkInID).availSched = Sched::GetScheduleAlwaysOn(state); - } else if ((WalkIn(WalkInID).availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), Alphas(2)); - ErrorsFound = true; - } else if (!WalkIn(WalkInID).availSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(2), Alphas(2), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } + getScheduleOrAlwaysOn(eoh, 2, WalkIn(WalkInID).availSched); WalkIn(WalkInID).DesignRatedCap = Numbers(1); if (Numbers(1) <= 0.0) { @@ -1433,15 +2133,7 @@ void GetRefrigerationInput(EnergyPlusData &state) } AlphaNum = 3; - if (lAlphaBlanks(AlphaNum)) { - WalkIn(WalkInID).heaterSched = Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but defaults to constant-1.0 - } else if ((WalkIn(WalkInID).heaterSched = Sched::GetSchedule(state, Alphas(AlphaNum))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum)); - ErrorsFound = true; - } else if (!WalkIn(WalkInID).heaterSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } + getScheduleOrAlwaysOn(eoh, AlphaNum, WalkIn(WalkInID).heaterSched); if (!lNumericBlanks(5) && Numbers(5) > 0.0) { WalkIn(WalkInID).CoilFanPower = Numbers(5); @@ -1478,15 +2170,7 @@ void GetRefrigerationInput(EnergyPlusData &state) } AlphaNum = 4; - if (lAlphaBlanks(AlphaNum)) { - WalkIn(WalkInID).lightingSched = Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but defaults to constant-1.0 - } else if ((WalkIn(WalkInID).lightingSched = Sched::GetSchedule(state, Alphas(AlphaNum))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum)); - ErrorsFound = true; - } else if (!WalkIn(WalkInID).lightingSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } + getScheduleOrAlwaysOn(eoh, AlphaNum, WalkIn(WalkInID).lightingSched); // Input walk-in cooler defrost information AlphaNum = 5; @@ -1510,69 +2194,29 @@ void GetRefrigerationInput(EnergyPlusData &state) // convert defrost schedule name to pointer AlphaNum = 7; - if (lAlphaBlanks(AlphaNum)) { - ShowSevereEmptyField(state, eoh, cAlphaFieldNames(AlphaNum)); - ErrorsFound = true; - } else if ((WalkIn(WalkInID).defrostSched = Sched::GetSchedule(state, Alphas(AlphaNum))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum)); - ErrorsFound = true; - } else if (!WalkIn(WalkInID).defrostSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } + getRequiredSchedule(eoh, AlphaNum, WalkIn(WalkInID).defrostSched); // convert defrost drip-down schedule name to pointer // some defrost types do not use drip-down schedules, use same defrost schedule pointer in that case AlphaNum = 8; - if (lAlphaBlanks(AlphaNum)) { // blank input so use drip down schedule for defrost - WalkIn(WalkInID).defrostDripDownSched = WalkIn(WalkInID).defrostSched; - } else if ((WalkIn(WalkInID).defrostDripDownSched = Sched::GetSchedule(state, Alphas(AlphaNum))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum)); - ErrorsFound = true; - } else if (!WalkIn(WalkInID).defrostDripDownSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } + getDripDownScheduleOrDefault(eoh, AlphaNum, WalkIn(WalkInID).defrostSched, WalkIn(WalkInID).defrostDripDownSched); - if (WalkIn(WalkInID).defrostType == DefrostType::OffCycle || WalkIn(WalkInID).defrostType == DefrostType::None) { - WalkIn(WalkInID).DefrostCapacity = 0.0; - // Don't even need to read N8 or N9 for those two defrost types. - } else { // have electric or hot gas/brine defrost - if ((lNumericBlanks(8)) || (Numbers(8) <= 0.0)) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and greater than or equal to 0 W for {} {}", - RoutineName, - CurrentModuleObject, - WalkIn(WalkInID).Name, - cNumericFieldNames(8), - cAlphaFieldNames(5), - Alphas(5))); - ErrorsFound = true; - } else { - WalkIn(WalkInID).DefrostCapacity = Numbers(8); - } // Blank or negative N8 - - // defaults for defrost energy fraction are 0.7 for elec defrost and 0.3 for warm fluid - // note this value is only used for temperature terminated defrost control type - if (WalkIn(WalkInID).defrostType == DefrostType::Elec) { - WalkIn(WalkInID).DefEnergyFraction = 0.7; - } - if (WalkIn(WalkInID).defrostType == DefrostType::Fluid) { - WalkIn(WalkInID).DefEnergyFraction = 0.3; - } - if (!lNumericBlanks(9)) { - if ((Numbers(9) > 1.0) || (Numbers(9) < 0.0)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be between 0 and 1, default values will be used.", - RoutineName, - CurrentModuleObject, - WalkIn(WalkInID).Name, - cNumericFieldNames(9))); - } else { - WalkIn(WalkInID).DefEnergyFraction = Numbers(9); - } // number out of range - } // lnumericblanks - } // defrost type + readDefrostCapAndEnergyFraction(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Numbers, + lNumericBlanks, + cNumericFieldNames, + cAlphaFieldNames, + Alphas, + WalkIn(WalkInID).defrostType, + WalkIn(WalkInID).Name, + /*capFieldNum=*/8, + /*fracFieldNum=*/9, + /*defTypeAlphaNum=*/5, + WalkIn(WalkInID).DefrostCapacity, + WalkIn(WalkInID).DefEnergyFraction); // convert restocking schedule name to pointer, default of 0.1 is assigned inside walkin subroutine if blank AlphaNum = 9; @@ -1610,93 +2254,17 @@ void GetRefrigerationInput(EnergyPlusData &state) } } - // Calculate the number of zones exposed to walk-in based on number of input fields, all integer math, - // This approach used because last zone could have less than NumWIFieldsPerZone due to optional values + // Calculate the number of zones exposed to walk-in based on number of input fields, all integer math. + // Ceiling-divide total fields by fields-per-zone, capped at 6. The last zone may supply fewer + // than NumWIFieldsPerZone fields because some per-zone inputs are optional. int NumWIFieldsPerZone = NumWIAlphaFieldsPerZone + NumWINumberFieldsPerZone; int NumWIFieldsTotal = NumNumbers + NumAlphas - NumWIAlphaFieldsBeforeZoneInput - NumWINumberFieldsBeforeZoneInput; - int NumZones = 1; - if (NumWIFieldsTotal > NumWIFieldsPerZone) { - NumZones = 2; - } - if (NumWIFieldsTotal > (2 * NumWIFieldsPerZone)) { - NumZones = 3; - } - if (NumWIFieldsTotal > (3 * NumWIFieldsPerZone)) { - NumZones = 4; - } - if (NumWIFieldsTotal > (4 * NumWIFieldsPerZone)) { - NumZones = 5; - } - if (NumWIFieldsTotal > (5 * NumWIFieldsPerZone)) { - NumZones = 6; - } + int NumZones = min(6, max(1, (NumWIFieldsTotal + NumWIFieldsPerZone - 1) / NumWIFieldsPerZone)); WalkIn(WalkInID).NumZones = NumZones; - // All variables for walk-in/zone interactions need to be allocated after know number of zones + // Allocate all per-zone arrays (idempotent: skips any that are already allocated). // Autodesk Missing initialization added below: At least SensZoneCreditRate was used uninitialized - if (!allocated(WalkIn(WalkInID).ZoneName)) { - WalkIn(WalkInID).ZoneName.allocate(NumZones); - } - if (!allocated(WalkIn(WalkInID).ZoneNum)) { - WalkIn(WalkInID).ZoneNum.allocate(NumZones) = 0; - } - if (!allocated(WalkIn(WalkInID).ZoneNodeNum)) { - WalkIn(WalkInID).ZoneNodeNum.allocate(NumZones) = 0; - } - if (!allocated(WalkIn(WalkInID).SurfaceArea)) { - WalkIn(WalkInID).SurfaceArea.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).UValue)) { - WalkIn(WalkInID).UValue.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).UValueGlassDr)) { - WalkIn(WalkInID).UValueGlassDr.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).glassDoorOpenScheds)) { - WalkIn(WalkInID).glassDoorOpenScheds.allocate(NumZones) = nullptr; // What is this? - } - if (!allocated(WalkIn(WalkInID).AreaGlassDr)) { - WalkIn(WalkInID).AreaGlassDr.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).HeightGlassDr)) { - WalkIn(WalkInID).HeightGlassDr.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).UValueStockDr)) { - WalkIn(WalkInID).UValueStockDr.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).stockDoorOpenScheds)) { - WalkIn(WalkInID).stockDoorOpenScheds.allocate(NumZones) = nullptr; // What is this? - } - if (!allocated(WalkIn(WalkInID).StockDoorProtectType)) { - WalkIn(WalkInID).StockDoorProtectType.allocate(NumZones) = WIStockDoor::Invalid; - } - if (!allocated(WalkIn(WalkInID).AreaStockDr)) { - WalkIn(WalkInID).AreaStockDr.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).HeightStockDr)) { - WalkIn(WalkInID).HeightStockDr.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).SensZoneCreditRate)) { - WalkIn(WalkInID).SensZoneCreditRate.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).SensZoneCreditCoolRate)) { - WalkIn(WalkInID).SensZoneCreditCoolRate.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).SensZoneCreditCool)) { - WalkIn(WalkInID).SensZoneCreditCool.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).SensZoneCreditHeatRate)) { - WalkIn(WalkInID).SensZoneCreditHeatRate.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).SensZoneCreditHeat)) { - WalkIn(WalkInID).SensZoneCreditHeat.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).LatZoneCreditRate)) { - WalkIn(WalkInID).LatZoneCreditRate.allocate(NumZones) = 0.0; - } - if (!allocated(WalkIn(WalkInID).LatZoneCredit)) { - WalkIn(WalkInID).LatZoneCredit.allocate(NumZones) = 0.0; - } + WalkIn(WalkInID).allocateZoneArrays(NumZones); int AStart = NumWIAlphaFieldsBeforeZoneInput + 1; int NStart = NumWINumberFieldsBeforeZoneInput + 1; @@ -1750,61 +2318,57 @@ void GetRefrigerationInput(EnergyPlusData &state) } } - // start IF set for glass doors in this zone - WalkIn(WalkInID).AreaGlassDr(ZoneID) = 0.0; - WalkIn(WalkInID).HeightGlassDr(ZoneID) = 0.0; - WalkIn(WalkInID).UValueGlassDr(ZoneID) = 0.0; - if (!lNumericBlanks(NStart + 2)) { - WalkIn(WalkInID).AreaGlassDr(ZoneID) = Numbers(NStart + 2); - - WalkIn(WalkInID).HeightGlassDr(ZoneID) = DefaultWIHeightGlassDr; - if (!lNumericBlanks(NStart + 3)) { - WalkIn(WalkInID).HeightGlassDr(ZoneID) = Numbers(NStart + 3); - } - - WalkIn(WalkInID).UValueGlassDr(ZoneID) = DefaultWIUValueGlassDr; - if (!lNumericBlanks(NStart + 4)) { - WalkIn(WalkInID).UValueGlassDr(ZoneID) = Numbers(NStart + 4); - } - - // convert door opening schedule name to pointer, default of 0.1 is assigned inside walkin subroutine if blank - if (lAlphaBlanks(AStart + 1)) { - } else if ((WalkIn(WalkInID).glassDoorOpenScheds(ZoneID) = Sched::GetSchedule(state, Alphas(AStart + 1))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AStart + 1), Alphas(AStart + 1)); - ErrorsFound = true; - } else if (!WalkIn(WalkInID).glassDoorOpenScheds(ZoneID)->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AStart + 1), Alphas(AStart + 1), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } // blank on door opening schedule (AStart + 1) - } // have glassdoor area facing zone (blank on lNumericBlanks(NStart+2)) - - // start IF set for stock doors in this zone - WalkIn(WalkInID).AreaStockDr(ZoneID) = 0.0; - WalkIn(WalkInID).HeightStockDr(ZoneID) = 0.0; - WalkIn(WalkInID).UValueStockDr(ZoneID) = 0.0; - if (!lNumericBlanks(NStart + 5)) { - WalkIn(WalkInID).AreaStockDr(ZoneID) = Numbers(NStart + 5); - - WalkIn(WalkInID).HeightStockDr(ZoneID) = DefaultWIHeightStockDr; - if (!lNumericBlanks(NStart + 6)) { - WalkIn(WalkInID).HeightStockDr(ZoneID) = Numbers(NStart + 6); - } - - WalkIn(WalkInID).UValueStockDr(ZoneID) = DefaultWIUValueStockDr; - if (!lNumericBlanks(NStart + 7)) { - WalkIn(WalkInID).UValueStockDr(ZoneID) = Numbers(NStart + 7); - } - - // convert door opening schedule name to pointer, default of 0.1 is assigned inside walkin subroutine if blank - if (lAlphaBlanks(AStart + 2)) { - } else if ((WalkIn(WalkInID).stockDoorOpenScheds(ZoneID) = Sched::GetSchedule(state, Alphas(AStart + 2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AStart + 2), Alphas(AStart + 2)); - ErrorsFound = true; - } else if (!WalkIn(WalkInID).stockDoorOpenScheds(ZoneID)->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AStart + 2), Alphas(AStart + 2), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } // blank on door opening schedule (AStart + 2) - + // Helper lambda: read the common area/height/U-value/schedule fields for one + // door type in a walk-in zone. nArea/nHeight/nUValue are numeric field offsets + // from NStart; aSchedule is the alpha field offset from AStart. + // defaultHeight and defaultUValue are the default values for that door type. + // schedOut is the schedule pointer member to fill; area/height/uvalue are the + // per-zone array members to fill. + // Returns true if the area field was present (i.e., this door type is present in + // this zone), allowing the caller to perform additional door-type-specific checks. + // Glass doors in this zone + readWalkInDoor(state, + ErrorsFound, + eoh, + Numbers, + lNumericBlanks, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + NStart, + AStart, + 2, + 3, + 4, + 1, + DefaultWIHeightGlassDr, + DefaultWIUValueGlassDr, + WalkIn(WalkInID).AreaGlassDr(ZoneID), + WalkIn(WalkInID).HeightGlassDr(ZoneID), + WalkIn(WalkInID).UValueGlassDr(ZoneID), + WalkIn(WalkInID).glassDoorOpenScheds(ZoneID)); + + // Stock doors in this zone + if (readWalkInDoor(state, + ErrorsFound, + eoh, + Numbers, + lNumericBlanks, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + NStart, + AStart, + 5, + 6, + 7, + 2, + DefaultWIHeightStockDr, + DefaultWIUValueStockDr, + WalkIn(WalkInID).AreaStockDr(ZoneID), + WalkIn(WalkInID).HeightStockDr(ZoneID), + WalkIn(WalkInID).UValueStockDr(ZoneID), + WalkIn(WalkInID).stockDoorOpenScheds(ZoneID))) { if (lAlphaBlanks(AStart + 3)) { // default air curtain WalkIn(WalkInID).StockDoorProtectType(ZoneID) = WIStockDoor::AirCurtain; @@ -1813,7 +2377,7 @@ void GetRefrigerationInput(EnergyPlusData &state) ShowSevereInvalidKey(state, eoh, cAlphaFieldNames(AStart + 3), Alphas(AStart + 3)); ErrorsFound = true; } // stock door protection (AStart + 3) blank - } // have Stockdoor area facing zone + } // have stock door area facing zone AStart += NumWIAlphaFieldsPerZone; NStart += NumWINumberFieldsPerZone; @@ -1828,18 +2392,7 @@ void GetRefrigerationInput(EnergyPlusData &state) for (int CoilID = 1; CoilID <= state.dataRefrigCase->NumSimulationRefrigAirChillers; ++CoilID) { // A1 AlphaNum = 1; - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CoilID, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(CoilID); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; @@ -1847,15 +2400,7 @@ void GetRefrigerationInput(EnergyPlusData &state) // A2 ++AlphaNum; - if (lAlphaBlanks(AlphaNum)) { - WarehouseCoil(CoilID).availSched = Sched::GetScheduleAlwaysOn(state); - } else if ((WarehouseCoil(CoilID).availSched = Sched::GetSchedule(state, Alphas(AlphaNum))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum)); - ErrorsFound = true; - } else if (!WarehouseCoil(CoilID).availSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } + getScheduleOrAlwaysOn(eoh, AlphaNum, WarehouseCoil(CoilID).availSched); // Input capacity rating type // bbbbb input values (DT1 or DTM type)translate DT1 to DTm here because node will give avg temp? @@ -1879,6 +2424,17 @@ void GetRefrigerationInput(EnergyPlusData &state) // Here have to do select case with one numeric field with units of W and the second with units of W/deltaC, // (RatedRH field only used for RatedCapacityTotal type) + // Lambda used by every switch case below to issue the same "must be > 0" error. + auto showCoilCapError = [&](int numNum, std::string_view units = "W") { + ShowSevereError(state, + EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 {}", + RoutineName, + CurrentModuleObject, + WarehouseCoil(CoilID).Name, + cNumericFieldNames(numNum), + units)); + ErrorsFound = true; + }; { // Why is this a new scope switch (WarehouseCoil(CoilID).ratingType) { case RatingType::UnitLoadFactorSens: { @@ -1887,13 +2443,7 @@ void GetRefrigerationInput(EnergyPlusData &state) if (!lNumericBlanks(NumNum) && Numbers(NumNum) > 0.0) { WarehouseCoil(CoilID).UnitLoadFactorSens = Numbers(NumNum); } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W/C", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; + showCoilCapError(NumNum, "W/C"); } } break; @@ -1919,188 +2469,38 @@ void GetRefrigerationInput(EnergyPlusData &state) WarehouseCoil(CoilID).RatedRH = Numbers(NumNum) / 100.0; } } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; - } - } break; - - case RatingType::EuropeanSC1Std: { - // N2 - NumNum = 2; // advance past rating in W/C to rating in W at N2 - if (!lNumericBlanks(NumNum) && Numbers(NumNum) > 0.0) { - WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum); - WarehouseCoil(CoilID).SCIndex = 1; - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; - } - } break; - - case RatingType::EuropeanSC1Nom: { - // N2 - NumNum = 2; // advance past rating in W/C to rating in W at N2 - if (!lNumericBlanks(NumNum) && Numbers(NumNum) > 0.0) { - WarehouseCoil(CoilID).RatedCapTotal = Numbers(NumNum); - WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum) / EuropeanWetCoilFactor[0]; - WarehouseCoil(CoilID).SCIndex = 1; - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; - } - } break; - - case RatingType::EuropeanSC2Std: { - // N2 - NumNum = 2; // advance past rating in W/C to rating in W at N2 - if (!lNumericBlanks(NumNum) && Numbers(NumNum) > 0.0) { - WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum); - WarehouseCoil(CoilID).SCIndex = 2; - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; - } - } break; - - case RatingType::EuropeanSC2Nom: { - // N2 - NumNum = 2; // advance past rating in W/C to rating in W at N2 - if (!lNumericBlanks(NumNum) && Numbers(NumNum) > 0.0) { - WarehouseCoil(CoilID).RatedCapTotal = Numbers(NumNum); - WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum) / EuropeanWetCoilFactor[1]; - WarehouseCoil(CoilID).SCIndex = 2; - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; - } - } break; - - case RatingType::EuropeanSC3Std: { - // N2 - NumNum = 2; // advance past rating in W/C to rating in W at N2 - if (!lNumericBlanks(NumNum) && Numbers(NumNum) > 0.0) { - WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum); - WarehouseCoil(CoilID).SCIndex = 3; - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; - } - } break; - - case RatingType::EuropeanSC3Nom: { - // N2 - NumNum = 2; // advance past rating in W/C to rating in W at N2 - if (!lNumericBlanks(NumNum) && Numbers(NumNum) > 0.0) { - WarehouseCoil(CoilID).RatedCapTotal = Numbers(NumNum); - WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum) / EuropeanWetCoilFactor[2]; - WarehouseCoil(CoilID).SCIndex = 3; - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; - } - } break; - - case RatingType::EuropeanSC4Std: { - // N2 - NumNum = 2; // advance past rating in W/C to rating in W at N2 - if (!lNumericBlanks(NumNum) && Numbers(NumNum) > 0.0) { - WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum); - WarehouseCoil(CoilID).SCIndex = 4; - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; - } - } break; - - case RatingType::EuropeanSC4Nom: { - // N2 - NumNum = 2; // advance past rating in W/C to rating in W at N2 - if (!lNumericBlanks(NumNum) && Numbers(NumNum) > 0.0) { - WarehouseCoil(CoilID).RatedCapTotal = Numbers(NumNum); - WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum) / EuropeanWetCoilFactor[3]; - WarehouseCoil(CoilID).SCIndex = 4; - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; - } - } break; - - case RatingType::EuropeanSC5Std: { - // N2 - NumNum = 2; // advance past rating in W/C to rating in W at N2 - if (!lNumericBlanks(NumNum) && Numbers(NumNum) > 0.0) { - WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum); - WarehouseCoil(CoilID).SCIndex = 5; - } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; + showCoilCapError(NumNum); } } break; + case RatingType::EuropeanSC1Std: + case RatingType::EuropeanSC1Nom: + case RatingType::EuropeanSC2Std: + case RatingType::EuropeanSC2Nom: + case RatingType::EuropeanSC3Std: + case RatingType::EuropeanSC3Nom: + case RatingType::EuropeanSC4Std: + case RatingType::EuropeanSC4Nom: + case RatingType::EuropeanSC5Std: case RatingType::EuropeanSC5Nom: { - // N2 + // All EuropeanSCx types read N2, set SCIndex = 1..5. + // For Nom types, also set RatedCapTotal and derive RatedSensibleCap via EuropeanWetCoilFactor. + // Map: EuropeanSC1Std=0, EuropeanSC1Nom=1, ..., EuropeanSC5Std=8, EuropeanSC5Nom=9 + // relative to the first European type enum value. + int scOffset = static_cast(WarehouseCoil(CoilID).ratingType) - static_cast(RatingType::EuropeanSC1Std); + int scIndex = scOffset / 2 + 1; // 1..5 + bool isNom = (scOffset % 2) != 0; NumNum = 2; // advance past rating in W/C to rating in W at N2 if (!lNumericBlanks(NumNum) && Numbers(NumNum) > 0.0) { - WarehouseCoil(CoilID).RatedCapTotal = Numbers(NumNum); - WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum) / EuropeanWetCoilFactor[4]; - WarehouseCoil(CoilID).SCIndex = 5; + if (isNom) { + WarehouseCoil(CoilID).RatedCapTotal = Numbers(NumNum); + WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum) / EuropeanWetCoilFactor[scIndex - 1]; + } else { + WarehouseCoil(CoilID).RatedSensibleCap = Numbers(NumNum); + } + WarehouseCoil(CoilID).SCIndex = scIndex; } else { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and be greater than 0 W", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - ErrorsFound = true; + showCoilCapError(NumNum); } } break; @@ -2299,15 +2699,7 @@ void GetRefrigerationInput(EnergyPlusData &state) } ++AlphaNum; // A6 - if (lAlphaBlanks(AlphaNum)) { - WarehouseCoil(CoilID).heaterAvailSched = Sched::GetScheduleAlwaysOn(state); - } else if ((WarehouseCoil(CoilID).heaterAvailSched = Sched::GetSchedule(state, Alphas(AlphaNum))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum)); - ErrorsFound = true; - } else if (!WarehouseCoil(CoilID).heaterAvailSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } + getScheduleOrAlwaysOn(eoh, AlphaNum, WarehouseCoil(CoilID).heaterAvailSched); // Input fan control type ++AlphaNum; // A7 @@ -2371,72 +2763,31 @@ void GetRefrigerationInput(EnergyPlusData &state) // convert defrost schedule name to pointer ++AlphaNum; // A10 - if (lAlphaBlanks(AlphaNum)) { - ShowSevereEmptyField(state, eoh, cAlphaFieldNames(AlphaNum)); - ErrorsFound = true; - } else if ((WarehouseCoil(CoilID).defrostSched = Sched::GetSchedule(state, Alphas(AlphaNum))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum)); - ErrorsFound = true; - } else if (!WarehouseCoil(CoilID).defrostSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } // check for valid schedule name + getRequiredSchedule(eoh, AlphaNum, WarehouseCoil(CoilID).defrostSched); // convert defrost drip-down schedule name to pointer // some defrost types do not use drip-down schedules, use same defrost schedule pointer in that case ++AlphaNum; // A11 - if (lAlphaBlanks(AlphaNum)) { - WarehouseCoil(CoilID).defrostDripDownSched = WarehouseCoil(CoilID).defrostSched; - } else if ((WarehouseCoil(CoilID).defrostDripDownSched = Sched::GetSchedule(state, Alphas(AlphaNum))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum)); - ErrorsFound = true; - } else if (!WarehouseCoil(CoilID).defrostDripDownSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } // check for valid schedule name + getDripDownScheduleOrDefault(eoh, AlphaNum, WarehouseCoil(CoilID).defrostSched, WarehouseCoil(CoilID).defrostDripDownSched); ++NumNum; // N14 - if (WarehouseCoil(CoilID).defrostType == DefrostType::OffCycle || WarehouseCoil(CoilID).defrostType == DefrostType::None) { - WarehouseCoil(CoilID).DefrostCapacity = 0.0; - // Don't even need to read Defrost capacity for those two defrost types. - } else { // have electric or hot gas/brine defrost - if ((lNumericBlanks(NumNum)) || (Numbers(NumNum) <= 0.0)) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be input and greater than or equal to 0 W for {} {}", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum), - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else { - WarehouseCoil(CoilID).DefrostCapacity = Numbers(NumNum); - } // Blank or negative Defrost Capacity - - // defaults for defrost energy fraction are 0.7 for elec defrost and 0.3 for warm fluid - // note this value is only used for temperature terminated defrost control type - if (WarehouseCoil(CoilID).defrostType == DefrostType::Elec) { - WarehouseCoil(CoilID).DefEnergyFraction = 0.7; - } - if (WarehouseCoil(CoilID).defrostType == DefrostType::Fluid) { - WarehouseCoil(CoilID).DefEnergyFraction = 0.3; - } - - ++NumNum; // N15 - if (!lNumericBlanks(NumNum)) { - if ((Numbers(NumNum) > 1.0) || (Numbers(NumNum) < 0.0)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\", {} must be between 0 and 1, default values will be used.", - RoutineName, - CurrentModuleObject, - WarehouseCoil(CoilID).Name, - cNumericFieldNames(NumNum))); - } else { - WarehouseCoil(CoilID).DefEnergyFraction = Numbers(NumNum); - } // number out of range - } // lnumericblanks - } // defrost type + readDefrostCapAndEnergyFraction(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Numbers, + lNumericBlanks, + cNumericFieldNames, + cAlphaFieldNames, + Alphas, + WarehouseCoil(CoilID).defrostType, + WarehouseCoil(CoilID).Name, + /*capFieldNum=*/NumNum, + /*fracFieldNum=*/NumNum + 1, + /*defTypeAlphaNum=*/AlphaNum, + WarehouseCoil(CoilID).DefrostCapacity, + WarehouseCoil(CoilID).DefEnergyFraction); + ++NumNum; // N15 ++AlphaNum; // A12 if (lAlphaBlanks(AlphaNum)) { @@ -2464,18 +2815,7 @@ void GetRefrigerationInput(EnergyPlusData &state) CurrentModuleObject = "ZoneHVAC:RefrigerationChillerSet"; for (int SetID = 1; SetID <= state.dataRefrigCase->NumRefrigChillerSets; ++SetID) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - SetID, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(SetID); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; @@ -2484,15 +2824,7 @@ void GetRefrigerationInput(EnergyPlusData &state) AirChillerSet(SetID).Name = Alphas(AlphaNum); AlphaNum = 2; - if (lAlphaBlanks(AlphaNum)) { - AirChillerSet(SetID).availSched = Sched::GetScheduleAlwaysOn(state); - } else if ((AirChillerSet(SetID).availSched = Sched::GetSchedule(state, Alphas(AlphaNum))) == nullptr) { - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum)); - ErrorsFound = true; - } else if (!AirChillerSet(SetID).availSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) { - Sched::ShowSevereBadMinMax(state, eoh, cAlphaFieldNames(AlphaNum), Alphas(AlphaNum), Clusive::In, 0.0, Clusive::In, 1.0); - ErrorsFound = true; - } + getScheduleOrAlwaysOn(eoh, AlphaNum, AirChillerSet(SetID).availSched); ++AlphaNum; AirChillerSet(SetID).ZoneName = Alphas(AlphaNum); @@ -2591,18 +2923,7 @@ void GetRefrigerationInput(EnergyPlusData &state) if (state.dataRefrigCase->NumSimulationCaseAndWalkInLists > 0) { CurrentModuleObject = "Refrigeration:CaseAndWalkInList"; for (int ListNum = 1; ListNum <= state.dataRefrigCase->NumSimulationCaseAndWalkInLists; ++ListNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - ListNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(ListNum); CaseAndWalkInList(ListNum).Name = Alphas(1); @@ -2690,18 +3011,7 @@ void GetRefrigerationInput(EnergyPlusData &state) for (int RackNum = 1; RackNum <= state.dataRefrigCase->NumRefrigeratedRacks; ++RackNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - RackNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(RackNum); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; @@ -2996,97 +3306,24 @@ void GetRefrigerationInput(EnergyPlusData &state) cAlphaFieldNames(14))); ErrorsFound = true; } else { // (.NOT. lAlphaBlanks(AlphaNum)) - // Entry for Alphas(AlphaNum) can be either a Case, WalkIn, Coil, or CaseAndWalkInList name - int CaseAndWalkInListNum = 0; - int CaseNum = 0; - int WalkInNum = 0; - int CoilNum = 0; - if (state.dataRefrigCase->NumSimulationCaseAndWalkInLists > 0) { - CaseAndWalkInListNum = Util::FindItemInList(Alphas(AlphaNum), CaseAndWalkInList); - } - if (state.dataRefrigCase->NumSimulationCases > 0) { - CaseNum = Util::FindItemInList(Alphas(AlphaNum), RefrigCase); - } - if (state.dataRefrigCase->NumSimulationWalkIns > 0) { - WalkInNum = Util::FindItemInList(Alphas(AlphaNum), WalkIn); - } - if (state.dataRefrigCase->NumSimulationRefrigAirChillers > 0) { - CoilNum = Util::FindItemInList(Alphas(AlphaNum), WarehouseCoil); - } - int NumNameMatches = 0; - if (CaseAndWalkInListNum != 0) { - ++NumNameMatches; - } - if (CaseNum != 0) { - ++NumNameMatches; - } - if (WalkInNum != 0) { - ++NumNameMatches; - } - if (CoilNum != 0) { - ++NumNameMatches; - } - - if (NumNameMatches != 1) { // name must uniquely point to a list or a single case or walkin - ErrorsFound = true; - if (NumNameMatches == 0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\" : has an invalid {}: {}", - RoutineName, - CurrentModuleObject, - RefrigRack(RackNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } else if (NumNameMatches > 1) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\" : has a non-unique name that could be either a {}: {}", - RoutineName, - CurrentModuleObject, - RefrigRack(RackNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } // num matches = 0 or > 1 - } else if (CaseAndWalkInListNum != 0) { // Name points to a CaseAndWalkInList - NumCoils = CaseAndWalkInList(CaseAndWalkInListNum).NumCoils; - NumCases = CaseAndWalkInList(CaseAndWalkInListNum).NumCases; - NumWalkIns = CaseAndWalkInList(CaseAndWalkInListNum).NumWalkIns; - RefrigRack(RackNum).NumCoils = NumCoils; - RefrigRack(RackNum).NumCases = NumCases; - RefrigRack(RackNum).NumWalkIns = NumWalkIns; - if (!allocated(RefrigRack(RackNum).CoilNum)) { - RefrigRack(RackNum).CoilNum.allocate(NumCoils); - } - RefrigRack(RackNum).CoilNum({1, NumCoils}) = CaseAndWalkInList(CaseAndWalkInListNum).CoilItemNum({1, NumCoils}); - if (!allocated(RefrigRack(RackNum).CaseNum)) { - RefrigRack(RackNum).CaseNum.allocate(NumCases); - } - RefrigRack(RackNum).CaseNum({1, NumCases}) = CaseAndWalkInList(CaseAndWalkInListNum).CaseItemNum({1, NumCases}); - if (!allocated(RefrigRack(RackNum).WalkInNum)) { - RefrigRack(RackNum).WalkInNum.allocate(NumWalkIns); - } - RefrigRack(RackNum).WalkInNum({1, NumWalkIns}) = CaseAndWalkInList(CaseAndWalkInListNum).WalkInItemNum({1, NumWalkIns}); - } else if (CoilNum != 0) { // Name points to a coil - NumCoils = 1; - RefrigRack(RackNum).NumCoils = 1; - if (!allocated(RefrigRack(RackNum).CoilNum)) { - RefrigRack(RackNum).CoilNum.allocate(NumCoils); - } - RefrigRack(RackNum).CoilNum(NumCoils) = CoilNum; - } else if (CaseNum != 0) { // Name points to a case - NumCases = 1; - RefrigRack(RackNum).NumCases = 1; - if (!allocated(RefrigRack(RackNum).CaseNum)) { - RefrigRack(RackNum).CaseNum.allocate(NumCases); - } - RefrigRack(RackNum).CaseNum(NumCases) = CaseNum; - } else if (WalkInNum != 0) { // Name points to a walkin - NumWalkIns = 1; - RefrigRack(RackNum).NumWalkIns = 1; - if (!allocated(RefrigRack(RackNum).WalkInNum)) { - RefrigRack(RackNum).WalkInNum.allocate(NumWalkIns); - } - RefrigRack(RackNum).WalkInNum(NumWalkIns) = WalkInNum; - } // NumNameMatches /= 1 + resolveLoadsWithCoils(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + AlphaNum, + RefrigRack(RackNum).Name, + NumCases, + NumWalkIns, + NumCoils, + RefrigRack(RackNum).CaseNum, + RefrigRack(RackNum).WalkInNum, + RefrigRack(RackNum).CoilNum); + RefrigRack(RackNum).NumCases = NumCases; + RefrigRack(RackNum).NumWalkIns = NumWalkIns; + RefrigRack(RackNum).NumCoils = NumCoils; } // blank input for loads on rack if (NumCases > 0) { @@ -3190,6 +3427,14 @@ void GetRefrigerationInput(EnergyPlusData &state) state.dataRefrigCase->CheckEquipNameRackWaterCondenser.dimension(state.dataRefrigCase->NumRefrigeratedRacks, true); } //(NumRefrigeratedRacks > 0) + // Helper lambda: read one suction-piping UA + zone field pair. + // alphaFieldNum is the alpha field index for the zone name. + // numericFieldNum is the numeric field index for the UA value. + // objName is the parent object's name (for error messages). + // sumUASuctionPiping, suctionPipeActualZoneNum, suctionPipeZoneNodeNum are the output members. + // tempLevelLabel is an optional qualifier ("medium temperature", "low temperature", or "" for + // single-level systems) used in error/warning messages. + if (state.dataRefrigCase->NumRefrigSystems > 0 || state.dataRefrigCase->NumTransRefrigSystems > 0) { if (state.dataRefrigCase->NumRefrigSystems > 0 && state.dataRefrigCase->NumRefrigCondensers == 0) { @@ -3215,21 +3460,17 @@ void GetRefrigerationInput(EnergyPlusData &state) //************ START CONDENSER INPUT ************** + // Helper lambda: read the optional air-inlet node field (alphaNum) for an air-cooled + // condenser or gas cooler. If blank, sets inletAirNodeNum=0. Otherwise, first tries + // the name as a zone name; on match sets inletAirNodeNum via GetSystemNodeNumberForZone, + // sets rejectHeatToZone=true, and marks RefrigPresentInZone. On no zone match, calls + // GetOnlySingleNode with the supplied ConnectionObjectType and verifies it is an + // OutsideAir node; reports a severe error + continue error if not found. + // The eoh argument is used only for the "not found" error message on the outside-air path. if (state.dataRefrigCase->NumSimulationCondAir > 0) { CurrentModuleObject = "Refrigeration:Condenser:AirCooled"; for (int CondNum = 1; CondNum <= state.dataRefrigCase->NumSimulationCondAir; ++CondNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CondNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(CondNum); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; @@ -3250,10 +3491,7 @@ void GetRefrigerationInput(EnergyPlusData &state) } // set start of count for number of systems attached to this condenser - Condenser(CondNum).NumSysAttach = 0; - if (!allocated(Condenser(CondNum).SysNum)) { - Condenser(CondNum).SysNum.allocate(state.dataRefrigCase->NumRefrigSystems); - } + initSysAttach(Condenser(CondNum), state.dataRefrigCase->NumRefrigSystems); // set CondenserType and rated temperature difference (51.7 - 35)C per ARI 460 Condenser(CondNum).CondenserType = DataHeatBalance::RefrigCondenserType::Air; @@ -3265,25 +3503,15 @@ void GetRefrigerationInput(EnergyPlusData &state) } // elevation capacity correction on air-cooled condensers, Carrier correlation more conservative than Trane Condenser(CondNum).RatedCapacity *= (1.0 - 7.17e-5 * state.dataEnvrn->Elevation); - if (Condenser(CondNum).RatedCapacity > 0.0) { - Curve::GetCurveMinMaxValues(state, Condenser(CondNum).CapCurvePtr, DelTempMin, DelTempMax); - Real64 Capmin = Curve::CurveValue(state, Condenser(CondNum).CapCurvePtr, DelTempMin) * - (1.0 - 7.17e-5 * state.dataEnvrn->Elevation); // Mar 2011 bug fix - Real64 Capmax = Curve::CurveValue(state, Condenser(CondNum).CapCurvePtr, DelTempMax) * - (1.0 - 7.17e-5 * state.dataEnvrn->Elevation); // Mar 2011 bug - Condenser(CondNum).TempSlope = - (DelTempMax - DelTempMin) / ((Capmax - Capmin)); // * ( 1.0 - 7.17e-5 * Elevation ) ) //Mar 2011 bug fix - Condenser(CondNum).MinCondLoad = Capmax - DelTempMax / Condenser(CondNum).TempSlope; - } else { - ShowSevereError( - state, - EnergyPlus::format("{}{}=\"{}\" Condenser capacity curve per ARI 460 must be input and must be greater than 0 Watts at " - "16.7C temperature difference.", + computeCapCurveSlopeAndMin(state, + ErrorsFound, RoutineName, CurrentModuleObject, - Condenser(CondNum).Name)); - ErrorsFound = true; - } + Condenser(CondNum).CapCurvePtr, + Condenser(CondNum).Name, + Condenser(CondNum).RatedCapacity, + Condenser(CondNum).TempSlope, + Condenser(CondNum).MinCondLoad); Condenser(CondNum).RatedSubcool = 0.0; // default value if (!lNumericBlanks(1)) { @@ -3319,60 +3547,25 @@ void GetRefrigerationInput(EnergyPlusData &state) // Check condenser air inlet node connection // Jan 2011 - added ability to reject heat to a zone from air-cooled condenser - Condenser(CondNum).CondenserRejectHeatToZone = false; - if (lAlphaBlanks(4)) { - Condenser(CondNum).InletAirNodeNum = 0; - } else { // see if it's an outside air node name or an indoor zone name, - // have to check inside first because outside check automatically generates an error message - Condenser(CondNum).InletAirZoneNum = Util::FindItemInList(Alphas(4), state.dataHeatBal->Zone); - // need to clearly id node number for air inlet conditions and zone number for casecredit assignment - if (Condenser(CondNum).InletAirZoneNum != 0) { - // set condenser flag (later used to set system flag) and zone flag - Condenser(CondNum).InletAirNodeNum = DataZoneEquipment::GetSystemNodeNumberForZone(state, Condenser(CondNum).InletAirZoneNum); - Condenser(CondNum).CondenserRejectHeatToZone = true; - state.dataRefrigCase->RefrigPresentInZone(Condenser(CondNum).InletAirZoneNum) = true; - } else { // not in a conditioned zone, so see if it's outside - Condenser(CondNum).InletAirNodeNum = Node::GetOnlySingleNode(state, - Alphas(4), - ErrorsFound, - Node::ConnectionObjectType::RefrigerationCondenserAirCooled, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::OutsideAirReference, - Node::CompFluidStream::Primary, - Node::ObjectIsParent); - if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Condenser(CondNum).InletAirNodeNum)) { - // not outside and not a zone - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", {} not found: {}", - RoutineName, - CurrentModuleObject, - Condenser(CondNum).Name, - cAlphaFieldNames(4), - Alphas(4))); - ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node or as a Zone."); - ErrorsFound = true; - } // checkoutairnodenumber - } // InletAirZoneNum \=0 - } // Condenser air inlet node connection + readAirInletNodeField(state, + ErrorsFound, + eoh, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + 4, + Node::ConnectionObjectType::RefrigerationCondenserAirCooled, + Condenser(CondNum).InletAirNodeNum, + Condenser(CondNum).InletAirZoneNum, + Condenser(CondNum).CondenserRejectHeatToZone); Condenser(CondNum).EndUseSubcategory = ""; if (!lAlphaBlanks(5)) { Condenser(CondNum).EndUseSubcategory = Alphas(5); } - Condenser(CondNum).RefOpCharge = 0.0; - Condenser(CondNum).RefReceiverInventory = 0.0; - Condenser(CondNum).RefPipingInventory = 0.0; - if (!lNumericBlanks(4)) { - Condenser(CondNum).RefOpCharge = Numbers(4); - } - if (!lNumericBlanks(5)) { - Condenser(CondNum).RefReceiverInventory = Numbers(5); - } - if (!lNumericBlanks(6)) { - Condenser(CondNum).RefPipingInventory = Numbers(6); - } + readRefrigInventory( + Condenser(CondNum).RefOpCharge, Condenser(CondNum).RefReceiverInventory, Condenser(CondNum).RefPipingInventory, 4, 5, 6); } // Read input for REFRIGERATION:Condenser:AirCooled } // NumSimulationCondAir > 0 @@ -3381,18 +3574,7 @@ void GetRefrigerationInput(EnergyPlusData &state) CurrentModuleObject = "Refrigeration:Condenser:EvaporativeCooled"; for (int CondIndex = 1; CondIndex <= state.dataRefrigCase->NumSimulationCondEvap; ++CondIndex) { int CondNum = CondIndex + state.dataRefrigCase->NumSimulationCondAir; - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CondIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(CondIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; @@ -3402,10 +3584,7 @@ void GetRefrigerationInput(EnergyPlusData &state) state.dataHeatBal->HeatReclaimRefrigCondenser(CondNum).Name = Alphas(1); // set start of count for number of systems attached to this condenser - Condenser(CondNum).NumSysAttach = 0; - if (!allocated(Condenser(CondNum).SysNum)) { - Condenser(CondNum).SysNum.allocate(state.dataRefrigCase->NumRefrigSystems); - } + initSysAttach(Condenser(CondNum), state.dataRefrigCase->NumRefrigSystems); // set CondenserType and rated Heat Rejection per ARI 490 rating Condenser(CondNum).CondenserType = DataHeatBalance::RefrigCondenserType::Evap; @@ -3466,78 +3645,33 @@ void GetRefrigerationInput(EnergyPlusData &state) Condenser(CondNum).EvapCoeff4 = -0.322; Condenser(CondNum).MinCapFacEvap = 0.5; Condenser(CondNum).MaxCapFacEvap = 5.0; - NumNum = 5; // added warnings if below not blank but unused due to limits - if (!lNumericBlanks(NumNum)) { - if (Numbers(NumNum) >= 0.0) { - Condenser(CondNum).EvapCoeff1 = Numbers(NumNum); - } else { - ShowWarningError(state, - EnergyPlus::format("{}=\"{}\", {} is less than 0 and was not used. Default was used.", - CurrentModuleObject, - Condenser(CondNum).Name, - cNumericFieldNames(NumNum))); - } - } - NumNum = 6; // EvapCoeff2 can't be equal to 0 because used in a denominator - if (!lNumericBlanks(NumNum)) { - if (Numbers(NumNum) > 0.0) { - Condenser(CondNum).EvapCoeff2 = Numbers(NumNum); - } else { - ShowWarningError(state, - EnergyPlus::format("{}=\"{}\", {} is less than or equal to 0 and was not used. Default was used.", - CurrentModuleObject, - Condenser(CondNum).Name, - cNumericFieldNames(NumNum))); - } - } - NumNum = 7; - if (!lNumericBlanks(NumNum)) { - if (Numbers(NumNum) >= 0.0) { - Condenser(CondNum).EvapCoeff3 = Numbers(NumNum); - } else { - ShowWarningError(state, - EnergyPlus::format("{}=\"{}\", {} is less than 0 and was not used. Default was used.", - CurrentModuleObject, - Condenser(CondNum).Name, - cNumericFieldNames(NumNum))); - } - } - NumNum = 8; - if (!lNumericBlanks(NumNum)) { - if (Numbers(NumNum) >= -20.0) { - Condenser(CondNum).EvapCoeff4 = Numbers(NumNum); - } else { - ShowWarningError(state, - EnergyPlus::format("{}=\"{}\", {} is less than -20 and was not used. Default was used.", - CurrentModuleObject, - Condenser(CondNum).Name, - cNumericFieldNames(NumNum))); - } - } - NumNum = 9; - if (!lNumericBlanks(NumNum)) { - if (Numbers(NumNum) >= 0.0) { - Condenser(CondNum).MinCapFacEvap = Numbers(NumNum); - } else { - ShowWarningError(state, - EnergyPlus::format("{}=\"{}\", {} is less than 0 and was not used. Default was used.", - CurrentModuleObject, - Condenser(CondNum).Name, - cNumericFieldNames(NumNum))); + + // Helper: if field n is not blank and value passes the bound check, assign to dest; + // otherwise emit a warning and leave dest at its default. boundDesc is the text + // used in the "is and was not used" warning message. + auto tryReadEvapCoeff = [&](int n, Real64 lowerBound, bool strict, std::string_view boundDesc, Real64 &dest) { + if (lNumericBlanks(n)) { + return; } - } - NumNum = 10; - if (!lNumericBlanks(NumNum)) { - if (Numbers(NumNum) >= 0.0) { - Condenser(CondNum).MaxCapFacEvap = Numbers(NumNum); + bool ok = strict ? (Numbers(n) > lowerBound) : (Numbers(n) >= lowerBound); + if (ok) { + dest = Numbers(n); } else { ShowWarningError(state, - EnergyPlus::format("{}=\"{}\", {} is less than 0 and was not used. Default was used.", + EnergyPlus::format("{}=\"{}\", {} is {} and was not used. Default was used.", CurrentModuleObject, Condenser(CondNum).Name, - cNumericFieldNames(NumNum))); + cNumericFieldNames(n), + boundDesc)); } - } + }; + + tryReadEvapCoeff(5, 0.0, false, "less than 0", Condenser(CondNum).EvapCoeff1); // EvapCoeff2 can't be 0 (denominator) + tryReadEvapCoeff(6, 0.0, true, "less than or equal to 0", Condenser(CondNum).EvapCoeff2); + tryReadEvapCoeff(7, 0.0, false, "less than 0", Condenser(CondNum).EvapCoeff3); + tryReadEvapCoeff(8, -20.0, false, "less than -20", Condenser(CondNum).EvapCoeff4); + tryReadEvapCoeff(9, 0.0, false, "less than 0", Condenser(CondNum).MinCapFacEvap); + tryReadEvapCoeff(10, 0.0, false, "less than 0", Condenser(CondNum).MaxCapFacEvap); // Check condenser air inlet node connection if (lAlphaBlanks(3)) { @@ -3631,21 +3765,8 @@ void GetRefrigerationInput(EnergyPlusData &state) Condenser(CondNum).EndUseSubcategory = Alphas(6); } - Condenser(CondNum).RefOpCharge = 0.0; - Condenser(CondNum).RefReceiverInventory = 0.0; - Condenser(CondNum).RefPipingInventory = 0.0; - NumNum = 15; - if (!lNumericBlanks(NumNum)) { - Condenser(CondNum).RefOpCharge = Numbers(NumNum); - } - NumNum = 16; - if (!lNumericBlanks(NumNum)) { - Condenser(CondNum).RefReceiverInventory = Numbers(NumNum); - } - NumNum = 17; - if (!lNumericBlanks(NumNum)) { - Condenser(CondNum).RefPipingInventory = Numbers(NumNum); - } + readRefrigInventory( + Condenser(CondNum).RefOpCharge, Condenser(CondNum).RefReceiverInventory, Condenser(CondNum).RefPipingInventory, 15, 16, 17); } // Read input for CONDENSER:REFRIGERATION:EVAPorativeCooled } // If NumSimulationCondEvap > 0 @@ -3653,18 +3774,7 @@ void GetRefrigerationInput(EnergyPlusData &state) CurrentModuleObject = "Refrigeration:Condenser:WaterCooled"; for (int CondIndex = 1; CondIndex <= state.dataRefrigCase->NumSimulationCondWater; ++CondIndex) { int CondNum = CondIndex + state.dataRefrigCase->NumSimulationCondAir + state.dataRefrigCase->NumSimulationCondEvap; - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CondIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(CondIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; @@ -3674,10 +3784,7 @@ void GetRefrigerationInput(EnergyPlusData &state) state.dataHeatBal->HeatReclaimRefrigCondenser(CondNum).Name = Alphas(1); // set start of count for number of systems attached to this condenser - Condenser(CondNum).NumSysAttach = 0; - if (!allocated(Condenser(CondNum).SysNum)) { - Condenser(CondNum).SysNum.allocate(state.dataRefrigCase->NumRefrigSystems); - } + initSysAttach(Condenser(CondNum), state.dataRefrigCase->NumRefrigSystems); // set CondenserType and rated Heat Rejection per ARI 450 rating Condenser(CondNum).CondenserType = DataHeatBalance::RefrigCondenserType::Water; @@ -3824,18 +3931,8 @@ void GetRefrigerationInput(EnergyPlusData &state) Condenser(CondNum).EndUseSubcategory = Alphas(6); } - Condenser(CondNum).RefOpCharge = 0.0; - Condenser(CondNum).RefReceiverInventory = 0.0; - Condenser(CondNum).RefPipingInventory = 0.0; - if (!lNumericBlanks(9)) { - Condenser(CondNum).RefOpCharge = Numbers(9); - } - if (!lNumericBlanks(10)) { - Condenser(CondNum).RefReceiverInventory = Numbers(10); - } - if (!lNumericBlanks(11)) { - Condenser(CondNum).RefPipingInventory = Numbers(11); - } + readRefrigInventory( + Condenser(CondNum).RefOpCharge, Condenser(CondNum).RefReceiverInventory, Condenser(CondNum).RefPipingInventory, 9, 10, 11); } // Read input for CONDENSER:REFRIGERATION:WaterCooled @@ -3848,18 +3945,7 @@ void GetRefrigerationInput(EnergyPlusData &state) for (int CondIndex = 1; CondIndex <= state.dataRefrigCase->NumSimulationCascadeCondensers; ++CondIndex) { int CondNum = CondIndex + state.dataRefrigCase->NumSimulationCondAir + state.dataRefrigCase->NumSimulationCondEvap + state.dataRefrigCase->NumSimulationCondWater; - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CondIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(CondIndex); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; @@ -3869,10 +3955,7 @@ void GetRefrigerationInput(EnergyPlusData &state) state.dataHeatBal->HeatReclaimRefrigCondenser(CondNum).Name = Alphas(1); // set start of count for number of systems attached to this condenser - Condenser(CondNum).NumSysAttach = 0; - if (!allocated(Condenser(CondNum).SysNum)) { - Condenser(CondNum).SysNum.allocate(state.dataRefrigCase->NumRefrigSystems); - } + initSysAttach(Condenser(CondNum), state.dataRefrigCase->NumRefrigSystems); // set CondenserType Condenser(CondNum).CondenserType = DataHeatBalance::RefrigCondenserType::Cascade; @@ -3927,18 +4010,8 @@ void GetRefrigerationInput(EnergyPlusData &state) Condenser(CondNum).CascadeRatedEvapTemp = Condenser(CondNum).RatedTCondense - Condenser(CondNum).RatedApproachT; // future - add refrigerant inventory on system side accepting reject heat (as was done for secondary) - Condenser(CondNum).RefOpCharge = 0.0; - Condenser(CondNum).RefReceiverInventory = 0.0; - Condenser(CondNum).RefPipingInventory = 0.0; - if (!lNumericBlanks(4)) { - Condenser(CondNum).RefOpCharge = Numbers(4); - } - if (!lNumericBlanks(5)) { - Condenser(CondNum).RefReceiverInventory = Numbers(5); - } - if (!lNumericBlanks(6)) { - Condenser(CondNum).RefPipingInventory = Numbers(6); - } + readRefrigInventory( + Condenser(CondNum).RefOpCharge, Condenser(CondNum).RefReceiverInventory, Condenser(CondNum).RefPipingInventory, 4, 5, 6); } // Read input for CONDENSER:REFRIGERATION:Cascade } // NumSimulationCascadeCondensers > 0 @@ -3950,18 +4023,7 @@ void GetRefrigerationInput(EnergyPlusData &state) if (state.dataRefrigCase->NumSimulationGasCooler > 0) { CurrentModuleObject = "Refrigeration:GasCooler:AirCooled"; for (int GCNum = 1; GCNum <= state.dataRefrigCase->NumSimulationGasCooler; ++GCNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - GCNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(GCNum); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; GasCooler(GCNum).Name = Alphas(1); @@ -3973,10 +4035,7 @@ void GetRefrigerationInput(EnergyPlusData &state) } // set start of count for number of systems attached to this gas cooler - GasCooler(GCNum).NumSysAttach = 0; - if (!allocated(GasCooler(GCNum).SysNum)) { - GasCooler(GCNum).SysNum.allocate(state.dataRefrigCase->NumTransRefrigSystems); - } + initSysAttach(GasCooler(GCNum), state.dataRefrigCase->NumTransRefrigSystems); GasCooler(GCNum).RatedApproachT = 3.0; // rated CO2 gas cooler approach temperature if (GasCooler(GCNum).CapCurvePtr > 0) { @@ -3984,22 +4043,15 @@ void GetRefrigerationInput(EnergyPlusData &state) } // elevation capacity correction on air-cooled condensers, Carrier correlation more conservative than Trane GasCooler(GCNum).RatedCapacity *= (1.0 - 7.17e-5 * state.dataEnvrn->Elevation); - if (GasCooler(GCNum).RatedCapacity > 0.0) { - Curve::GetCurveMinMaxValues(state, GasCooler(GCNum).CapCurvePtr, DelTempMin, DelTempMax); - Real64 Capmin = Curve::CurveValue(state, GasCooler(GCNum).CapCurvePtr, DelTempMin) * (1.0 - 7.17e-5 * state.dataEnvrn->Elevation); - Real64 Capmax = Curve::CurveValue(state, GasCooler(GCNum).CapCurvePtr, DelTempMax) * (1.0 - 7.17e-5 * state.dataEnvrn->Elevation); - GasCooler(GCNum).TempSlope = (DelTempMax - DelTempMin) / ((Capmax - Capmin)); - GasCooler(GCNum).MinCondLoad = Capmax - DelTempMax / GasCooler(GCNum).TempSlope; - } else { - ShowSevereError( - state, - EnergyPlus::format( - "{}{}=\"{}\" Gas Cooler capacity curve must be input and must be greater than 0 Watts at 3C temperature difference.", - RoutineName, - CurrentModuleObject, - GasCooler(GCNum).Name)); - ErrorsFound = true; - } + computeCapCurveSlopeAndMin(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + GasCooler(GCNum).CapCurvePtr, + GasCooler(GCNum).Name, + GasCooler(GCNum).RatedCapacity, + GasCooler(GCNum).TempSlope, + GasCooler(GCNum).MinCondLoad); // Get fan control type if (lAlphaBlanks(3)) { @@ -4113,54 +4165,25 @@ void GetRefrigerationInput(EnergyPlusData &state) } // Check GasCooler air inlet node connection - GasCooler(GCNum).GasCoolerRejectHeatToZone = false; - if (lAlphaBlanks(4)) { - GasCooler(GCNum).InletAirNodeNum = 0; - } else { // see if it's an outside air node name or an indoor zone name, - // have to check inside first because outside check automatically generates an error message - GasCooler(GCNum).InletAirZoneNum = Util::FindItemInList(Alphas(4), state.dataHeatBal->Zone); - // need to clearly id node number for air inlet conditions and zone number for casecredit assignment - if (GasCooler(GCNum).InletAirZoneNum != 0) { - // set condenser flag (later used to set system flag) and zone flag - GasCooler(GCNum).InletAirNodeNum = DataZoneEquipment::GetSystemNodeNumberForZone(state, GasCooler(GCNum).InletAirZoneNum); - GasCooler(GCNum).GasCoolerRejectHeatToZone = true; - state.dataRefrigCase->RefrigPresentInZone(GasCooler(GCNum).InletAirZoneNum) = true; - } else { // not in a conditioned zone, so see if it's outside - GasCooler(GCNum).InletAirNodeNum = Node::GetOnlySingleNode(state, - Alphas(4), - ErrorsFound, - Node::ConnectionObjectType::RefrigerationGasCoolerAirCooled, - Alphas(1), - Node::FluidType::Air, - Node::ConnectionType::OutsideAirReference, - Node::CompFluidStream::Primary, - Node::ObjectIsParent); - if (!OutAirNodeManager::CheckOutAirNodeNumber(state, GasCooler(GCNum).InletAirNodeNum)) { - // not outside and not a zone - ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(4), Alphas(4)); - ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node or as a Zone."); - ErrorsFound = true; - } // checkoutairnodenumber - } // InletAirZoneNum \=0 - } // Gas cooler air inlet node connection + readAirInletNodeField(state, + ErrorsFound, + eoh, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + 4, + Node::ConnectionObjectType::RefrigerationGasCoolerAirCooled, + GasCooler(GCNum).InletAirNodeNum, + GasCooler(GCNum).InletAirZoneNum, + GasCooler(GCNum).GasCoolerRejectHeatToZone); GasCooler(GCNum).EndUseSubcategory = ""; if (!lAlphaBlanks(5)) { GasCooler(GCNum).EndUseSubcategory = Alphas(5); } - GasCooler(GCNum).RefOpCharge = 0.0; - GasCooler(GCNum).RefReceiverInventory = 0.0; - GasCooler(GCNum).RefPipingInventory = 0.0; - if (!lNumericBlanks(7)) { - GasCooler(GCNum).RefOpCharge = Numbers(7); - } - if (!lNumericBlanks(8)) { - GasCooler(GCNum).RefReceiverInventory = Numbers(8); - } - if (!lNumericBlanks(9)) { - GasCooler(GCNum).RefPipingInventory = Numbers(9); - } + readRefrigInventory( + GasCooler(GCNum).RefOpCharge, GasCooler(GCNum).RefReceiverInventory, GasCooler(GCNum).RefPipingInventory, 7, 8, 9); } // Read input for REFRIGERATION:GasCooler:AirCooled } // NumSimulationGasCooler > 0 @@ -4171,18 +4194,7 @@ void GetRefrigerationInput(EnergyPlusData &state) if (state.dataRefrigCase->NumSimulationSecondarySystems > 0) { CurrentModuleObject = "Refrigeration:SecondarySystem"; for (int SecondaryNum = 1; SecondaryNum <= state.dataRefrigCase->NumSimulationSecondarySystems; ++SecondaryNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - SecondaryNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(SecondaryNum); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; @@ -4209,98 +4221,24 @@ void GetRefrigerationInput(EnergyPlusData &state) cAlphaFieldNames(AlphaNum))); ErrorsFound = true; } else { // (.NOT. lAlphaBlanks(AlphaNum)) - - // Entry for Alphas(AlphaNum) can be either a Case, WalkIn Coil, or CaseAndWalkInList name - int CaseAndWalkInListNum = 0; - int CaseNum = 0; - int WalkInNum = 0; - int CoilNum = 0; - if (state.dataRefrigCase->NumSimulationCaseAndWalkInLists > 0) { - CaseAndWalkInListNum = Util::FindItemInList(Alphas(AlphaNum), CaseAndWalkInList); - } - if (state.dataRefrigCase->NumSimulationCases > 0) { - CaseNum = Util::FindItemInList(Alphas(AlphaNum), RefrigCase); - } - if (state.dataRefrigCase->NumSimulationWalkIns > 0) { - WalkInNum = Util::FindItemInList(Alphas(AlphaNum), WalkIn); - } - if (state.dataRefrigCase->NumSimulationRefrigAirChillers > 0) { - CoilNum = Util::FindItemInList(Alphas(AlphaNum), WarehouseCoil); - } - int NumNameMatches = 0; - if (CaseAndWalkInListNum != 0) { - ++NumNameMatches; - } - if (CaseNum != 0) { - ++NumNameMatches; - } - if (WalkInNum != 0) { - ++NumNameMatches; - } - if (CoilNum != 0) { - ++NumNameMatches; - } - - if (NumNameMatches != 1) { // name must uniquely point to a list or a single case or walkin or coil - ErrorsFound = true; - if (NumNameMatches == 0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", has an invalid {}: {}", - RoutineName, - CurrentModuleObject, - Secondary(SecondaryNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } else if (NumNameMatches > 1) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", has a non-unique name that could be either a {}: {}", - RoutineName, - CurrentModuleObject, - Secondary(SecondaryNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } // num matches = 0 or > 1 - } else if (CaseAndWalkInListNum != 0) { // Name points to a CaseAndWalkInList - NumCoils = CaseAndWalkInList(CaseAndWalkInListNum).NumCoils; - NumCases = CaseAndWalkInList(CaseAndWalkInListNum).NumCases; - NumWalkIns = CaseAndWalkInList(CaseAndWalkInListNum).NumWalkIns; - Secondary(SecondaryNum).NumCases = NumCases; - Secondary(SecondaryNum).NumCoils = NumCoils; - Secondary(SecondaryNum).NumWalkIns = NumWalkIns; - if (!allocated(Secondary(SecondaryNum).CaseNum)) { - Secondary(SecondaryNum).CaseNum.allocate(NumCases); - } - Secondary(SecondaryNum).CaseNum({1, NumCases}) = CaseAndWalkInList(CaseAndWalkInListNum).CaseItemNum({1, NumCases}); - if (!allocated(Secondary(SecondaryNum).CoilNum)) { - Secondary(SecondaryNum).CoilNum.allocate(NumCoils); - } - Secondary(SecondaryNum).CoilNum({1, NumCoils}) = CaseAndWalkInList(CaseAndWalkInListNum).CoilItemNum({1, NumCoils}); - if (!allocated(Secondary(SecondaryNum).WalkInNum)) { - Secondary(SecondaryNum).WalkInNum.allocate(NumWalkIns); - } - Secondary(SecondaryNum).WalkInNum({1, NumWalkIns}) = CaseAndWalkInList(CaseAndWalkInListNum).WalkInItemNum({1, NumWalkIns}); - } else if (CaseNum != 0) { // Name points to a case - NumCases = 1; - Secondary(SecondaryNum).NumCases = 1; - if (!allocated(Secondary(SecondaryNum).CaseNum)) { - Secondary(SecondaryNum).CaseNum.allocate(NumCases); - } - Secondary(SecondaryNum).CaseNum(NumCases) = CaseNum; - } else if (CoilNum != 0) { // Name points to a coil - NumCoils = 1; - Secondary(SecondaryNum).NumCoils = 1; - if (!allocated(Secondary(SecondaryNum).CoilNum)) { - Secondary(SecondaryNum).CoilNum.allocate(NumCoils); - } - Secondary(SecondaryNum).CoilNum(NumCoils) = CoilNum; - } else if (WalkInNum != 0) { // Name points to a walkin - NumWalkIns = 1; - Secondary(SecondaryNum).NumWalkIns = 1; - if (!allocated(Secondary(SecondaryNum).WalkInNum)) { - Secondary(SecondaryNum).WalkInNum.allocate(NumWalkIns); - } - Secondary(SecondaryNum).WalkInNum(NumWalkIns) = WalkInNum; - } // NumNameMatches /= 1 + resolveLoadsWithCoils(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + AlphaNum, + Secondary(SecondaryNum).Name, + NumCases, + NumWalkIns, + NumCoils, + Secondary(SecondaryNum).CaseNum, + Secondary(SecondaryNum).WalkInNum, + Secondary(SecondaryNum).CoilNum); + Secondary(SecondaryNum).NumCases = NumCases; + Secondary(SecondaryNum).NumWalkIns = NumWalkIns; + Secondary(SecondaryNum).NumCoils = NumCoils; } // blank input for loads on secondary if (NumCases > 0) { @@ -4667,132 +4605,48 @@ void GetRefrigerationInput(EnergyPlusData &state) } // range of pump moter heat to fluid } // blank input for pumppowertoheat + // Read distribution piping or receiver UA and zone heat-gain inputs (optional). + // The two blocks have identical structure; only field indices, member references, + // and message text differ, so they are handled by a single lambda. // Distribution piping heat gain - optional - // Input UA and Zone containing the bulk of the secondary coolant distribution piping - // This Zone ID will be used to determine the temperature used for distribution piping heat gain. - // Zone Id is only required if Sum UA Distribution Piping >0.0 - // Get the Zone node number from the zone name entered by the user - Secondary(SecondaryNum).SumUADistPiping = 0.0; - AlphaNum = 7; - NumNum = 12; - if (!lNumericBlanks(NumNum) && !lAlphaBlanks(AlphaNum)) { - Secondary(SecondaryNum).SumUADistPiping = Numbers(NumNum); - Secondary(SecondaryNum).DistPipeZoneNum = Util::FindItemInList(Alphas(AlphaNum), state.dataHeatBal->Zone); - Secondary(SecondaryNum).DistPipeZoneNodeNum = - DataZoneEquipment::GetSystemNodeNumberForZone(state, Secondary(SecondaryNum).DistPipeZoneNum); - - if (Secondary(SecondaryNum).DistPipeZoneNum == 0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid {} not valid: {}", - RoutineName, - CurrentModuleObject, - Secondary(SecondaryNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else { - state.dataRefrigCase->RefrigPresentInZone(Secondary(SecondaryNum).DistPipeZoneNum) = true; - } - - if (Secondary(SecondaryNum).DistPipeZoneNodeNum == 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{}{}=\"{}\" System Node Number not found for {} = {} even though {} is greater than zero. Distribution " - "piping heat gain cannot be calculated unless a controlled Zone (appear in a ZoneHVAC:EquipmentConnections " - "object.) is defined to determine the environmental temperature surrounding the piping.", - RoutineName, - CurrentModuleObject, - Secondary(SecondaryNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum), - cNumericFieldNames(NumNum))); - ErrorsFound = true; - } - } else if (!lNumericBlanks(NumNum) && lAlphaBlanks(AlphaNum)) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\", {} not found even though {} is greater than zero. Distribution piping heat gain will not be " - "calculated unless a Zone is defined to determine the environmental temperature surrounding the piping.", - RoutineName, - CurrentModuleObject, - Secondary(SecondaryNum).Name, - cAlphaFieldNames(AlphaNum), - cNumericFieldNames(NumNum))); - } else if (lNumericBlanks(NumNum) && !lAlphaBlanks(AlphaNum)) { - ShowWarningError( - state, - EnergyPlus::format( - "{}{}=\"{}\", {} will not be used and distribution piping heat gain will not be calculated because {} was blank.", - RoutineName, - CurrentModuleObject, - Secondary(SecondaryNum).Name, - cAlphaFieldNames(AlphaNum), - cNumericFieldNames(NumNum))); - } // distribution piping + readSecondaryPipingOrReceiver(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Secondary(SecondaryNum).Name, + Numbers, + lNumericBlanks, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + cNumericFieldNames, + 7, + 12, + Secondary(SecondaryNum).SumUADistPiping, + Secondary(SecondaryNum).DistPipeZoneNum, + Secondary(SecondaryNum).DistPipeZoneNodeNum, + "Distribution piping", + "piping"); // Separator/receiver heat gain - optional - // Input UA and Zone containing the Separator/receiver - // This Zone ID will be used to determine the temperature used for Separator/receiver heat gain. - // Zone Id is only required if Sum UA Separator/receiver >0.0 - // Get the Zone node number from the zone name entered by the user - Secondary(SecondaryNum).SumUAReceiver = 0.0; - AlphaNum = 8; - NumNum = 13; - if (!lNumericBlanks(NumNum) && !lAlphaBlanks(AlphaNum)) { - Secondary(SecondaryNum).SumUAReceiver = Numbers(NumNum); - Secondary(SecondaryNum).ReceiverZoneNum = Util::FindItemInList(Alphas(AlphaNum), state.dataHeatBal->Zone); - Secondary(SecondaryNum).ReceiverZoneNodeNum = - DataZoneEquipment::GetSystemNodeNumberForZone(state, Secondary(SecondaryNum).ReceiverZoneNum); - - if (Secondary(SecondaryNum).ReceiverZoneNum == 0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", invalid {} not valid: {}", - RoutineName, - CurrentModuleObject, - Secondary(SecondaryNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else { - state.dataRefrigCase->RefrigPresentInZone(Secondary(SecondaryNum).ReceiverZoneNum) = true; - } - if (Secondary(SecondaryNum).ReceiverZoneNodeNum == 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{}{}=\"{}\" System Node Number not found for {} = {} even though {} is greater than zero. Receiver heat gain " - "cannot be calculated unless a controlled Zone (appear in a ZoneHVAC:EquipmentConnections object.) is defined " - "to determine the environmental temperature surrounding the Receiver.", - RoutineName, - CurrentModuleObject, - Secondary(SecondaryNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum), - cNumericFieldNames(NumNum))); - ErrorsFound = true; - } - } else if (!lNumericBlanks(NumNum) && lAlphaBlanks(AlphaNum)) { - ShowWarningError( - state, - EnergyPlus::format( - "{}{}=\"{}\", {} not found even though {} is greater than zero. Receiver heat gain will not be calculated unless " - "a Zone is defined to determine the environmental temperature surrounding the Receiver.", - RoutineName, - CurrentModuleObject, - Secondary(SecondaryNum).Name, - cAlphaFieldNames(AlphaNum), - cNumericFieldNames(NumNum))); - } else if (lNumericBlanks(NumNum) && !lAlphaBlanks(AlphaNum)) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\", {} will not be used and Receiver heat gain will not be calculated because {} was blank.", - RoutineName, - CurrentModuleObject, - Secondary(SecondaryNum).Name, - cAlphaFieldNames(AlphaNum), - cNumericFieldNames(NumNum))); - } // Receiver + readSecondaryPipingOrReceiver(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Secondary(SecondaryNum).Name, + Numbers, + lNumericBlanks, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + cNumericFieldNames, + 8, + 13, + Secondary(SecondaryNum).SumUAReceiver, + Secondary(SecondaryNum).ReceiverZoneNum, + Secondary(SecondaryNum).ReceiverZoneNodeNum, + "Receiver", + "Receiver"); NumNum = 14; Secondary(SecondaryNum).ChillerRefInventory = 0.0; @@ -4908,18 +4762,7 @@ void GetRefrigerationInput(EnergyPlusData &state) CurrentModuleObject = "Refrigeration:Compressor"; for (int CompNum = 1; CompNum <= state.dataRefrigCase->NumSimulationCompressors; ++CompNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - CompNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(CompNum); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; Compressor(CompNum).Name = Alphas(1); @@ -4937,42 +4780,36 @@ void GetRefrigerationInput(EnergyPlusData &state) } // Get superheat rating type (Either N1 or N2 Must be input) - if (((!lNumericBlanks(1)) && (!lNumericBlanks(2))) || (lNumericBlanks(1) && lNumericBlanks(2))) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\"One, and Only One of {} or {}", - RoutineName, - CurrentModuleObject, - Compressor(CompNum).Name, - cNumericFieldNames(1), - cNumericFieldNames(2))); - ShowContinueError(state, "Must Be Entered. Check input value choices."); - ErrorsFound = true; - } else if (!lNumericBlanks(1)) { - Compressor(CompNum).SuperheatRatingType = CompRatingType::Superheat; - Compressor(CompNum).RatedSuperheat = Numbers(1); - } else if (!lNumericBlanks(2)) { - Compressor(CompNum).SuperheatRatingType = CompRatingType::ReturnGasTemperature; - Compressor(CompNum).RatedSuperheat = Numbers(2); - } // Set SuperheatRatingType + readOneOfTwoRatingFields(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Compressor(CompNum).Name, + Numbers, + lNumericBlanks, + cNumericFieldNames, + 1, + 2, + CompRatingType::Superheat, + CompRatingType::ReturnGasTemperature, + Compressor(CompNum).SuperheatRatingType, + Compressor(CompNum).RatedSuperheat); // Get subcool rating type (Either N3 or N4 Must be input) - if (((!lNumericBlanks(3)) && (!lNumericBlanks(4))) || (lNumericBlanks(3) && lNumericBlanks(4))) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\" One, and Only One of {} or {}", - RoutineName, - CurrentModuleObject, - Compressor(CompNum).Name, - cNumericFieldNames(3), - cNumericFieldNames(4))); - ShowContinueError(state, "Must Be Entered. Check input value choices."); - ErrorsFound = true; - } else if (!lNumericBlanks(3)) { - Compressor(CompNum).SubcoolRatingType = CompRatingType::LiquidTemperature; - Compressor(CompNum).RatedSubcool = Numbers(3); - } else if (!lNumericBlanks(4)) { - Compressor(CompNum).SubcoolRatingType = CompRatingType::Subcooling; - Compressor(CompNum).RatedSubcool = Numbers(4); - } // Set SubcoolRatingType + readOneOfTwoRatingFields(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Compressor(CompNum).Name, + Numbers, + lNumericBlanks, + cNumericFieldNames, + 3, + 4, + CompRatingType::LiquidTemperature, + CompRatingType::Subcooling, + Compressor(CompNum).SubcoolRatingType, + Compressor(CompNum).RatedSubcool); Compressor(CompNum).EndUseSubcategory = "General"; if (!lAlphaBlanks(4)) { @@ -5025,18 +4862,7 @@ void GetRefrigerationInput(EnergyPlusData &state) CurrentModuleObject = "Refrigeration:Subcooler"; state.dataRefrigCase->NumSimulationMechSubcoolers = 0; for (int SubcoolerNum = 1; SubcoolerNum <= state.dataRefrigCase->NumSimulationSubcoolers; ++SubcoolerNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - SubcoolerNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(SubcoolerNum); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; Subcooler(SubcoolerNum).Name = Alphas(1); @@ -5127,18 +4953,7 @@ void GetRefrigerationInput(EnergyPlusData &state) if (state.dataRefrigCase->NumSimulationTransferLoadLists > 0) { CurrentModuleObject = "Refrigeration:TransferLoadList"; for (int ListNum = 1; ListNum <= state.dataRefrigCase->NumSimulationTransferLoadLists; ++ListNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - ListNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(ListNum); TransferLoadList(ListNum).Name = Alphas(1); @@ -5209,18 +5024,7 @@ void GetRefrigerationInput(EnergyPlusData &state) //**** Read Compressor Lists ********************************************************** CurrentModuleObject = "Refrigeration:CompressorList"; for (int ListNum = 1; ListNum <= NumCompressorLists; ++ListNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - ListNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(ListNum); CompressorLists(ListNum).NumCompressors = NumAlphas - 1; CompressorLists(ListNum).Name = Alphas(1); @@ -5252,18 +5056,7 @@ void GetRefrigerationInput(EnergyPlusData &state) CurrentModuleObject = "Refrigeration:System"; for (RefrigSysNum = 1; RefrigSysNum <= state.dataRefrigCase->NumRefrigSystems; ++RefrigSysNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - RefrigSysNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(RefrigSysNum); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; @@ -5300,106 +5093,24 @@ void GetRefrigerationInput(EnergyPlusData &state) // Check for case or walkin or CaseAndWalkInList names AlphaNum = 2; - if (!lAlphaBlanks(AlphaNum)) { - - // Entry for Alphas(AlphaNum) can be either a Case, WalkIn or CaseAndWalkInList name - int CaseAndWalkInListNum = 0; - int CaseNum = 0; - int WalkInNum = 0; - int CoilNum = 0; - if (state.dataRefrigCase->NumSimulationCaseAndWalkInLists > 0) { - CaseAndWalkInListNum = Util::FindItemInList(Alphas(AlphaNum), CaseAndWalkInList); - } - if (state.dataRefrigCase->NumSimulationCases > 0) { - CaseNum = Util::FindItemInList(Alphas(AlphaNum), RefrigCase); - } - if (state.dataRefrigCase->NumSimulationWalkIns > 0) { - WalkInNum = Util::FindItemInList(Alphas(AlphaNum), WalkIn); - } - if (state.dataRefrigCase->NumSimulationRefrigAirChillers > 0) { - CoilNum = Util::FindItemInList(Alphas(AlphaNum), WarehouseCoil); - } - int NumNameMatches = 0; - if (CaseAndWalkInListNum != 0) { - ++NumNameMatches; - } - if (CaseNum != 0) { - ++NumNameMatches; - } - if (WalkInNum != 0) { - ++NumNameMatches; - } - if (CoilNum != 0) { - ++NumNameMatches; - } - - if (NumNameMatches != 1) { // name must uniquely point to a list or a single case or walkin or coil - ErrorsFound = true; - if (NumNameMatches == 0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", has an invalid {}: {}", - RoutineName, - CurrentModuleObject, - System(RefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } else if (NumNameMatches > 1) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", has a non-unique name that could be either a {}: {}", - RoutineName, - CurrentModuleObject, - System(RefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } // num matches = 0 or > 1 - } else if (CaseAndWalkInListNum != 0) { // Name points to a CaseAndWalkInList - NumCases = CaseAndWalkInList(CaseAndWalkInListNum).NumCases; - NumWalkIns = CaseAndWalkInList(CaseAndWalkInListNum).NumWalkIns; - NumCoils = CaseAndWalkInList(CaseAndWalkInListNum).NumCoils; - System(RefrigSysNum).NumCases = NumCases; - System(RefrigSysNum).NumWalkIns = NumWalkIns; - System(RefrigSysNum).NumCoils = NumCoils; - if (NumCases > 0) { - if (!allocated(System(RefrigSysNum).CaseNum)) { - System(RefrigSysNum).CaseNum.allocate(NumCases); - } - System(RefrigSysNum).CaseNum({1, NumCases}) = CaseAndWalkInList(CaseAndWalkInListNum).CaseItemNum({1, NumCases}); - } - if (NumCoils > 0) { - if (!allocated(System(RefrigSysNum).CoilNum)) { - System(RefrigSysNum).CoilNum.allocate(NumCoils); - } - System(RefrigSysNum).CoilNum({1, NumCoils}) = CaseAndWalkInList(CaseAndWalkInListNum).CoilItemNum({1, NumCoils}); - } - if (NumWalkIns > 0) { - if (!allocated(System(RefrigSysNum).WalkInNum)) { - System(RefrigSysNum).WalkInNum.allocate(NumWalkIns); - } - System(RefrigSysNum).WalkInNum({1, NumWalkIns}) = CaseAndWalkInList(CaseAndWalkInListNum).WalkInItemNum({1, NumWalkIns}); - } - } else if (CaseNum != 0) { // Name points to a case - NumCases = 1; - System(RefrigSysNum).NumCases = 1; - if (!allocated(System(RefrigSysNum).CaseNum)) { - System(RefrigSysNum).CaseNum.allocate(NumCases); - } - System(RefrigSysNum).CaseNum(NumCases) = CaseNum; - } else if (CoilNum != 0) { // Name points to a coil - NumCoils = 1; - System(RefrigSysNum).NumCoils = 1; - if (!allocated(System(RefrigSysNum).CoilNum)) { - System(RefrigSysNum).CoilNum.allocate(NumCoils); - } - System(RefrigSysNum).CoilNum(NumCoils) = CoilNum; - } else if (WalkInNum != 0) { // Name points to a walkin - NumWalkIns = 1; - System(RefrigSysNum).NumWalkIns = 1; - if (!allocated(System(RefrigSysNum).WalkInNum)) { - System(RefrigSysNum).WalkInNum.allocate(NumWalkIns); - } - System(RefrigSysNum).WalkInNum(NumWalkIns) = WalkInNum; - } // NumNameMatches /= 1 - } // blank input for cases, walkins, or caseandwalkinlist + resolveLoadsWithCoils(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + AlphaNum, + System(RefrigSysNum).Name, + NumCases, + NumWalkIns, + NumCoils, + System(RefrigSysNum).CaseNum, + System(RefrigSysNum).WalkInNum, + System(RefrigSysNum).CoilNum); + System(RefrigSysNum).NumCases = NumCases; + System(RefrigSysNum).NumWalkIns = NumWalkIns; + System(RefrigSysNum).NumCoils = NumCoils; if (NumCases > 0) { // Find lowest design evap T @@ -5444,19 +5155,9 @@ void GetRefrigerationInput(EnergyPlusData &state) ++WalkIn(WalkInID).NumSysAttach; NominalTotalWalkInCap += WalkIn(WalkInID).DesignRatedCap; System(RefrigSysNum).RefInventory += WalkIn(WalkInID).DesignRefrigInventory; - // Defrost capacity is treated differently by compressor racks and detailed systems, - // so this value may be adjusted (or warnings issued) after the walkin is assigned - // to either the rack or system. - // for walkins served by detailed system, need capacity for both fluid and electric types. - if (WalkIn(WalkInID).DefrostCapacity <= -98.0) { - // - 99 used as a flag for blank input error message for detailed systems - ShowSevereError(state, - EnergyPlus::format("{}Refrigeration:WalkIn=\"{}\", Defrost capacity must be greater than or equal to 0 W for " - "electric and hotfluid defrost types", - RoutineName, - WalkIn(WalkInID).Name)); - ErrorsFound = true; - } + // Defrost capacity is treated differently by compressor racks and detailed systems; + // for detailed systems, blank input is an error (flag value <= -98). + checkWalkInDefrostCap(WalkInID); // Find design evaporating temperature for system by getting min design evap for ALL loads if ((WalkInIndex == 1) && (System(RefrigSysNum).NumCases == 0) && (System(RefrigSysNum).NumCoils == 0)) { // note use walk in index, not walkinid here to get @@ -5501,24 +5202,14 @@ void GetRefrigerationInput(EnergyPlusData &state) int NumCascadeLoad = 0; if (NumNameMatches != 1) { // name must uniquely point to a list or a single transfer load - ErrorsFound = true; - if (NumNameMatches == 0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", has an invalid {}: {}", - RoutineName, - CurrentModuleObject, - System(RefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } else if (NumNameMatches > 1) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", has a non-unique name that could be either a {}: {}", - RoutineName, - CurrentModuleObject, - System(RefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } // num matches = 0 or > 1 + reportNameMatchError(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + System(RefrigSysNum).Name, + NumNameMatches, + cAlphaFieldNames(AlphaNum), + Alphas(AlphaNum)); } else if (TransferLoadListNum != 0) { // Name points to a transferLoad list NumSecondary = TransferLoadList(TransferLoadListNum).NumSecondarys; NumCascadeLoad = TransferLoadList(TransferLoadListNum).NumCascadeLoads; @@ -5726,50 +5417,19 @@ void GetRefrigerationInput(EnergyPlusData &state) ShowSevereError(state, EnergyPlus::format("{}{} {}\" : must be input.", RoutineName, CurrentModuleObject, cAlphaFieldNames(AlphaNum))); ErrorsFound = true; - } else { // Entry for Alphas(AlphaNum) can be either a compressor name or a compressorlist name - int ListNum; - if (NumCompressorLists > 0) { - ListNum = Util::FindItemInList(Alphas(AlphaNum), CompressorLists); - } else { - ListNum = 0; - } - int CompNum; - if (state.dataRefrigCase->NumSimulationCompressors > 0) { - CompNum = Util::FindItemInList(Alphas(AlphaNum), Compressor); - } else { - CompNum = 0; - } - if ((ListNum == 0) && (CompNum == 0)) { // name doesn't match either a compressor or a compressor list - ShowSevereError(state, - EnergyPlus::format("{}{} {}, has an invalid or undefined value=\"{}\".", - RoutineName, - CurrentModuleObject, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else if ((ListNum != 0) && (CompNum != 0)) { // have compressor list and compressor with same name - ShowSevereError(state, - EnergyPlus::format("{}{} {}, has a non-unique name used for both Compressor and CompressorList name: \"{}\".", - RoutineName, - CurrentModuleObject, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else if (ListNum != 0) { - NumCompressorsSys = CompressorLists(ListNum).NumCompressors; - System(RefrigSysNum).NumCompressors = NumCompressorsSys; - if (!allocated(System(RefrigSysNum).CompressorNum)) { - System(RefrigSysNum).CompressorNum.allocate(NumCompressorsSys); - } - System(RefrigSysNum).CompressorNum({1, NumCompressorsSys}) = CompressorLists(ListNum).CompItemNum({1, NumCompressorsSys}); - } else if (CompNum != 0) { - NumCompressorsSys = 1; - System(RefrigSysNum).NumCompressors = 1; - if (!allocated(System(RefrigSysNum).CompressorNum)) { - System(RefrigSysNum).CompressorNum.allocate(NumCompressorsSys); - } - System(RefrigSysNum).CompressorNum(NumCompressorsSys) = CompNum; - } + } else { + lookupAndAssignCompressors(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Alphas, + cAlphaFieldNames, + CompressorLists, + Compressor, + AlphaNum, + NumCompressorsSys, + System(RefrigSysNum).NumCompressors, + System(RefrigSysNum).CompressorNum); } if (!lNumericBlanks(1)) { @@ -5843,90 +5503,31 @@ void GetRefrigerationInput(EnergyPlusData &state) System(RefrigSysNum).SubcoolerNum.allocate(System(RefrigSysNum).NumSubcoolers); } int NumSubcooler = 1; + assignSubcoolerToSystem(AlphaNum, NumSubcooler); if (!lAlphaBlanks(AlphaNum)) { - System(RefrigSysNum).SubcoolerNum(NumSubcooler) = - state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Refrigeration:Subcooler", Alphas(AlphaNum)); - if (System(RefrigSysNum).SubcoolerNum(NumSubcooler) <= 0) { - ShowSevereError(state, - EnergyPlus::format(R"({}{}="{}", has an invalid {} defined as "{}".)", - RoutineName, - CurrentModuleObject, - System(RefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else { - Subcooler(System(RefrigSysNum).SubcoolerNum(NumSubcooler)).CoilFlag = System(RefrigSysNum).CoilFlag; - } ++NumSubcooler; } - if (!lAlphaBlanks(AlphaNum + 1)) { - System(RefrigSysNum).SubcoolerNum(NumSubcooler) = - state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Refrigeration:Subcooler", Alphas(AlphaNum + 1)); - if (System(RefrigSysNum).SubcoolerNum(NumSubcooler) <= 0) { - ShowSevereError(state, - EnergyPlus::format(R"({}{}="{}", has an invalid {} defined as "{}".)", - RoutineName, - CurrentModuleObject, - System(RefrigSysNum).Name, - cAlphaFieldNames(AlphaNum + 1), - Alphas(AlphaNum + 1))); - ErrorsFound = true; - } else { - Subcooler(System(RefrigSysNum).SubcoolerNum(NumSubcooler)).CoilFlag = System(RefrigSysNum).CoilFlag; - } - } + assignSubcoolerToSystem(AlphaNum + 1, NumSubcooler); } // Suction piping heat gain - optional - // Input UA and identify the Zone containing the bulk of the suction piping - // This Zone ID will be used to determine the temperature used for suction piping heat gain. - // The pipe heat gains are also counted as cooling credit for the zone. - // Zone Id is only required if Sum UA Suction Piping >0.0 - // Get the Zone and zone node numbers from the zone name entered by the user AlphaNum = 10; - System(RefrigSysNum).SumUASuctionPiping = 0.0; - if (!lNumericBlanks(2) && !lAlphaBlanks(AlphaNum)) { - System(RefrigSysNum).SumUASuctionPiping = Numbers(2); - System(RefrigSysNum).SuctionPipeActualZoneNum = Util::FindItemInList(Alphas(AlphaNum), state.dataHeatBal->Zone); - System(RefrigSysNum).SuctionPipeZoneNodeNum = - DataZoneEquipment::GetSystemNodeNumberForZone(state, System(RefrigSysNum).SuctionPipeActualZoneNum); - if (System(RefrigSysNum).SuctionPipeZoneNodeNum == 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{}{}=\"{}\", System Node Number not found for {} = {} even though {} is greater than zero. Suction piping heat gain " - "cannot be calculated unless a Zone is defined to determine the environmental temperature surrounding the piping.", - RoutineName, - CurrentModuleObject, - System(RefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum), - cNumericFieldNames(2))); - ErrorsFound = true; - } else { - state.dataRefrigCase->RefrigPresentInZone(System(RefrigSysNum).SuctionPipeActualZoneNum) = true; - } - } else if (!lNumericBlanks(2) && lAlphaBlanks(AlphaNum)) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\" {} not found even though {} is greater than zero. Suction piping heat gain will not be " - "calculated unless a Zone is defined to determine the environmental temperature surrounding the piping.", - RoutineName, - CurrentModuleObject, - System(RefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - cNumericFieldNames(2))); - } else if (lNumericBlanks(2) && !lAlphaBlanks(AlphaNum)) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\" {} will not be used and suction piping heat gain will not be calculated because {} was blank.", - RoutineName, - CurrentModuleObject, - System(RefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - cNumericFieldNames(2))); - } // suction piping heat gains + readSuctionPiping(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Numbers, + lNumericBlanks, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + cNumericFieldNames, + AlphaNum, + 2, + System(RefrigSysNum).Name, + System(RefrigSysNum).SumUASuctionPiping, + System(RefrigSysNum).SuctionPipeActualZoneNum, + System(RefrigSysNum).SuctionPipeZoneNodeNum); AlphaNum = 11; if (!lAlphaBlanks(AlphaNum)) { @@ -6010,44 +5611,19 @@ void GetRefrigerationInput(EnergyPlusData &state) System(RefrigSysNum).Name, cAlphaFieldNames(AlphaNum))); ErrorsFound = true; - } else { // Entry for Alphas(AlphaNum) can be either a compressor name or a compressorlist name - int ListNum = Util::FindItemInList(Alphas(AlphaNum), CompressorLists); - int CompNum = Util::FindItemInList(Alphas(AlphaNum), Compressor); - if ((ListNum == 0) && (CompNum == 0)) { // name doesn't match either a compressor or a compressor list - ShowSevereError(state, - EnergyPlus::format(R"({}{}="{}", {} has an invalid or undefined value="{}".)", - RoutineName, - CurrentModuleObject, - System(RefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else if ((ListNum != 0) && (CompNum != 0)) { // have compressor list and compressor with same name - ShowSevereError( - state, - EnergyPlus::format(R"({}{}="{}", {} has a non-unique name used for both Compressor and CompressorList name: "{}".)", + } else { + lookupAndAssignCompressors(state, + ErrorsFound, RoutineName, CurrentModuleObject, - System(RefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else if (ListNum != 0) { - NumHiStageCompressorsSys = CompressorLists(ListNum).NumCompressors; - System(RefrigSysNum).NumHiStageCompressors = NumHiStageCompressorsSys; - if (!allocated(System(RefrigSysNum).HiStageCompressorNum)) { - System(RefrigSysNum).HiStageCompressorNum.allocate(NumHiStageCompressorsSys); - } - System(RefrigSysNum).HiStageCompressorNum({1, NumHiStageCompressorsSys}) = - CompressorLists(ListNum).CompItemNum({1, NumHiStageCompressorsSys}); - } else if (CompNum != 0) { - NumHiStageCompressorsSys = 1; - System(RefrigSysNum).NumHiStageCompressors = 1; - if (!allocated(System(RefrigSysNum).HiStageCompressorNum)) { - System(RefrigSysNum).HiStageCompressorNum.allocate(NumHiStageCompressorsSys); - } - System(RefrigSysNum).HiStageCompressorNum(NumHiStageCompressorsSys) = CompNum; - } + Alphas, + cAlphaFieldNames, + CompressorLists, + Compressor, + AlphaNum, + NumHiStageCompressorsSys, + System(RefrigSysNum).NumHiStageCompressors, + System(RefrigSysNum).HiStageCompressorNum); } } @@ -6293,18 +5869,7 @@ void GetRefrigerationInput(EnergyPlusData &state) if (state.dataRefrigCase->NumTransRefrigSystems > 0) { CurrentModuleObject = "Refrigeration:TranscriticalSystem"; for (int TransRefrigSysNum = 1; TransRefrigSysNum <= state.dataRefrigCase->NumTransRefrigSystems; ++TransRefrigSysNum) { - state.dataInputProcessing->inputProcessor->getObjectItem(state, - CurrentModuleObject, - TransRefrigSysNum, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - IOStatus, - lNumericBlanks, - lAlphaBlanks, - cAlphaFieldNames, - cNumericFieldNames); + getItem(TransRefrigSysNum); ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; @@ -6356,270 +5921,73 @@ void GetRefrigerationInput(EnergyPlusData &state) // Check for Medium Temperature Case or Walk-In or CaseAndWalkInList names AlphaNum = 3; - - if (!lAlphaBlanks(AlphaNum)) { - - // Entry for Alphas(AlphaNum) can be either a Case, WalkIn or CaseAndWalkInList name - int CaseAndWalkInListNum = 0; - int CaseNum = 0; - int WalkInNum = 0; - if (state.dataRefrigCase->NumSimulationCaseAndWalkInLists > 0) { - CaseAndWalkInListNum = Util::FindItemInList(Alphas(AlphaNum), CaseAndWalkInList); - } - if (state.dataRefrigCase->NumSimulationCases > 0) { - CaseNum = Util::FindItemInList(Alphas(AlphaNum), RefrigCase); - } - if (state.dataRefrigCase->NumSimulationWalkIns > 0) { - WalkInNum = Util::FindItemInList(Alphas(AlphaNum), WalkIn); - } - int NumNameMatches = 0; - if (CaseAndWalkInListNum != 0) { - ++NumNameMatches; - } - if (CaseNum != 0) { - ++NumNameMatches; - } - if (WalkInNum != 0) { - ++NumNameMatches; - } - - if (NumNameMatches != 1) { // name must uniquely point to a list or a single case or walkin or coil - ErrorsFound = true; - if (NumNameMatches == 0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", has an invalid {}: {}", - RoutineName, - CurrentModuleObject, - TransSystem(TransRefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } else if (NumNameMatches > 1) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", has a non-unique name that could be either a {}: {}", - RoutineName, - CurrentModuleObject, - TransSystem(TransRefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } // num matches = 0 or > 1 - } else if (CaseAndWalkInListNum != 0) { // Name points to a CaseAndWalkInList - NumCasesMT = CaseAndWalkInList(CaseAndWalkInListNum).NumCases; - NumWalkInsMT = CaseAndWalkInList(CaseAndWalkInListNum).NumWalkIns; - TransSystem(TransRefrigSysNum).NumCasesMT = NumCasesMT; - TransSystem(TransRefrigSysNum).NumWalkInsMT = NumWalkInsMT; - if (NumCasesMT > 0) { - if (!allocated(TransSystem(TransRefrigSysNum).CaseNumMT)) { - TransSystem(TransRefrigSysNum).CaseNumMT.allocate(NumCasesMT); - } - TransSystem(TransRefrigSysNum).CaseNumMT({1, NumCasesMT}) = - CaseAndWalkInList(CaseAndWalkInListNum).CaseItemNum({1, NumCasesMT}); - } - if (NumWalkInsMT > 0) { - if (!allocated(TransSystem(TransRefrigSysNum).WalkInNumMT)) { - TransSystem(TransRefrigSysNum).WalkInNumMT.allocate(NumWalkInsMT); - } - TransSystem(TransRefrigSysNum).WalkInNumMT({1, NumWalkInsMT}) = - CaseAndWalkInList(CaseAndWalkInListNum).WalkInItemNum({1, NumWalkInsMT}); - } - } else if (CaseNum != 0) { // Name points to a case - NumCasesMT = 1; - TransSystem(TransRefrigSysNum).NumCasesMT = 1; - if (!allocated(TransSystem(TransRefrigSysNum).CaseNumMT)) { - TransSystem(TransRefrigSysNum).CaseNumMT.allocate(NumCasesMT); - } - TransSystem(TransRefrigSysNum).CaseNumMT(NumCases) = CaseNum; - } else if (WalkInNum != 0) { // Name points to a walkin - NumWalkInsMT = 1; - TransSystem(TransRefrigSysNum).NumWalkInsMT = 1; - if (!allocated(TransSystem(TransRefrigSysNum).WalkInNumMT)) { - TransSystem(TransRefrigSysNum).WalkInNumMT.allocate(NumWalkInsMT); - } - TransSystem(TransRefrigSysNum).WalkInNumMT(NumWalkIns) = WalkInNum; - } // NumNameMatches /= 1 - } // blank input for cases, walkins, or caseandwalkinlist + resolveTransSysLoads(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + AlphaNum, + TransSystem(TransRefrigSysNum).Name, + NumCasesMT, + NumWalkInsMT, + TransSystem(TransRefrigSysNum).CaseNumMT, + TransSystem(TransRefrigSysNum).WalkInNumMT); + TransSystem(TransRefrigSysNum).NumCasesMT = NumCasesMT; + TransSystem(TransRefrigSysNum).NumWalkInsMT = NumWalkInsMT; if (NumCasesMT > 0) { - // Find lowest design evap T - // Sum rated capacity of all MT cases on system - for (int caseIndex = 1; caseIndex <= NumCasesMT; ++caseIndex) { - // mark all cases on system as used by this system - checking for unused or non-unique cases - int CaseNum = TransSystem(TransRefrigSysNum).CaseNumMT(caseIndex); - ++RefrigCase(CaseNum).NumSysAttach; - NominalTotalCaseCapMT += RefrigCase(CaseNum).DesignRatedCap; - TransSystem(TransRefrigSysNum).RefInventory += RefrigCase(CaseNum).DesignRefrigInventory; - if (caseIndex == 1) { // look for lowest case design evap T for system - TransSystem(TransRefrigSysNum).TEvapDesignMT = RefrigCase(CaseNum).EvapTempDesign; - } else { - TransSystem(TransRefrigSysNum).TEvapDesignMT = - min(RefrigCase(CaseNum).EvapTempDesign, TransSystem(TransRefrigSysNum).TEvapDesignMT); - } - } // CaseIndex=1,NumCases - } // NumcasesMT > 0 + accumTransSysCases(TransSystem(TransRefrigSysNum).CaseNumMT, + NumCasesMT, + NominalTotalCaseCapMT, + TransSystem(TransRefrigSysNum).TEvapDesignMT, + TransSystem(TransRefrigSysNum).RefInventory); + } if (NumWalkInsMT > 0) { - for (int WalkInIndex = 1; WalkInIndex <= NumWalkInsMT; ++WalkInIndex) { - int WalkInID = TransSystem(TransRefrigSysNum).WalkInNumMT(WalkInIndex); - // mark all WalkIns on rack as used by this system (checking for unused or non-unique WalkIns) - ++WalkIn(WalkInID).NumSysAttach; - NominalTotalWalkInCapMT += WalkIn(WalkInID).DesignRatedCap; - TransSystem(TransRefrigSysNum).RefInventory += WalkIn(WalkInID).DesignRefrigInventory; - // Defrost capacity is treated differently by compressor racks and detailed systems, - // so this value may be adjusted (or warnings issued) after the walkin is assigned - // to either the rack or system. - // for walkins served by detailed system, need capacity for both fluid and electric types. - if (WalkIn(WalkInID).DefrostCapacity <= -98.0) { - // - 99 used as a flag for blank input error message for detailed systems - ShowSevereError(state, - EnergyPlus::format("{}Refrigeration:WalkIn=\"{}\", Defrost capacity must be greater than or equal to 0 W for " - "electric and hotfluid defrost types", - RoutineName, - WalkIn(WalkInID).Name)); - ErrorsFound = true; - } - // Find design evaporating temperature for system by getting min design evap for ALL loads - if ((WalkInIndex == 1) && (TransSystem(TransRefrigSysNum).NumCasesMT == 0)) { - // note use walk in index, not walkinid here to get - // first walkin on this suction group/system - TransSystem(TransRefrigSysNum).TEvapDesignMT = WalkIn(WalkInID).TEvapDesign; - } else { - TransSystem(TransRefrigSysNum).TEvapDesignMT = - min(WalkIn(WalkInID).TEvapDesign, TransSystem(TransRefrigSysNum).TEvapDesignMT); - } - } // WalkInIndex=1,NumWalkIns - } // NumWalkInsMT > 0 + accumTransSysWalkIns(TransSystem(TransRefrigSysNum).WalkInNumMT, + NumWalkInsMT, + NominalTotalWalkInCapMT, + TransSystem(TransRefrigSysNum).TEvapDesignMT, + TransSystem(TransRefrigSysNum).NumCasesMT, + TransSystem(TransRefrigSysNum).RefInventory); + } // Check for Low Temperature Case or Walk-In or CaseAndWalkInList names AlphaNum = 4; - if (!lAlphaBlanks(AlphaNum)) { - - // Entry for Alphas(AlphaNum) can be either a Case, WalkIn or CaseAndWalkInList name - int CaseAndWalkInListNum = 0; - int CaseNum = 0; - int WalkInNum = 0; - if (state.dataRefrigCase->NumSimulationCaseAndWalkInLists > 0) { - CaseAndWalkInListNum = Util::FindItemInList(Alphas(AlphaNum), CaseAndWalkInList); - } - if (state.dataRefrigCase->NumSimulationCases > 0) { - CaseNum = Util::FindItemInList(Alphas(AlphaNum), RefrigCase); - } - if (state.dataRefrigCase->NumSimulationWalkIns > 0) { - WalkInNum = Util::FindItemInList(Alphas(AlphaNum), WalkIn); - } - int NumNameMatches = 0; - if (CaseAndWalkInListNum != 0) { - ++NumNameMatches; - } - if (CaseNum != 0) { - ++NumNameMatches; - } - if (WalkInNum != 0) { - ++NumNameMatches; - } - - if (NumNameMatches != 1) { // name must uniquely point to a list or a single case or walkin or coil - ErrorsFound = true; - if (NumNameMatches == 0) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", has an invalid {}: {}", - RoutineName, - CurrentModuleObject, - TransSystem(TransRefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } else if (NumNameMatches > 1) { - ShowSevereError(state, - EnergyPlus::format("{}{}=\"{}\", has a non-unique name that could be either a {}: {}", - RoutineName, - CurrentModuleObject, - TransSystem(TransRefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - } // num matches = 0 or > 1 - } else if (CaseAndWalkInListNum != 0) { // Name points to a CaseAndWalkInList - NumCasesLT = CaseAndWalkInList(CaseAndWalkInListNum).NumCases; - NumWalkInsLT = CaseAndWalkInList(CaseAndWalkInListNum).NumWalkIns; - TransSystem(TransRefrigSysNum).NumCasesLT = NumCasesLT; - TransSystem(TransRefrigSysNum).NumWalkInsLT = NumWalkInsLT; - if (NumCasesLT > 0) { - if (!allocated(TransSystem(TransRefrigSysNum).CaseNumLT)) { - TransSystem(TransRefrigSysNum).CaseNumLT.allocate(NumCasesLT); - } - TransSystem(TransRefrigSysNum).CaseNumLT({1, NumCasesLT}) = - CaseAndWalkInList(CaseAndWalkInListNum).CaseItemNum({1, NumCasesLT}); - } - if (NumWalkInsLT > 0) { - if (!allocated(TransSystem(TransRefrigSysNum).WalkInNumLT)) { - TransSystem(TransRefrigSysNum).WalkInNumLT.allocate(NumWalkInsLT); - } - TransSystem(TransRefrigSysNum).WalkInNumLT({1, NumWalkInsLT}) = - CaseAndWalkInList(CaseAndWalkInListNum).WalkInItemNum({1, NumWalkInsLT}); - } - } else if (CaseNum != 0) { // Name points to a case - NumCasesLT = 1; - TransSystem(TransRefrigSysNum).NumCasesLT = 1; - if (!allocated(TransSystem(TransRefrigSysNum).CaseNumLT)) { - TransSystem(TransRefrigSysNum).CaseNumLT.allocate(NumCasesLT); - } - TransSystem(TransRefrigSysNum).CaseNumLT(NumCases) = CaseNum; - } else if (WalkInNum != 0) { // Name points to a walkin - NumWalkInsLT = 1; - TransSystem(TransRefrigSysNum).NumWalkInsLT = 1; - if (!allocated(TransSystem(TransRefrigSysNum).WalkInNumLT)) { - TransSystem(TransRefrigSysNum).WalkInNumLT.allocate(NumWalkInsLT); - } - TransSystem(TransRefrigSysNum).WalkInNumLT(NumWalkIns) = WalkInNum; - } // NumNameMatches /= 1 - } // blank input for cases, walkins, or caseandwalkinlist + resolveTransSysLoads(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + AlphaNum, + TransSystem(TransRefrigSysNum).Name, + NumCasesLT, + NumWalkInsLT, + TransSystem(TransRefrigSysNum).CaseNumLT, + TransSystem(TransRefrigSysNum).WalkInNumLT); + TransSystem(TransRefrigSysNum).NumCasesLT = NumCasesLT; + TransSystem(TransRefrigSysNum).NumWalkInsLT = NumWalkInsLT; if (NumCasesLT > 0) { - // Find lowest design evap T - // Sum rated capacity of all LT cases on system - for (int caseIndex = 1; caseIndex <= NumCasesLT; ++caseIndex) { - // mark all cases on system as used by this system - checking for unused or non-unique cases - int CaseNum = TransSystem(TransRefrigSysNum).CaseNumLT(caseIndex); - ++RefrigCase(CaseNum).NumSysAttach; - NominalTotalCaseCapLT += RefrigCase(CaseNum).DesignRatedCap; - TransSystem(TransRefrigSysNum).RefInventory += RefrigCase(CaseNum).DesignRefrigInventory; - if (caseIndex == 1) { // look for lowest case design evap T for system - TransSystem(TransRefrigSysNum).TEvapDesignLT = RefrigCase(CaseNum).EvapTempDesign; - } else { - TransSystem(TransRefrigSysNum).TEvapDesignLT = - min(RefrigCase(CaseNum).EvapTempDesign, TransSystem(TransRefrigSysNum).TEvapDesignLT); - } - } // CaseIndex=1,NumCases - } // NumcasesLT > 0 + accumTransSysCases(TransSystem(TransRefrigSysNum).CaseNumLT, + NumCasesLT, + NominalTotalCaseCapLT, + TransSystem(TransRefrigSysNum).TEvapDesignLT, + TransSystem(TransRefrigSysNum).RefInventory); + } if (NumWalkInsLT > 0) { - for (int WalkInIndex = 1; WalkInIndex <= NumWalkInsLT; ++WalkInIndex) { - int WalkInID = TransSystem(TransRefrigSysNum).WalkInNumLT(WalkInIndex); - // mark all WalkIns on rack as used by this system (checking for unused or non-unique WalkIns) - ++WalkIn(WalkInID).NumSysAttach; - NominalTotalWalkInCapLT += WalkIn(WalkInID).DesignRatedCap; - TransSystem(TransRefrigSysNum).RefInventory += WalkIn(WalkInID).DesignRefrigInventory; - // Defrost capacity is treated differently by compressor racks and detailed systems, - // so this value may be adjusted (or warnings issued) after the walkin is assigned - // to either the rack or system. - // for walkins served by detailed system, need capacity for both fluid and electric types. - if (WalkIn(WalkInID).DefrostCapacity <= -98.0) { - // - 99 used as a flag for blank input error message for detailed systems - ShowSevereError(state, - EnergyPlus::format("{}Refrigeration:WalkIn=\"{}\", Defrost capacity must be greater than or equal to 0 W for " - "electric and hotfluid defrost types", - RoutineName, - WalkIn(WalkInID).Name)); - ErrorsFound = true; - } - // Find design evaporating temperature for system by getting min design evap for ALL loads - if ((WalkInIndex == 1) && (TransSystem(TransRefrigSysNum).NumCasesLT == 0)) { - // note use walk in index, not walkinid here to get - // first walkin on this suction group/system - TransSystem(TransRefrigSysNum).TEvapDesignLT = WalkIn(WalkInID).TEvapDesign; - } else { - TransSystem(TransRefrigSysNum).TEvapDesignLT = - min(WalkIn(WalkInID).TEvapDesign, TransSystem(TransRefrigSysNum).TEvapDesignLT); - } - } // WalkInIndex=1,NumWalkIns - } // NumWalkInsMT > 0 + accumTransSysWalkIns(TransSystem(TransRefrigSysNum).WalkInNumLT, + NumWalkInsLT, + NominalTotalWalkInCapLT, + TransSystem(TransRefrigSysNum).TEvapDesignLT, + TransSystem(TransRefrigSysNum).NumCasesLT, + TransSystem(TransRefrigSysNum).RefInventory); + } NominalTotalCoolingCap = NominalTotalCaseCapMT + NominalTotalCaseCapLT + NominalTotalWalkInCapMT + NominalTotalWalkInCapLT; @@ -6665,44 +6033,22 @@ void GetRefrigerationInput(EnergyPlusData &state) EnergyPlus::format("{}{} {}\" : must be input.", RoutineName, CurrentModuleObject, cAlphaFieldNames(AlphaNum))); ErrorsFound = true; } else { // Entry for Alphas(AlphaNum) can be either a compressor name or a compressorlist name - int ListNum = Util::FindItemInList(Alphas(AlphaNum), CompressorLists); - int CompNum = Util::FindItemInList(Alphas(AlphaNum), Compressor); - if ((ListNum == 0) && (CompNum == 0)) { // name doesn't match either a compressor or a compressor list - ShowSevereError(state, - EnergyPlus::format(R"({}{}, "{}", has an invalid or undefined value="{}".)", - RoutineName, - CurrentModuleObject, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else if ((ListNum != 0) && (CompNum != 0)) { // have compressor list and compressor with same name - ShowSevereError(state, - EnergyPlus::format("{}{} {}, has a non-unique name used for both Compressor and CompressorList name: \"{}\".", - RoutineName, - CurrentModuleObject, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else if (ListNum != 0) { - NumCompressorsSys = CompressorLists(ListNum).NumCompressors; - TransSystem(TransRefrigSysNum).NumCompressorsHP = NumCompressorsSys; - if (!allocated(TransSystem(TransRefrigSysNum).CompressorNumHP)) { - TransSystem(TransRefrigSysNum).CompressorNumHP.allocate(NumCompressorsSys); - } - TransSystem(TransRefrigSysNum).CompressorNumHP({1, NumCompressorsSys}) = - CompressorLists(ListNum).CompItemNum({1, NumCompressorsSys}); - } else if (CompNum != 0) { - NumCompressorsSys = 1; - TransSystem(TransRefrigSysNum).NumCompressorsHP = 1; - if (!allocated(TransSystem(TransRefrigSysNum).CompressorNumHP)) { - TransSystem(TransRefrigSysNum).CompressorNumHP.allocate(NumCompressorsSys); - } - TransSystem(TransRefrigSysNum).CompressorNumHP(NumCompressorsSys) = CompNum; - } + lookupAndAssignCompressors(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Alphas, + cAlphaFieldNames, + CompressorLists, + Compressor, + AlphaNum, + NumCompressorsSys, + TransSystem(TransRefrigSysNum).NumCompressorsHP, + TransSystem(TransRefrigSysNum).CompressorNumHP); // Sum rated capacity of all HP compressors on system NominalTotalCompCapHP = 0.0; for (int CompIndex = 1; CompIndex <= NumCompressorsSys; ++CompIndex) { - CompNum = TransSystem(TransRefrigSysNum).CompressorNumHP(CompIndex); + int CompNum = TransSystem(TransRefrigSysNum).CompressorNumHP(CompIndex); if (Compressor(CompNum).TransFlag) { // Calculate nominal capacity of transcritical Compressor Real64 GCOutletH = TransSystem(TransRefrigSysNum) @@ -6752,44 +6098,22 @@ void GetRefrigerationInput(EnergyPlusData &state) cAlphaFieldNames(AlphaNum))); } else if ((!(lAlphaBlanks(AlphaNum))) && (TransSystem(TransRefrigSysNum).transSysType == TransSysType::TwoStage)) { // TwoStage system with low pressure compressors specified - int ListNum = Util::FindItemInList(Alphas(AlphaNum), CompressorLists); - int CompNum = Util::FindItemInList(Alphas(AlphaNum), Compressor); - if ((ListNum == 0) && (CompNum == 0)) { // name doesn't match either a compressor or a compressor list - ShowSevereError(state, - EnergyPlus::format(R"({}{}, "{}", has an invalid or undefined value="{}".)", - RoutineName, - CurrentModuleObject, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else if ((ListNum != 0) && (CompNum != 0)) { // have compressor list and compressor with same name - ShowSevereError(state, - EnergyPlus::format("{}{} {}, has a non-unique name used for both Compressor and CompressorList name: \"{}\".", - RoutineName, - CurrentModuleObject, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum))); - ErrorsFound = true; - } else if (ListNum != 0) { - NumCompressorsSys = CompressorLists(ListNum).NumCompressors; - TransSystem(TransRefrigSysNum).NumCompressorsLP = NumCompressorsSys; - if (!allocated(TransSystem(TransRefrigSysNum).CompressorNumLP)) { - TransSystem(TransRefrigSysNum).CompressorNumLP.allocate(NumCompressorsSys); - } - TransSystem(TransRefrigSysNum).CompressorNumLP({1, NumCompressorsSys}) = - CompressorLists(ListNum).CompItemNum({1, NumCompressorsSys}); - } else if (CompNum != 0) { - NumCompressorsSys = 1; - TransSystem(TransRefrigSysNum).NumCompressorsLP = 1; - if (!allocated(TransSystem(TransRefrigSysNum).CompressorNumLP)) { - TransSystem(TransRefrigSysNum).CompressorNumLP.allocate(NumCompressorsSys); - } - TransSystem(TransRefrigSysNum).CompressorNumLP(NumCompressorsSys) = CompNum; - } + lookupAndAssignCompressors(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Alphas, + cAlphaFieldNames, + CompressorLists, + Compressor, + AlphaNum, + NumCompressorsSys, + TransSystem(TransRefrigSysNum).NumCompressorsLP, + TransSystem(TransRefrigSysNum).CompressorNumLP); // Sum rated capacity of all LP compressors on system NominalTotalCompCapLP = 0.0; for (int CompIndex = 1; CompIndex <= NumCompressorsSys; ++CompIndex) { - CompNum = TransSystem(TransRefrigSysNum).CompressorNumLP(CompIndex); + int CompNum = TransSystem(TransRefrigSysNum).CompressorNumLP(CompIndex); if (TransSystem(TransRefrigSysNum).transSysType == TransSysType::TwoStage) { // Calculate capacity of LP compressors Compressor(CompNum).NomCap = Curve::CurveValue(state, Compressor(CompNum).CapacityCurvePtr, @@ -6887,97 +6211,44 @@ void GetRefrigerationInput(EnergyPlusData &state) // The pipe heat gains are also counted as cooling credit for the zone. // Zone Id is only required if Sum UA Suction Piping >0.0 // Get the Zone and zone node numbers from the zone name entered by the user + AlphaNum = 9; // Medium temperature suction piping - TransSystem(TransRefrigSysNum).SumUASuctionPipingMT = 0.0; - if (!lNumericBlanks(3) && !lAlphaBlanks(AlphaNum)) { - TransSystem(TransRefrigSysNum).SumUASuctionPipingMT = Numbers(3); - TransSystem(TransRefrigSysNum).SuctionPipeActualZoneNumMT = Util::FindItemInList(Alphas(AlphaNum), state.dataHeatBal->Zone); - TransSystem(TransRefrigSysNum).SuctionPipeZoneNodeNumMT = - DataZoneEquipment::GetSystemNodeNumberForZone(state, TransSystem(TransRefrigSysNum).SuctionPipeActualZoneNumMT); - if (TransSystem(TransRefrigSysNum).SuctionPipeZoneNodeNumMT == 0) { - ShowSevereError( - state, - EnergyPlus::format(R"({}{}="{}", System Node Number not found for {} = "{}" even though {} is greater than zero.)", - RoutineName, - CurrentModuleObject, - TransSystem(TransRefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum), - cNumericFieldNames(3))); - ShowContinueError(state, - " The medium temperature suction piping heat gain cannot be calculated unless a Zone is defined to " - "determine the environmental temperature surrounding the piping."); - ErrorsFound = true; - } else { - state.dataRefrigCase->RefrigPresentInZone(TransSystem(TransRefrigSysNum).SuctionPipeActualZoneNumMT) = true; - } - } else if (!lNumericBlanks(3) && lAlphaBlanks(AlphaNum)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\" {} not found even though {} is greater than zero.", - RoutineName, - CurrentModuleObject, - TransSystem(TransRefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - cNumericFieldNames(3))); - ShowContinueError(state, - " The medium temperature suction piping heat gain will not be calculated unless a Zone is defined to " - "determine the environmental temperature surrounding the piping."); - } else if (lNumericBlanks(3) && !lAlphaBlanks(AlphaNum)) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\" {} will not be used and suction piping heat gain will not be calculated because {} was blank.", - RoutineName, - CurrentModuleObject, - TransSystem(TransRefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - cNumericFieldNames(3))); - } // Medium temperature suction piping heat gains + readSuctionPiping(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Numbers, + lNumericBlanks, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + cNumericFieldNames, + AlphaNum, + 3, + TransSystem(TransRefrigSysNum).Name, + TransSystem(TransRefrigSysNum).SumUASuctionPipingMT, + TransSystem(TransRefrigSysNum).SuctionPipeActualZoneNumMT, + TransSystem(TransRefrigSysNum).SuctionPipeZoneNodeNumMT, + "medium temperature"); AlphaNum = 10; // Low temperature suction piping - TransSystem(TransRefrigSysNum).SumUASuctionPipingLT = 0.0; - if (!lNumericBlanks(4) && !lAlphaBlanks(AlphaNum)) { - TransSystem(TransRefrigSysNum).SumUASuctionPipingLT = Numbers(4); - TransSystem(TransRefrigSysNum).SuctionPipeActualZoneNumLT = Util::FindItemInList(Alphas(AlphaNum), state.dataHeatBal->Zone); - TransSystem(TransRefrigSysNum).SuctionPipeZoneNodeNumLT = - DataZoneEquipment::GetSystemNodeNumberForZone(state, TransSystem(TransRefrigSysNum).SuctionPipeActualZoneNumLT); - if (TransSystem(TransRefrigSysNum).SuctionPipeZoneNodeNumLT == 0) { - ShowSevereError( - state, - EnergyPlus::format(R"({}{}="{}", System Node Number not found for {} = "{}" even though {} is greater than zero.)", - RoutineName, - CurrentModuleObject, - TransSystem(TransRefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - Alphas(AlphaNum), - cNumericFieldNames(4))); - ShowContinueError(state, - " The low temperature suction piping heat gain cannot be calculated unless a Zone is defined to " - "determine the environmental temperature surrounding the piping."); - ErrorsFound = true; - } else { - state.dataRefrigCase->RefrigPresentInZone(TransSystem(TransRefrigSysNum).SuctionPipeActualZoneNumLT) = true; - } - } else if (!lNumericBlanks(4) && lAlphaBlanks(AlphaNum)) { - ShowWarningError(state, - EnergyPlus::format("{}{}=\"{}\" {} not found even though {} is greater than zero.", - RoutineName, - CurrentModuleObject, - TransSystem(TransRefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - cNumericFieldNames(4))); - ShowContinueError(state, - " The low temperature suction piping heat gain will not be calculated unless a Zone is defined to determine " - "the environmental temperature surrounding the piping."); - } else if (lNumericBlanks(4) && !lAlphaBlanks(AlphaNum)) { - ShowWarningError( - state, - EnergyPlus::format("{}{}=\"{}\" {} will not be used and suction piping heat gain will not be calculated because {} was blank.", - RoutineName, - CurrentModuleObject, - TransSystem(TransRefrigSysNum).Name, - cAlphaFieldNames(AlphaNum), - cNumericFieldNames(4))); - } // Low temperature suction piping heat gains + readSuctionPiping(state, + ErrorsFound, + RoutineName, + CurrentModuleObject, + Numbers, + lNumericBlanks, + Alphas, + lAlphaBlanks, + cAlphaFieldNames, + cNumericFieldNames, + AlphaNum, + 4, + TransSystem(TransRefrigSysNum).Name, + TransSystem(TransRefrigSysNum).SumUASuctionPipingLT, + TransSystem(TransRefrigSysNum).SuctionPipeActualZoneNumLT, + TransSystem(TransRefrigSysNum).SuctionPipeZoneNodeNumLT, + "low temperature"); AlphaNum = 11; if (!lAlphaBlanks(AlphaNum)) { @@ -7014,6 +6285,11 @@ void GetRefrigerationInput(EnergyPlusData &state) lAlphaBlanks.deallocate(); lNumericBlanks.deallocate(); + // Helper lambda: iterate a 1-based Array1D collection checking NumSysAttach. + // Items with NumSysAttach < 1 are counted as unused and optionally listed. + // The caller supplies onMultiple (called with the item index when NumSysAttach > 1) + // and warnSummary (called with unusedCount when unusedCount > 0 and + // !DisplayExtraWarnings) so that per-type summary messages are preserved exactly. if (state.dataRefrigCase->NumSimulationCases > 0) { // Find unused and non-unique display case objects to report in eio and err file and sum // all HVAC RA fractions and write error message if greater than 1 for any zone @@ -7042,195 +6318,145 @@ void GetRefrigerationInput(EnergyPlusData &state) // check for cases not connected to systems and cases connected // more than once (twice in a system or to more than one system) - state.dataRefrigCase->NumUnusedRefrigCases = 0; - for (int CaseNum = 1; CaseNum <= state.dataRefrigCase->NumSimulationCases; ++CaseNum) { - if (RefrigCase(CaseNum).NumSysAttach == 1) { - continue; - } - if (RefrigCase(CaseNum).NumSysAttach < 1) { - ++state.dataRefrigCase->NumUnusedRefrigCases; - if (state.dataGlobal->DisplayExtraWarnings) { - // individual case names listed if DataGlobals::DisplayExtraWarnings option selected - ShowWarningError(state, EnergyPlus::format("{}: Refrigeration:Case=\"{}\" unused. ", RoutineName, RefrigCase(CaseNum).Name)); - } // display extra warnings - give a list of unused cases - } // unused case - if (RefrigCase(CaseNum).NumSysAttach > 1) { + checkUnusedComponents( + state, + RoutineName, + RefrigCase, + state.dataRefrigCase->NumSimulationCases, + state.dataRefrigCase->NumUnusedRefrigCases, + "Refrigeration:Case", + [&](int CaseNum) { ErrorsFound = true; ShowSevereError(state, EnergyPlus::format( "{}: Refrigeration:Case=\"{}\", Same refrigerated case name referenced ", RoutineName, RefrigCase(CaseNum).Name)); ShowContinueError(state, " by more than one refrigeration system and/or compressor rack."); - } // if looking for same case attached to multiple systems/racks - } // NumSimulationCases - - if ((state.dataRefrigCase->NumUnusedRefrigCases > 0) && (!state.dataGlobal->DisplayExtraWarnings)) { - // write to error file, - // summary number of unused cases given if DataGlobals::DisplayExtraWarnings option not selected - ShowWarningError(state, - EnergyPlus::format("Refrigeration:Case -> {} unused refrigerated case(s) found during input processing.", - state.dataRefrigCase->NumUnusedRefrigCases)); - ShowContinueError(state, " These refrigerated cases are in the input file but are not connected to a "); - ShowContinueError(state, " Refrigeration:CompressorRack, Refrigeration:System, or Refrigeration:SecondarySystem object."); - ShowContinueError(state, " These unused refrigeration cases will not be simulated."); - ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); - } // NumUnusedRefrigCases + }, + [&](int n) { + ShowWarningError(state, EnergyPlus::format("Refrigeration:Case -> {} unused refrigerated case(s) found during input processing.", n)); + ShowContinueError(state, " These refrigerated cases are in the input file but are not connected to a "); + ShowContinueError(state, " Refrigeration:CompressorRack, Refrigeration:System, or Refrigeration:SecondarySystem object."); + ShowContinueError(state, " These unused refrigeration cases will not be simulated."); + ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); + }); } // numsimulation cases > 0 if (state.dataRefrigCase->NumSimulationCompressors > 0) { // check for compressors not connected to systems and compressors connected more than once // (twice in a system or to more than one system) - state.dataRefrigCase->NumUnusedCompressors = 0; - for (int CompNum = 1; CompNum <= state.dataRefrigCase->NumSimulationCompressors; ++CompNum) { - if (Compressor(CompNum).NumSysAttach == 1) { - continue; - } - if (Compressor(CompNum).NumSysAttach < 1) { - ++state.dataRefrigCase->NumUnusedCompressors; - if (state.dataGlobal->DisplayExtraWarnings) { - // individual compressor names listed if DataGlobals::DisplayExtraWarnings option selected - ShowWarningError(state, - EnergyPlus::format("{}: Refrigeration:Compressor=\"{}\" unused. ", RoutineName, Compressor(CompNum).Name)); - } // display extra warnings - give a list of unused compressors - } // unused compressor - if (Compressor(CompNum).NumSysAttach > 1) { + checkUnusedComponents( + state, + RoutineName, + Compressor, + state.dataRefrigCase->NumSimulationCompressors, + state.dataRefrigCase->NumUnusedCompressors, + "Refrigeration:Compressor", + [&](int CompNum) { ErrorsFound = true; ShowSevereError(state, EnergyPlus::format("{}: Refrigeration:Compressor=\"{}\", Same refrigeration compressor name referenced", RoutineName, Compressor(CompNum).Name)); ShowContinueError(state, " by more than one refrigeration system."); - } // looking for same compressor attached to multiple systems/racks - } // NumSimulationCompressors - - if ((state.dataRefrigCase->NumUnusedCompressors > 0) && (!state.dataGlobal->DisplayExtraWarnings)) { - // write to error file, - // summary number of unused compressors given if DataGlobals::DisplayExtraWarnings option not selected - ShowWarningError(state, - EnergyPlus::format("Refrigeration:Compressor -> {} unused refrigeration compressor(s) found during input processing.", - state.dataRefrigCase->NumUnusedCompressors)); - ShowContinueError(state, - " Those refrigeration compressors are in the input file but are not connected to a Refrigeration:System object."); - ShowContinueError(state, " These unused refrigeration compressors will not be simulated."); - ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); - } // NumUnusedCompressors + }, + [&](int n) { + ShowWarningError( + state, EnergyPlus::format("Refrigeration:Compressor -> {} unused refrigeration compressor(s) found during input processing.", n)); + ShowContinueError(state, + " Those refrigeration compressors are in the input file but are not connected to a Refrigeration:System object."); + ShowContinueError(state, " These unused refrigeration compressors will not be simulated."); + ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); + }); } // NumSimulationCompressors > 0 int NumUnusedWalkIns = 0; if (state.dataRefrigCase->NumSimulationWalkIns > 0) { // check for refrigeration WalkIns not connected to any systems and // refrigeration WalkIns connected more than once - for (int WalkInNum = 1; WalkInNum <= state.dataRefrigCase->NumSimulationWalkIns; ++WalkInNum) { - if (WalkIn(WalkInNum).NumSysAttach == 1) { - continue; - } - if (WalkIn(WalkInNum).NumSysAttach < 1) { - ++NumUnusedWalkIns; - if (state.dataGlobal->DisplayExtraWarnings) { - // individual walkin names listed if DataGlobals::DisplayExtraWarnings option selected - ShowWarningError(state, EnergyPlus::format("{}: Refrigeration:WalkIn=\"{}\" unused. ", RoutineName, WalkIn(WalkInNum).Name)); - } // display extra warnings - give a list of unused WalkIns - } // unused walkin - if (WalkIn(WalkInNum).NumSysAttach > 1) { + checkUnusedComponents( + state, + RoutineName, + WalkIn, + state.dataRefrigCase->NumSimulationWalkIns, + NumUnusedWalkIns, + "Refrigeration:WalkIn", + [&](int WalkInNum) { ErrorsFound = true; ShowSevereError(state, EnergyPlus::format("{}: Refrigeration:WalkIn=\"{}\", Same Refrigeration WalkIn name referenced", RoutineName, WalkIn(WalkInNum).Name)); ShowContinueError(state, " by more than one refrigeration system and/or compressor rack."); - } // if looking for same walk in attached to multiple systems/racks - } // NumSimulationWalkIns - - if ((NumUnusedWalkIns > 0) && (!state.dataGlobal->DisplayExtraWarnings)) { - // write to error file, - // summary number of unused walkins given if DataGlobals::DisplayExtraWarnings option not selected - ShowWarningError(state, - EnergyPlus::format("{}Refrigeration:WalkIn -> {} unused refrigeration WalkIns found during input processing.", - RoutineName, - NumUnusedWalkIns)); - ShowContinueError(state, " Those refrigeration WalkIns are in the input file but are not connected to a "); - ShowContinueError(state, " Refrigeration:CompressorRack, Refrigeration:System or Refrigeration:SecondarySystem object."); - ShowContinueError(state, " These unused refrigeration WalkIns will not be simulated."); - ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); - } // NumUnusedWalkIns + }, + [&](int n) { + ShowWarningError( + state, + EnergyPlus::format("{}Refrigeration:WalkIn -> {} unused refrigeration WalkIns found during input processing.", RoutineName, n)); + ShowContinueError(state, " Those refrigeration WalkIns are in the input file but are not connected to a "); + ShowContinueError(state, " Refrigeration:CompressorRack, Refrigeration:System or Refrigeration:SecondarySystem object."); + ShowContinueError(state, " These unused refrigeration WalkIns will not be simulated."); + ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); + }); } // NumSimulationWalkIns > 0 if (state.dataRefrigCase->NumSimulationRefrigAirChillers > 0) { // check for air chillers not connected to any systems and // air chillers connected more than once - state.dataRefrigCase->NumUnusedCoils = 0; - for (int CoilNum = 1; CoilNum <= state.dataRefrigCase->NumSimulationRefrigAirChillers; ++CoilNum) { - if (WarehouseCoil(CoilNum).NumSysAttach == 1) { - continue; - } - if (WarehouseCoil(CoilNum).NumSysAttach < 1) { - ++NumUnusedWalkIns; - if (state.dataGlobal->DisplayExtraWarnings) { - // individual walkin names listed if DataGlobals::DisplayExtraWarnings option selected - ShowWarningError(state, - EnergyPlus::format("{}: Refrigeration:AirChiller=\"{}\" unused. ", RoutineName, WarehouseCoil(CoilNum).Name)); - } // display extra warnings - give a list of unused chillers - } // unused chiller - if (WarehouseCoil(CoilNum).NumSysAttach > 1) { + checkUnusedComponents( + state, + RoutineName, + WarehouseCoil, + state.dataRefrigCase->NumSimulationRefrigAirChillers, + state.dataRefrigCase->NumUnusedCoils, + "Refrigeration:AirChiller", + [&](int CoilNum) { ErrorsFound = true; ShowSevereError(state, EnergyPlus::format("{}: Refrigeration:AirChiller=\"{}\", Same Refrigeration Air Chiller name referenced", RoutineName, WarehouseCoil(CoilNum).Name)); ShowContinueError(state, " by more than one refrigeration system and/or compressor rack."); - } // if looking for same walk in attached to multiple systems/racks - } // NumSimulationRefrigAirchillers - - if ((state.dataRefrigCase->NumUnusedCoils > 0) && (!state.dataGlobal->DisplayExtraWarnings)) { - // write to error file, - // summary number of unused air chillers given if DataGlobals::DisplayExtraWarnings option not selected - ShowWarningError(state, - EnergyPlus::format("{}Refrigeration:AirChiller -> {} unused refrigeration air chillers found during input processing.", - RoutineName, - state.dataRefrigCase->NumUnusedCoils)); - ShowContinueError(state, " Those refrigeration air chillers are in the input file but are not connected to a "); - ShowContinueError(state, " Refrigeration:CompressorRack, Refrigeration:System or Refrigeration:SecondarySystem object."); - ShowContinueError(state, " These unused refrigeration air chillers will not be simulated."); - ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); - } // NumUnusedAirChllerss - } // NumSimulationAirChillers > 0 - + }, + [&](int n) { + ShowWarningError( + state, + EnergyPlus::format( + "{}Refrigeration:AirChiller -> {} unused refrigeration air chillers found during input processing.", RoutineName, n)); + ShowContinueError(state, " Those refrigeration air chillers are in the input file but are not connected to a "); + ShowContinueError(state, " Refrigeration:CompressorRack, Refrigeration:System or Refrigeration:SecondarySystem object."); + ShowContinueError(state, " These unused refrigeration air chillers will not be simulated."); + ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); + }); + } // NumSimulationAirChillers > 0 + if (state.dataRefrigCase->NumSimulationSecondarySystems > 0) { // check for refrigeration Secondarys not connected to detailed systems and // refrigeration Secondarys connected more than once - state.dataRefrigCase->NumUnusedSecondarys = 0; - for (int SecondaryNum = 1; SecondaryNum <= state.dataRefrigCase->NumSimulationSecondarySystems; ++SecondaryNum) { - if (Secondary(SecondaryNum).NumSysAttach == 1) { - continue; - } - if (Secondary(SecondaryNum).NumSysAttach < 1) { - ++state.dataRefrigCase->NumUnusedSecondarys; - if (state.dataGlobal->DisplayExtraWarnings) { - // individual secondary names listed if DataGlobals::DisplayExtraWarnings option selected - ShowWarningError(state, - EnergyPlus::format("{}: Refrigeration:Secondary=\"{}\" unused. ", RoutineName, Secondary(SecondaryNum).Name)); - } // display extra warnings - give a list of unused Secondaries - } // unused secondary - if (Secondary(SecondaryNum).NumSysAttach > 1) { + checkUnusedComponents( + state, + RoutineName, + Secondary, + state.dataRefrigCase->NumSimulationSecondarySystems, + state.dataRefrigCase->NumUnusedSecondarys, + "Refrigeration:Secondary", + [&](int SecondaryNum) { ErrorsFound = true; ShowSevereError(state, EnergyPlus::format("{}: Refrigeration:Secondary=\"{}\", Same Refrigeration Secondary name referenced", RoutineName, Secondary(SecondaryNum).Name)); ShowContinueError(state, " by more than one refrigeration system"); - } // looking for same secondary loop attached to multiple systems/racks - } // NumSimulationSecondarys - - if ((state.dataRefrigCase->NumUnusedSecondarys > 0) && (!state.dataGlobal->DisplayExtraWarnings)) { - // write to error file, - // summary number of unused secondaries given if DataGlobals::DisplayExtraWarnings option not selected - ShowWarningError(state, - EnergyPlus::format("{}Refrigeration:Secondary -> {} unused refrigeration Secondary Loops found during input processing.", - RoutineName, - state.dataRefrigCase->NumUnusedSecondarys)); - ShowContinueError(state, " Those refrigeration Secondary Loops are in the input file but are not connected to a refrigeration system."); - ShowContinueError(state, " These unused refrigeration secondaries will not be simulated."); - ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); - } // NumUnusedSecondarys + }, + [&](int n) { + ShowWarningError( + state, + EnergyPlus::format( + "{}Refrigeration:Secondary -> {} unused refrigeration Secondary Loops found during input processing.", RoutineName, n)); + ShowContinueError(state, + " Those refrigeration Secondary Loops are in the input file but are not connected to a refrigeration system."); + ShowContinueError(state, " These unused refrigeration secondaries will not be simulated."); + ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); + }); } // NumSimulationSecondarySystems > 0 if (state.dataRefrigCase->NumRefrigCondensers > 0) { @@ -7238,67 +6464,45 @@ void GetRefrigerationInput(EnergyPlusData &state) // - determines number of loops through refrigeration simulation // because of dependence of performance on total condenser load state.dataRefrigCase->NumSimulationSharedCondensers = 0; - state.dataRefrigCase->NumUnusedCondensers = 0; - for (int CondNum = 1; CondNum <= state.dataRefrigCase->NumRefrigCondensers; ++CondNum) { - if (Condenser(CondNum).NumSysAttach == 1) { - continue; - } - if (Condenser(CondNum).NumSysAttach < 1) { - ++state.dataRefrigCase->NumUnusedCondensers; - if (state.dataGlobal->DisplayExtraWarnings) { - // individual condenser names listed if DataGlobals::DisplayExtraWarnings option selected - ShowWarningError(state, EnergyPlus::format("{}: Refrigeration:Condenser=\"{}\" unused. ", RoutineName, Condenser(CondNum).Name)); - } // display extra warnings - give a list of unused condensers - } // unused condenser - if (Condenser(CondNum).NumSysAttach > 1) { - ++state.dataRefrigCase->NumSimulationSharedCondensers; - } // looking for shared condensers - } // CondNum - - if ((state.dataRefrigCase->NumUnusedCondensers > 0) && (!state.dataGlobal->DisplayExtraWarnings)) { - // write to error file, - // summary number of unused condensers given if DataGlobals::DisplayExtraWarnings option not selected - ShowWarningError(state, - EnergyPlus::format("{}Refrigeration condenser -> {} unused refrigeration condensers found during input processing.", - RoutineName, - state.dataRefrigCase->NumUnusedCondensers)); - ShowContinueError(state, " Those refrigeration condensers are in the input file but are not connected to a refrigeration system."); - ShowContinueError(state, " These unused refrigeration condensers will not be simulated."); - ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); - } // NumUnusedCondensers and displayextra warnings + checkUnusedComponents( + state, + RoutineName, + Condenser, + state.dataRefrigCase->NumRefrigCondensers, + state.dataRefrigCase->NumUnusedCondensers, + "Refrigeration:Condenser", + [&](int /*CondNum*/) { ++state.dataRefrigCase->NumSimulationSharedCondensers; }, + [&](int n) { + ShowWarningError(state, + EnergyPlus::format("{}Refrigeration condenser -> {} unused refrigeration condensers found during input processing.", + RoutineName, + n)); + ShowContinueError(state, " Those refrigeration condensers are in the input file but are not connected to a refrigeration system."); + ShowContinueError(state, " These unused refrigeration condensers will not be simulated."); + ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); + }); } // DataHeatBalance::NumRefrigCondensers > 0 if (state.dataRefrigCase->NumSimulationGasCooler > 0) { // Check for presence of shared gas coolers and for unused gas coolers state.dataRefrigCase->NumSimulationSharedGasCoolers = 0; - state.dataRefrigCase->NumUnusedGasCoolers = 0; - for (int GCNum = 1; GCNum <= state.dataRefrigCase->NumSimulationGasCooler; ++GCNum) { - if (GasCooler(GCNum).NumSysAttach == 1) { - continue; - } - if (GasCooler(GCNum).NumSysAttach < 1) { - ++state.dataRefrigCase->NumUnusedGasCoolers; - if (state.dataGlobal->DisplayExtraWarnings) { - // individual gas cooler names listed if DataGlobals::DisplayExtraWarnings option selected - ShowWarningError(state, EnergyPlus::format("{}: Refrigeration:GasCooler=\"{}\" unused. ", RoutineName, GasCooler(GCNum).Name)); - } // display extra warnings - give a list of unused gas coolers - } // unused gas cooler - if (GasCooler(GCNum).NumSysAttach > 1) { - ++state.dataRefrigCase->NumSimulationSharedGasCoolers; - } // looking for shared gas coolers - } // GCNum - - if ((state.dataRefrigCase->NumUnusedGasCoolers > 0) && (!state.dataGlobal->DisplayExtraWarnings)) { - // write to error file, - // summary number of unused gas coolers given if DataGlobals::DisplayExtraWarnings option not selected - ShowWarningError(state, - EnergyPlus::format("{}Refrigeration gas cooler -> {} unused refrigeration gas cooler(s) found during input processing.", - RoutineName, - state.dataRefrigCase->NumUnusedGasCoolers)); - ShowContinueError(state, " These refrigeration gas coolers are in the input file but are not connected to a refrigeration system."); - ShowContinueError(state, " These unused refrigeration gas coolers will not be simulated."); - ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); - } // NumUnusedGasCoolers and displayextra warnings + checkUnusedComponents( + state, + RoutineName, + GasCooler, + state.dataRefrigCase->NumSimulationGasCooler, + state.dataRefrigCase->NumUnusedGasCoolers, + "Refrigeration:GasCooler", + [&](int /*GCNum*/) { ++state.dataRefrigCase->NumSimulationSharedGasCoolers; }, + [&](int n) { + ShowWarningError( + state, + EnergyPlus::format( + "{}Refrigeration gas cooler -> {} unused refrigeration gas cooler(s) found during input processing.", RoutineName, n)); + ShowContinueError(state, " These refrigeration gas coolers are in the input file but are not connected to a refrigeration system."); + ShowContinueError(state, " These unused refrigeration gas coolers will not be simulated."); + ShowContinueError(state, " Use Output:Diagnostics,DisplayUnusedObjects; to see them. "); + }); } // NumSimulationGasCooler > 0 // echo input to eio file. @@ -7309,6 +6513,30 @@ void GetRefrigerationInput(EnergyPlusData &state) } } +// Helper: set up the 5 standard output variables for a single refrigeration compressor. +static void +setupCompressorOutputVars(EnergyPlusData &state, RefrigCompressorData &comp, const std::string &prefix, OutputProcessor::TimeStepType tsType) +{ + SetupOutputVariable(state, prefix + " Electricity Rate", Constant::Units::W, comp.Power, tsType, OutputProcessor::StoreType::Average, comp.Name); + SetupOutputVariable(state, + prefix + " Electricity Energy", + Constant::Units::J, + comp.ElecConsumption, + tsType, + OutputProcessor::StoreType::Sum, + comp.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::Plant, + OutputProcessor::EndUseCat::Refrigeration, + comp.EndUseSubcategory); + SetupOutputVariable( + state, prefix + " Heat Transfer Rate", Constant::Units::W, comp.Capacity, tsType, OutputProcessor::StoreType::Average, comp.Name); + SetupOutputVariable( + state, prefix + " Heat Transfer Energy", Constant::Units::J, comp.CoolingEnergy, tsType, OutputProcessor::StoreType::Sum, comp.Name); + SetupOutputVariable( + state, prefix + " Runtime Fraction", Constant::Units::None, comp.LoadFactor, tsType, OutputProcessor::StoreType::Average, comp.Name); +} + void SetupReportInput(EnergyPlusData &state) { // SUBROUTINE INFORMATION: @@ -8172,185 +7400,98 @@ void SetupReportInput(EnergyPlusData &state) for (int secondNum = 1; secondNum <= state.dataRefrigCase->NumSimulationSecondarySystems; ++secondNum) { auto &secondary = Secondary(secondNum); if (secondary.NumSysAttach == 1) { - if (secondary.CoilFlag) { // secondary system serves chillers and is solved on HVAC time step - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Pump Electricity Rate", - Constant::Units::W, - secondary.PumpPowerTotal, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Pump Electricity Energy", - Constant::Units::J, - secondary.PumpElecEnergyTotal, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - secondary.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - secondary.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Load Heat Transfer Rate", - Constant::Units::W, - secondary.TotalRefrigLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Load Heat Transfer Energy", - Constant::Units::J, - secondary.TotalRefrigEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Total Heat Transfer Rate", - Constant::Units::W, - secondary.TotalCoolingLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Total Heat Transfer Energy", - Constant::Units::J, - secondary.TotalCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Estimated Refrigerant Inventory Mass", - Constant::Units::kg, - secondary.RefInventory, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Volume Flow Rate", - Constant::Units::m3_s, - secondary.FlowVolActual, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Pipe Heat Gain Rate", - Constant::Units::W, - secondary.DistPipeHeatGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Pipe Heat Gain Energy", - Constant::Units::J, - secondary.DistPipeHeatGainEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Receiver Heat Gain Rate", - Constant::Units::W, - secondary.ReceiverHeatGain, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Secondary Loop Receiver Heat Gain Energy", - Constant::Units::J, - secondary.ReceiverHeatGainEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - secondary.Name); - } else { // Secondary loop serves cases and walk-ins on zone(load) time step - SetupOutputVariable(state, - "Refrigeration Secondary Loop Pump Electricity Rate", - Constant::Units::W, - secondary.PumpPowerTotal, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Secondary Loop Pump Electricity Energy", - Constant::Units::J, - secondary.PumpElecEnergyTotal, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - secondary.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - secondary.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Secondary Loop Load Heat Transfer Rate", - Constant::Units::W, - secondary.TotalRefrigLoad, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Secondary Loop Load Heat Transfer Energy", - Constant::Units::J, - secondary.TotalRefrigEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Secondary Loop Total Heat Transfer Rate", - Constant::Units::W, - secondary.TotalCoolingLoad, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Secondary Loop Total Heat Transfer Energy", - Constant::Units::J, - secondary.TotalCoolingEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Secondary Loop Estimated Refrigerant Inventory Mass", - Constant::Units::kg, - secondary.RefInventory, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Secondary Loop Volume Flow Rate", - Constant::Units::m3_s, - secondary.FlowVolActual, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Secondary Loop Pipe Heat Gain Rate", - Constant::Units::W, - secondary.DistPipeHeatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Secondary Loop Pipe Heat Gain Energy", - Constant::Units::J, - secondary.DistPipeHeatGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Secondary Loop Receiver Heat Gain Rate", - Constant::Units::W, - secondary.ReceiverHeatGain, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - secondary.Name); - SetupOutputVariable(state, - "Refrigeration Secondary Loop Receiver Heat Gain Energy", - Constant::Units::J, - secondary.ReceiverHeatGainEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - secondary.Name); - } // NOT coilflag so on Zone timestep + // CoilFlag: serves chillers on HVAC (System) time step; otherwise cases/walkins on Zone time step + const std::string secPrefix = secondary.CoilFlag ? "Refrigeration Air Chiller Secondary Loop" : "Refrigeration Secondary Loop"; + const auto secTsType = secondary.CoilFlag ? OutputProcessor::TimeStepType::System : OutputProcessor::TimeStepType::Zone; + + SetupOutputVariable(state, + secPrefix + " Pump Electricity Rate", + Constant::Units::W, + secondary.PumpPowerTotal, + secTsType, + OutputProcessor::StoreType::Average, + secondary.Name); + SetupOutputVariable(state, + secPrefix + " Pump Electricity Energy", + Constant::Units::J, + secondary.PumpElecEnergyTotal, + secTsType, + OutputProcessor::StoreType::Sum, + secondary.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::Plant, + OutputProcessor::EndUseCat::Refrigeration, + secondary.EndUseSubcategory); + SetupOutputVariable(state, + secPrefix + " Load Heat Transfer Rate", + Constant::Units::W, + secondary.TotalRefrigLoad, + secTsType, + OutputProcessor::StoreType::Average, + secondary.Name); + SetupOutputVariable(state, + secPrefix + " Load Heat Transfer Energy", + Constant::Units::J, + secondary.TotalRefrigEnergy, + secTsType, + OutputProcessor::StoreType::Sum, + secondary.Name); + SetupOutputVariable(state, + secPrefix + " Total Heat Transfer Rate", + Constant::Units::W, + secondary.TotalCoolingLoad, + secTsType, + OutputProcessor::StoreType::Average, + secondary.Name); + SetupOutputVariable(state, + secPrefix + " Total Heat Transfer Energy", + Constant::Units::J, + secondary.TotalCoolingEnergy, + secTsType, + OutputProcessor::StoreType::Sum, + secondary.Name); + SetupOutputVariable(state, + secPrefix + " Estimated Refrigerant Inventory Mass", + Constant::Units::kg, + secondary.RefInventory, + secTsType, + OutputProcessor::StoreType::Average, + secondary.Name); + SetupOutputVariable(state, + secPrefix + " Volume Flow Rate", + Constant::Units::m3_s, + secondary.FlowVolActual, + secTsType, + OutputProcessor::StoreType::Average, + secondary.Name); + SetupOutputVariable(state, + secPrefix + " Pipe Heat Gain Rate", + Constant::Units::W, + secondary.DistPipeHeatGain, + secTsType, + OutputProcessor::StoreType::Average, + secondary.Name); + SetupOutputVariable(state, + secPrefix + " Pipe Heat Gain Energy", + Constant::Units::J, + secondary.DistPipeHeatGainEnergy, + secTsType, + OutputProcessor::StoreType::Sum, + secondary.Name); + SetupOutputVariable(state, + secPrefix + " Receiver Heat Gain Rate", + Constant::Units::W, + secondary.ReceiverHeatGain, + secTsType, + OutputProcessor::StoreType::Average, + secondary.Name); + SetupOutputVariable(state, + secPrefix + " Receiver Heat Gain Energy", + Constant::Units::J, + secondary.ReceiverHeatGainEnergy, + secTsType, + OutputProcessor::StoreType::Sum, + secondary.Name); if (secondary.ReceiverZoneNum > 0) { SetupZoneInternalGain(state, secondary.ReceiverZoneNum, @@ -8375,19 +7516,80 @@ void SetupReportInput(EnergyPlusData &state) auto &RefrigRack = state.dataRefrigCase->RefrigRack; for (int rackNum = 1; rackNum <= state.dataRefrigCase->NumRefrigeratedRacks; ++rackNum) { auto &rack = RefrigRack(rackNum); - if (rack.CoilFlag) { // rack serves chillers and is solved on HVAC time step + // CoilFlag: serves chillers on HVAC (System) time step; otherwise cases/walkins on Zone time step + const std::string rackPrefix = rack.CoilFlag ? "Refrigeration Air Chiller Compressor Rack" : "Refrigeration Compressor Rack"; + const auto rackTsType = rack.CoilFlag ? OutputProcessor::TimeStepType::System : OutputProcessor::TimeStepType::Zone; + + SetupOutputVariable(state, + rackPrefix + " Electricity Rate", + Constant::Units::W, + rack.RackCompressorPower, + rackTsType, + OutputProcessor::StoreType::Average, + rack.Name); + SetupOutputVariable(state, + rackPrefix + " Electricity Energy", + Constant::Units::J, + rack.RackElecConsumption, + rackTsType, + OutputProcessor::StoreType::Sum, + rack.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::Plant, + OutputProcessor::EndUseCat::Refrigeration, + rack.EndUseSubcategory); + SetupOutputVariable(state, + rackPrefix + " Condenser Fan Electricity Rate", + Constant::Units::W, + rack.ActualCondenserFanPower, + rackTsType, + OutputProcessor::StoreType::Average, + rack.Name); + SetupOutputVariable(state, + rackPrefix + " Condenser Fan Electricity Energy", + Constant::Units::J, + rack.CondenserFanConsumption, + rackTsType, + OutputProcessor::StoreType::Sum, + rack.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::Plant, + OutputProcessor::EndUseCat::Refrigeration, + rack.EndUseSubcategory); + SetupOutputVariable(state, + rackPrefix + " Total Heat Transfer Rate", + Constant::Units::W, + rack.RackCapacity, + rackTsType, + OutputProcessor::StoreType::Average, + rack.Name); + SetupOutputVariable(state, + rackPrefix + " Total Heat Transfer Energy", + Constant::Units::J, + rack.RackCoolingEnergy, + rackTsType, + OutputProcessor::StoreType::Sum, + rack.Name, + Constant::eResource::EnergyTransfer, + OutputProcessor::Group::Plant, + OutputProcessor::EndUseCat::Refrigeration, + rack.EndUseSubcategory); + SetupOutputVariable( + state, rackPrefix + " COP", Constant::Units::W_W, rack.RackCompressorCOP, rackTsType, OutputProcessor::StoreType::Average, rack.Name); + + if (rack.CondenserType == DataHeatBalance::RefrigCondenserType::Evap) { SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Electricity Rate", + rackPrefix + " Evaporative Condenser Pump Electricity Rate", Constant::Units::W, - rack.RackCompressorPower, - OutputProcessor::TimeStepType::System, + rack.ActualEvapPumpPower, + rackTsType, OutputProcessor::StoreType::Average, rack.Name); SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Electricity Energy", + rackPrefix + " Evaporative Condenser Pump Electricity Energy", Constant::Units::J, - rack.RackElecConsumption, - OutputProcessor::TimeStepType::System, + rack.EvapPumpConsumption, + rackTsType, OutputProcessor::StoreType::Sum, rack.Name, Constant::eResource::Electricity, @@ -8395,17 +7597,17 @@ void SetupReportInput(EnergyPlusData &state) OutputProcessor::EndUseCat::Refrigeration, rack.EndUseSubcategory); SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Condenser Fan Electricity Rate", + rackPrefix + " Evaporative Condenser Basin Heater Electricity Rate", Constant::Units::W, - rack.ActualCondenserFanPower, - OutputProcessor::TimeStepType::System, + rack.BasinHeaterPower, + rackTsType, OutputProcessor::StoreType::Average, rack.Name); SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Condenser Fan Electricity Energy", + rackPrefix + " Evaporative Condenser Basin Heater Electricity Energy", Constant::Units::J, - rack.CondenserFanConsumption, - OutputProcessor::TimeStepType::System, + rack.BasinHeaterConsumption, + rackTsType, OutputProcessor::StoreType::Sum, rack.Name, Constant::eResource::Electricity, @@ -8413,299 +7615,69 @@ void SetupReportInput(EnergyPlusData &state) OutputProcessor::EndUseCat::Refrigeration, rack.EndUseSubcategory); SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Total Heat Transfer Rate", - Constant::Units::W, - rack.RackCapacity, - OutputProcessor::TimeStepType::System, + rackPrefix + " Evaporative Condenser Water Volume Flow Rate", + Constant::Units::m3_s, + rack.EvapWaterConsumpRate, + rackTsType, OutputProcessor::StoreType::Average, rack.Name); SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Total Heat Transfer Energy", - Constant::Units::J, - rack.RackCoolingEnergy, - OutputProcessor::TimeStepType::System, + rackPrefix + " Evaporative Condenser Water Volume", + Constant::Units::m3, + rack.EvapWaterConsumption, + rackTsType, OutputProcessor::StoreType::Sum, rack.Name, - Constant::eResource::EnergyTransfer, + Constant::eResource::Water, OutputProcessor::Group::Plant, OutputProcessor::EndUseCat::Refrigeration, rack.EndUseSubcategory); + } // Evap condenser + + if (rack.HeatRejectionLocation == HeatRejLocation::Zone) { SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack COP", - Constant::Units::W_W, - rack.RackCompressorCOP, - OutputProcessor::TimeStepType::System, + rackPrefix + " Zone Sensible Heating Rate", + Constant::Units::W, + rack.SensZoneCreditHeatRate, + rackTsType, OutputProcessor::StoreType::Average, rack.Name); + SetupOutputVariable(state, + rackPrefix + " Zone Sensible Heating Energy", + Constant::Units::J, + rack.SensZoneCreditHeat, + rackTsType, + OutputProcessor::StoreType::Sum, + rack.Name); - if (rack.CondenserType == DataHeatBalance::RefrigCondenserType::Evap) { - SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Evaporative Condenser Pump Electricity Rate", - Constant::Units::W, - rack.ActualEvapPumpPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Evaporative Condenser Pump Electricity Energy", - Constant::Units::J, - rack.EvapPumpConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - rack.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - rack.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Evaporative Condenser Basin Heater Electricity Rate", - Constant::Units::W, - rack.BasinHeaterPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Evaporative Condenser Basin Heater Electricity Energy", - Constant::Units::J, - rack.BasinHeaterConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - rack.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - rack.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Evaporative Condenser Water Volume Flow Rate", - Constant::Units::m3_s, - rack.EvapWaterConsumpRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Evaporative Condenser Water Volume", - Constant::Units::m3, - rack.EvapWaterConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - rack.Name, - Constant::eResource::Water, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - rack.EndUseSubcategory); - } // Evap condenser + SetupOutputVariable(state, + rackPrefix + " Return Air Sensible Heating Rate", + Constant::Units::W, + rack.SensHVACCreditHeatRate, + rackTsType, + OutputProcessor::StoreType::Average, + rack.Name); + SetupOutputVariable(state, + rackPrefix + " Return Air Sensible Heating Energy", + Constant::Units::J, + rack.SensHVACCreditHeat, + rackTsType, + OutputProcessor::StoreType::Sum, + rack.Name); - if (rack.HeatRejectionLocation == HeatRejLocation::Zone) { - SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Zone Sensible Heating Rate", - Constant::Units::W, - rack.SensZoneCreditHeatRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Zone Sensible Heating Energy", - Constant::Units::J, - rack.SensZoneCreditHeat, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - rack.Name); - - SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Return Air Sensible Heating Rate", - Constant::Units::W, - rack.SensHVACCreditHeatRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller Compressor Rack Return Air Sensible Heating Energy", - Constant::Units::J, - rack.SensHVACCreditHeat, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - rack.Name); - - // If CoilFlag is true and Location is Zone, GetRefrigerationInput ensures you must have a Heat Rejection Zone provided already - SetupZoneInternalGain(state, - rack.HeatRejectionZoneNum, - rack.Name, - DataHeatBalance::IntGainType::RefrigerationCompressorRack, - &rack.SensZoneCreditHeatRate, - &rack.SensHVACCreditHeatRate); - - } // LocationZone - - } else { // Rack serves cases and walkins on zone (load) time step - - SetupOutputVariable(state, - "Refrigeration Compressor Rack Electricity Rate", - Constant::Units::W, - rack.RackCompressorPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Electricity Energy", - Constant::Units::J, - rack.RackElecConsumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - rack.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - rack.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Condenser Fan Electricity Rate", - Constant::Units::W, - rack.ActualCondenserFanPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Condenser Fan Electricity Energy", - Constant::Units::J, - rack.CondenserFanConsumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - rack.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - rack.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Total Heat Transfer Rate", - Constant::Units::W, - rack.RackCapacity, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Total Heat Transfer Energy", - Constant::Units::J, - rack.RackCoolingEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - rack.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - rack.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Compressor Rack COP", - Constant::Units::W_W, - rack.RackCompressorCOP, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - rack.Name); - - if (rack.CondenserType == DataHeatBalance::RefrigCondenserType::Evap) { - SetupOutputVariable(state, - "Refrigeration Compressor Rack Evaporative Condenser Pump Electricity Rate", - Constant::Units::W, - rack.ActualEvapPumpPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Evaporative Condenser Pump Electricity Energy", - Constant::Units::J, - rack.EvapPumpConsumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - rack.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - rack.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Evaporative Condenser Basin Heater Electricity Rate", - Constant::Units::W, - rack.BasinHeaterPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Evaporative Condenser Basin Heater Electricity Energy", - Constant::Units::J, - rack.BasinHeaterConsumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - rack.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - rack.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Evaporative Condenser Water Volume Flow Rate", - Constant::Units::m3_s, - rack.EvapWaterConsumpRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Evaporative Condenser Water Volume", - Constant::Units::m3, - rack.EvapWaterConsumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - rack.Name, - Constant::eResource::Water, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - rack.EndUseSubcategory); - } // condenser evap - - if (rack.HeatRejectionLocation == HeatRejLocation::Zone) { - SetupOutputVariable(state, - "Refrigeration Compressor Rack Zone Sensible Heating Rate", - Constant::Units::W, - rack.SensZoneCreditHeatRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Zone Sensible Heating Energy", - Constant::Units::J, - rack.SensZoneCreditHeat, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - rack.Name); - - SetupOutputVariable(state, - "Refrigeration Compressor Rack Return Air Sensible Heating Rate", - Constant::Units::W, - rack.SensHVACCreditHeatRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - rack.Name); - SetupOutputVariable(state, - "Refrigeration Compressor Rack Return Air Sensible Heating Energy", - Constant::Units::J, - rack.SensHVACCreditHeat, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - rack.Name); - - // if Location is Zone, GetRefrigerationInputEither checks that you have at least one load and that either: - // * You have only cases, and they must be all in the same zone - // * Or you must have a Heat Rejection Zone provided - int rackZoneNum = -1; - if (rack.HeatRejectionZoneNum > 0) { - rackZoneNum = rack.HeatRejectionZoneNum; - } else { - rackZoneNum = RefrigCase(rack.CaseNum(1)).ActualZoneNum; - } - SetupZoneInternalGain(state, - rackZoneNum, - rack.Name, - DataHeatBalance::IntGainType::RefrigerationCompressorRack, - &rack.SensZoneCreditHeatRate, - &rack.SensHVACCreditHeatRate); - - } // location zone - } // Serves coils or case/walkin loads + // When CoilFlag is true, GetRefrigerationInput ensures HeatRejectionZoneNum is provided. + // Otherwise, fall back to zone of first case if no explicit rejection zone. + int rackZoneNum = rack.HeatRejectionZoneNum; + if (!rack.CoilFlag && rackZoneNum <= 0) { + rackZoneNum = RefrigCase(rack.CaseNum(1)).ActualZoneNum; + } + SetupZoneInternalGain(state, + rackZoneNum, + rack.Name, + DataHeatBalance::IntGainType::RefrigerationCompressorRack, + &rack.SensZoneCreditHeatRate, + &rack.SensHVACCreditHeatRate); + } // LocationZone if (rack.CondenserType == DataHeatBalance::RefrigCondenserType::Water) { // on HVAC time step no matter what SetupOutputVariable(state, @@ -8745,507 +7717,236 @@ void SetupReportInput(EnergyPlusData &state) auto &System = state.dataRefrigCase->System; for (int refrigSysNum = 1; refrigSysNum <= state.dataRefrigCase->NumRefrigSystems; ++refrigSysNum) { auto &sys = System(refrigSysNum); - if (sys.CoilFlag) { // system serves chillers and is solved on HVAC time step - if (sys.NumStages == 1) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Compressor Electricity Rate", - Constant::Units::W, - sys.TotCompPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Compressor Electricity Energy", - Constant::Units::J, - sys.TotCompElecConsump, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - sys.Name); - } else if (sys.NumStages == 2) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Low Stage Compressor Electricity Rate", - Constant::Units::W, - sys.TotCompPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Low Stage Compressor Electricity Energy", - Constant::Units::J, - sys.TotCompElecConsump, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total High Stage Compressor Electricity Rate", - Constant::Units::W, - sys.TotHiStageCompPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total High Stage Compressor Electricity Energy", - Constant::Units::J, - sys.TotHiStageCompElecConsump, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Low and High Stage Compressor Electricity Energy", - Constant::Units::J, - sys.TotCompElecConsumpTwoStage, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - sys.Name); - } // NumStages - SetupOutputVariable(state, - "Refrigeration Air Chiller System Average Compressor COP", - Constant::Units::W_W, - sys.AverageCompressorCOP, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); + // CoilFlag: system serves chillers on HVAC (System) time step; otherwise cases/walkins on Zone time step + const std::string sysPrefix = sys.CoilFlag ? "Refrigeration Air Chiller System" : "Refrigeration System"; + const auto sysTsType = sys.CoilFlag ? OutputProcessor::TimeStepType::System : OutputProcessor::TimeStepType::Zone; + // A few output variable name suffixes differ between CoilFlag branches + const std::string_view coolingRateSuffix = + sys.CoilFlag ? "Total Air Chiller Heat Transfer Rate" : "Total Cases and Walk Ins Heat Transfer Rate"; + const std::string_view coolingEnergySuffix = + sys.CoilFlag ? "Total Case and Walk In Heat Transfer Energy" : "Total Cases and Walk Ins Heat Transfer Energy"; + const std::string_view suctionTempSuffix = sys.CoilFlag ? "Suction Temperature" : "Suction Pipe Suction Temperature"; + const std::string_view txvTempSuffix = sys.CoilFlag ? "TXV Liquid Temperature" : "Thermostatic Expansion Valve Liquid Temperature"; + + // For 2-stage systems, the primary compressor labels use "Low Stage" instead of just "Total" + const std::string_view compStageLabel = (sys.NumStages == 2) ? "Total Low Stage Compressor" : "Total Compressor"; + + SetupOutputVariable(state, + EnergyPlus::format("{} {} Electricity Rate", sysPrefix, compStageLabel), + Constant::Units::W, + sys.TotCompPower, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Electricity Energy", sysPrefix, compStageLabel), + Constant::Units::J, + sys.TotCompElecConsump, + sysTsType, + OutputProcessor::StoreType::Sum, + sys.Name); + if (sys.NumStages == 2) { SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Air Chiller Heat Transfer Rate", + sysPrefix + " Total High Stage Compressor Electricity Rate", Constant::Units::W, - sys.TotalCoolingLoad, - OutputProcessor::TimeStepType::System, + sys.TotHiStageCompPower, + sysTsType, OutputProcessor::StoreType::Average, sys.Name); SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Case and Walk In Heat Transfer Energy", + sysPrefix + " Total High Stage Compressor Electricity Energy", Constant::Units::J, - sys.TotalCoolingEnergy, - OutputProcessor::TimeStepType::System, + sys.TotHiStageCompElecConsump, + sysTsType, OutputProcessor::StoreType::Sum, sys.Name); SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Transferred Load Heat Transfer Rate", - Constant::Units::W, - sys.TotTransferLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Transferred Load Heat Transfer Energy", + sysPrefix + " Total Low and High Stage Compressor Electricity Energy", Constant::Units::J, - sys.TotTransferEnergy, - OutputProcessor::TimeStepType::System, + sys.TotCompElecConsumpTwoStage, + sysTsType, OutputProcessor::StoreType::Sum, sys.Name); + } // NumStages == 2 + SetupOutputVariable(state, + sysPrefix + " Average Compressor COP", + Constant::Units::W_W, + sys.AverageCompressorCOP, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} {}", sysPrefix, coolingRateSuffix), + Constant::Units::W, + sys.TotalCoolingLoad, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} {}", sysPrefix, coolingEnergySuffix), + Constant::Units::J, + sys.TotalCoolingEnergy, + sysTsType, + OutputProcessor::StoreType::Sum, + sys.Name); + SetupOutputVariable(state, + sysPrefix + " Total Transferred Load Heat Transfer Rate", + Constant::Units::W, + sys.TotTransferLoad, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + sysPrefix + " Total Transferred Load Heat Transfer Energy", + Constant::Units::J, + sys.TotTransferEnergy, + sysTsType, + OutputProcessor::StoreType::Sum, + sys.Name); + SetupOutputVariable(state, + sysPrefix + " Total Suction Pipe Heat Gain Rate", + Constant::Units::W, + sys.PipeHeatLoad, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + sysPrefix + " Total Suction Pipe Heat Gain Energy", + Constant::Units::J, + sys.PipeHeatEnergy, + sysTsType, + OutputProcessor::StoreType::Sum, + sys.Name); + // compStageLabel already computed above for the electricity block + SetupOutputVariable(state, + EnergyPlus::format("{} {} Heat Transfer Rate", sysPrefix, compStageLabel), + Constant::Units::W, + sys.TotCompCapacity, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} {} Heat Transfer Energy", sysPrefix, compStageLabel), + Constant::Units::J, + sys.TotCompCoolingEnergy, + sysTsType, + OutputProcessor::StoreType::Sum, + sys.Name); // indiv compressors go to meter, not system sum + if (sys.NumStages == 2) { SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Suction Pipe Heat Gain Rate", + sysPrefix + " Total High Stage Compressor Heat Transfer Rate", Constant::Units::W, - sys.PipeHeatLoad, - OutputProcessor::TimeStepType::System, + sys.TotHiStageCompCapacity, + sysTsType, OutputProcessor::StoreType::Average, sys.Name); SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Suction Pipe Heat Gain Energy", + sysPrefix + " Total High Stage Compressor Heat Transfer Energy", Constant::Units::J, - sys.PipeHeatEnergy, - OutputProcessor::TimeStepType::System, + sys.TotHiStageCompCoolingEnergy, + sysTsType, OutputProcessor::StoreType::Sum, + sys.Name); // indiv compressors go to meter, not system sum + } // NumStages == 2 + SetupOutputVariable(state, + sysPrefix + " Net Rejected Heat Transfer Rate", + Constant::Units::W, + sys.NetHeatRejectLoad, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + sysPrefix + " Net Rejected Heat Transfer Energy", + Constant::Units::J, + sys.NetHeatRejectEnergy, + sysTsType, + OutputProcessor::StoreType::Sum, + sys.Name); + SetupOutputVariable(state, + sysPrefix + " Estimated Refrigerant Inventory Mass", + Constant::Units::kg, + sys.RefInventory, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + { + const std::string_view massFlowLabel = + (sys.NumStages == 2) ? "Estimated Low Stage Refrigerant Mass Flow Rate" : "Estimated Refrigerant Mass Flow Rate"; + SetupOutputVariable(state, + EnergyPlus::format("{} {}", sysPrefix, massFlowLabel), + Constant::Units::kg_s, + sys.RefMassFlowComps, + sysTsType, + OutputProcessor::StoreType::Average, sys.Name); - if (sys.NumStages == 1) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Compressor Heat Transfer Rate", - Constant::Units::W, - sys.TotCompCapacity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Compressor Heat Transfer Energy", - Constant::Units::J, - sys.TotCompCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - sys.Name); // indiv compressors go to meter, not system sum - } else if (sys.NumStages == 2) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Low Stage Compressor Heat Transfer Rate", - Constant::Units::W, - sys.TotCompCapacity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total Low Stage Compressor Heat Transfer Energy", - Constant::Units::J, - sys.TotCompCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - sys.Name); // indiv compressors go to meter, not system sum - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total High Stage Compressor Heat Transfer Rate", - Constant::Units::W, - sys.TotHiStageCompCapacity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Total High Stage Compressor Heat Transfer Energy", - Constant::Units::J, - sys.TotHiStageCompCoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - sys.Name); // indiv compressors go to meter, not system sum - } // NumStages + } + if (sys.NumStages == 2) { SetupOutputVariable(state, - "Refrigeration Air Chiller System Net Rejected Heat Transfer Rate", - Constant::Units::W, - sys.NetHeatRejectLoad, - OutputProcessor::TimeStepType::System, + sysPrefix + " Estimated High Stage Refrigerant Mass Flow Rate", + Constant::Units::kg_s, + sys.RefMassFlowHiStageComps, + sysTsType, OutputProcessor::StoreType::Average, sys.Name); + } + if (sys.NumStages == 2) { SetupOutputVariable(state, - "Refrigeration Air Chiller System Net Rejected Heat Transfer Energy", - Constant::Units::J, - sys.NetHeatRejectEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, + sysPrefix + " Intercooler Temperature", + Constant::Units::C, + sys.TIntercooler, + sysTsType, + OutputProcessor::StoreType::Average, sys.Name); SetupOutputVariable(state, - "Refrigeration Air Chiller System Estimated Refrigerant Inventory Mass", - Constant::Units::kg, - sys.RefInventory, - OutputProcessor::TimeStepType::System, + sysPrefix + " Intercooler Pressure", + Constant::Units::Pa, + sys.PIntercooler, + sysTsType, OutputProcessor::StoreType::Average, sys.Name); - if (sys.NumStages == 1) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Estimated Refrigerant Mass Flow Rate", - Constant::Units::kg_s, - sys.RefMassFlowComps, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - } else if (sys.NumStages == 2) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Estimated Low Stage Refrigerant Mass Flow Rate", - Constant::Units::kg_s, - sys.RefMassFlowComps, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Estimated High Stage Refrigerant Mass Flow Rate", - Constant::Units::kg_s, - sys.RefMassFlowHiStageComps, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - } // NumStages - if (sys.NumStages == 2) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Intercooler Temperature", - Constant::Units::C, - sys.TIntercooler, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Intercooler Pressure", - Constant::Units::Pa, - sys.PIntercooler, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - } - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condensing Temperature", - Constant::Units::C, - sys.TCondense, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Evaporating Temperature", - Constant::Units::C, - sys.TEvapNeeded, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Suction Temperature", - Constant::Units::C, - sys.TCompIn, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System TXV Liquid Temperature", - Constant::Units::C, - sys.TLiqInActual, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Liquid Suction Subcooler Heat Transfer Rate", - Constant::Units::W, - sys.LSHXTrans, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Liquid Suction Subcooler Heat Transfer Energy", - Constant::Units::J, - sys.LSHXTransEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - sys.Name); - } else { // NOT System(SysNum)%CoilFlag, so serving loads on zone timestep - if (sys.NumStages == 1) { - SetupOutputVariable(state, - "Refrigeration System Total Compressor Electricity Rate", - Constant::Units::W, - sys.TotCompPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total Compressor Electricity Energy", - Constant::Units::J, - sys.TotCompElecConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); - } else if (sys.NumStages == 2) { - SetupOutputVariable(state, - "Refrigeration System Total Low Stage Compressor Electricity Rate", - Constant::Units::W, - sys.TotCompPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total Low Stage Compressor Electricity Energy", - Constant::Units::J, - sys.TotCompElecConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total High Stage Compressor Electricity Rate", - Constant::Units::W, - sys.TotHiStageCompPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total High Stage Compressor Electricity Energy", - Constant::Units::J, - sys.TotHiStageCompElecConsump, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total Low and High Stage Compressor Electricity Energy", - Constant::Units::J, - sys.TotCompElecConsumpTwoStage, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); - } // NumStages - SetupOutputVariable(state, - "Refrigeration System Average Compressor COP", - Constant::Units::W_W, - sys.AverageCompressorCOP, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total Cases and Walk Ins Heat Transfer Rate", - Constant::Units::W, - sys.TotalCoolingLoad, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total Cases and Walk Ins Heat Transfer Energy", - Constant::Units::J, - sys.TotalCoolingEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total Transferred Load Heat Transfer Rate", - Constant::Units::W, - sys.TotTransferLoad, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total Transferred Load Heat Transfer Energy", - Constant::Units::J, - sys.TotTransferEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total Suction Pipe Heat Gain Rate", - Constant::Units::W, - sys.PipeHeatLoad, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total Suction Pipe Heat Gain Energy", - Constant::Units::J, - sys.PipeHeatEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); - if (sys.NumStages == 1) { - SetupOutputVariable(state, - "Refrigeration System Total Compressor Heat Transfer Rate", - Constant::Units::W, - sys.TotCompCapacity, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total Compressor Heat Transfer Energy", - Constant::Units::J, - sys.TotCompCoolingEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); // indiv compressors go to meter, not system sum - } else if (sys.NumStages == 2) { - SetupOutputVariable(state, - "Refrigeration System Total Low Stage Compressor Heat Transfer Rate", - Constant::Units::W, - sys.TotCompCapacity, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total Low Stage Compressor Heat Transfer Energy", - Constant::Units::J, - sys.TotCompCoolingEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); // indiv compressors go to meter, not system sum - SetupOutputVariable(state, - "Refrigeration System Total High Stage Compressor Heat Transfer Rate", - Constant::Units::W, - sys.TotHiStageCompCapacity, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Total High Stage Compressor Heat Transfer Energy", - Constant::Units::J, - sys.TotHiStageCompCoolingEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); // indiv compressors go to meter, not system sum - } // NumStages - SetupOutputVariable(state, - "Refrigeration System Net Rejected Heat Transfer Rate", - Constant::Units::W, - sys.NetHeatRejectLoad, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Net Rejected Heat Transfer Energy", - Constant::Units::J, - sys.NetHeatRejectEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Estimated Refrigerant Inventory Mass", - Constant::Units::kg, - sys.RefInventory, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - if (sys.NumStages == 1) { - SetupOutputVariable(state, - "Refrigeration System Estimated Refrigerant Mass Flow Rate", - Constant::Units::kg_s, - sys.RefMassFlowComps, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - } else if (sys.NumStages == 2) { - SetupOutputVariable(state, - "Refrigeration System Estimated Low Stage Refrigerant Mass Flow Rate", - Constant::Units::kg_s, - sys.RefMassFlowComps, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Estimated High Stage Refrigerant Mass Flow Rate", - Constant::Units::kg_s, - sys.RefMassFlowHiStageComps, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - } // NumStages - if (sys.NumStages == 2) { - SetupOutputVariable(state, - "Refrigeration System Intercooler Temperature", - Constant::Units::C, - sys.TIntercooler, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Intercooler Pressure", - Constant::Units::Pa, - sys.PIntercooler, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - } - SetupOutputVariable(state, - "Refrigeration System Condensing Temperature", - Constant::Units::C, - sys.TCondense, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Evaporating Temperature", - Constant::Units::C, - sys.TEvapNeeded, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Suction Pipe Suction Temperature", - Constant::Units::C, - sys.TCompIn, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Thermostatic Expansion Valve Liquid Temperature", - Constant::Units::C, - sys.TLiqInActual, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Liquid Suction Subcooler Heat Transfer Rate", - Constant::Units::W, - sys.LSHXTrans, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - sys.Name); - SetupOutputVariable(state, - "Refrigeration System Liquid Suction Subcooler Heat Transfer Energy", - Constant::Units::J, - sys.LSHXTransEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - sys.Name); - } // System(coilflag) + } + SetupOutputVariable(state, + sysPrefix + " Condensing Temperature", + Constant::Units::C, + sys.TCondense, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + sysPrefix + " Evaporating Temperature", + Constant::Units::C, + sys.TEvapNeeded, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} {}", sysPrefix, suctionTempSuffix), + Constant::Units::C, + sys.TCompIn, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + EnergyPlus::format("{} {}", sysPrefix, txvTempSuffix), + Constant::Units::C, + sys.TLiqInActual, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + sysPrefix + " Liquid Suction Subcooler Heat Transfer Rate", + Constant::Units::W, + sys.LSHXTrans, + sysTsType, + OutputProcessor::StoreType::Average, + sys.Name); + SetupOutputVariable(state, + sysPrefix + " Liquid Suction Subcooler Heat Transfer Energy", + Constant::Units::J, + sys.LSHXTransEnergy, + sysTsType, + OutputProcessor::StoreType::Sum, + sys.Name); if (sys.SystemRejectHeatToZone) { if (Condenser(sys.CondenserNum(1)).InletAirZoneNum > 0) { @@ -9269,433 +7970,171 @@ void SetupReportInput(EnergyPlusData &state) // Report Compressor ENERGY here, not on system level for meters. for (int compNum = 1; compNum <= state.dataRefrigCase->NumSimulationCompressors; ++compNum) { auto &comp = Compressor(compNum); - // CurrentModuleObject='Refrigeration:Compressor' - if (comp.NumSysAttach == 1) { // only set up reports for compressors that are used once and only once - if (comp.CoilFlag) { // Compressor serving system with chillers on HVAC time step - SetupOutputVariable(state, - "Refrigeration Air Chiller System Compressor Electricity Rate", - Constant::Units::W, - comp.Power, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - comp.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Compressor Electricity Energy", - Constant::Units::J, - comp.ElecConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - comp.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - comp.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Compressor Heat Transfer Rate", - Constant::Units::W, - comp.Capacity, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - comp.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Compressor Heat Transfer Energy", - Constant::Units::J, - comp.CoolingEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - comp.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Compressor Runtime Fraction", - Constant::Units::None, - comp.LoadFactor, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - comp.Name); - } else { // serve cases/walkins on zone time step - SetupOutputVariable(state, - "Refrigeration Compressor Electricity Rate", - Constant::Units::W, - comp.Power, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - comp.Name); - SetupOutputVariable(state, - "Refrigeration Compressor Electricity Energy", - Constant::Units::J, - comp.ElecConsumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - comp.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - comp.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Compressor Heat Transfer Rate", - Constant::Units::W, - comp.Capacity, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - comp.Name); - SetupOutputVariable(state, - "Refrigeration Compressor Heat Transfer Energy", - Constant::Units::J, - comp.CoolingEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - comp.Name); - SetupOutputVariable(state, - "Refrigeration Compressor Runtime Fraction", - Constant::Units::None, - comp.LoadFactor, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - comp.Name); - } // Serve coils on HVAC time step or cases/walkins on Zone time step - } // NumSysAttach + if (comp.NumSysAttach == 1) { + const std::string compPrefix = comp.CoilFlag ? "Refrigeration Air Chiller System Compressor" : "Refrigeration Compressor"; + const auto compTsType = comp.CoilFlag ? OutputProcessor::TimeStepType::System : OutputProcessor::TimeStepType::Zone; + setupCompressorOutputVars(state, comp, compPrefix, compTsType); + } } // CompNum on NumSimulationCompressors // Report Variables for Refrigeration Condensers for (int condNum = 1; condNum <= state.dataRefrigCase->NumRefrigCondensers; ++condNum) { auto &cond = Condenser(condNum); // CurrentModuleObject='Refrigeration:Condenser:*' - if (cond.CoilFlag) { // Condenser serving system with chillers on HVAC time step + // CoilFlag: serves chillers on HVAC (System) time step; otherwise cases/walkins on Zone time step + const std::string condPrefix = cond.CoilFlag ? "Refrigeration Air Chiller System Condenser" : "Refrigeration System Condenser"; + const auto condTsType = cond.CoilFlag ? OutputProcessor::TimeStepType::System : OutputProcessor::TimeStepType::Zone; + + SetupOutputVariable(state, + condPrefix + " Heat Transfer Rate", + Constant::Units::W, + cond.CondLoad, + condTsType, + OutputProcessor::StoreType::Average, + cond.Name); + SetupOutputVariable(state, + condPrefix + " Heat Transfer Energy", + Constant::Units::J, + cond.CondEnergy, + condTsType, + OutputProcessor::StoreType::Sum, + cond.Name); + + if (cond.CondenserType != DataHeatBalance::RefrigCondenserType::Cascade) { SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Heat Transfer Rate", + condPrefix + " Total Recovered Heat Transfer Rate", Constant::Units::W, - cond.CondLoad, - OutputProcessor::TimeStepType::System, + cond.TotalHeatRecoveredLoad, + condTsType, OutputProcessor::StoreType::Average, cond.Name); SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Heat Transfer Energy", + condPrefix + " Total Recovered Heat Transfer Energy", Constant::Units::J, - cond.CondEnergy, - OutputProcessor::TimeStepType::System, + cond.TotalHeatRecoveredEnergy, + condTsType, OutputProcessor::StoreType::Sum, cond.Name); - - if (cond.CondenserType != DataHeatBalance::RefrigCondenserType::Cascade) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Total Recovered Heat Transfer Rate", - Constant::Units::W, - cond.TotalHeatRecoveredLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Total Recovered Heat Transfer Energy", - Constant::Units::J, - cond.TotalHeatRecoveredEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - cond.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Non Refrigeration Recovered Heat Transfer Rate", - Constant::Units::W, - cond.ExternalHeatRecoveredLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Non Refrigeration Recovered Heat Transfer Energy", - Constant::Units::J, - cond.ExternalEnergyRecovered, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - cond.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Defrost Recovered Heat Transfer Rate", - Constant::Units::W, - cond.InternalHeatRecoveredLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Defrost Recovered Heat Transfer Energy", - Constant::Units::J, - cond.InternalEnergyRecovered, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - cond.Name); - } // not cascade because recovered energy on cascade systems passed up to higher temperature system - - if (cond.CondenserType == DataHeatBalance::RefrigCondenserType::Air) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Fan Electricity Rate", - Constant::Units::W, - cond.ActualFanPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Fan Electricity Energy", - Constant::Units::J, - cond.FanElecEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - cond.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - cond.EndUseSubcategory); - } // Air cooled - - if (cond.CondenserType == DataHeatBalance::RefrigCondenserType::Evap) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Fan Electricity Rate", - Constant::Units::W, - cond.ActualFanPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Fan Electricity Energy", - Constant::Units::J, - cond.FanElecEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - cond.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - cond.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Pump Electricity Rate", - Constant::Units::W, - cond.ActualEvapPumpPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Pump Electricity Energy", - Constant::Units::J, - cond.EvapPumpConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - cond.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - cond.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Basin Heater Electricity Rate", - Constant::Units::W, - cond.BasinHeaterPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Basin Heater Electricity Energy", - Constant::Units::J, - cond.BasinHeaterConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - cond.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - cond.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Evaporated Water Volume Flow Rate", - Constant::Units::m3_s, - cond.EvapWaterConsumpRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Evaporated Water Volume", - Constant::Units::m3, - cond.EvapWaterConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - cond.Name, - Constant::eResource::Water, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - cond.EndUseSubcategory); - } // Evaporative Condenser Variables - - if (cond.CondenserType == DataHeatBalance::RefrigCondenserType::Water) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Condenser Fluid Mass Flow Rate", - Constant::Units::kg_s, - cond.MassFlowRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - cond.Name); - - } // Water-cooled Condenser variables - - } else { // Serving loads/systems with cases and walkins on zone time step - SetupOutputVariable(state, - "Refrigeration System Condenser Heat Transfer Rate", + condPrefix + " Non Refrigeration Recovered Heat Transfer Rate", Constant::Units::W, - cond.CondLoad, - OutputProcessor::TimeStepType::Zone, + cond.ExternalHeatRecoveredLoad, + condTsType, OutputProcessor::StoreType::Average, cond.Name); SetupOutputVariable(state, - "Refrigeration System Condenser Heat Transfer Energy", + condPrefix + " Non Refrigeration Recovered Heat Transfer Energy", Constant::Units::J, - cond.CondEnergy, - OutputProcessor::TimeStepType::Zone, + cond.ExternalEnergyRecovered, + condTsType, OutputProcessor::StoreType::Sum, cond.Name); + SetupOutputVariable(state, + condPrefix + " Defrost Recovered Heat Transfer Rate", + Constant::Units::W, + cond.InternalHeatRecoveredLoad, + condTsType, + OutputProcessor::StoreType::Average, + cond.Name); + SetupOutputVariable(state, + condPrefix + " Defrost Recovered Heat Transfer Energy", + Constant::Units::J, + cond.InternalEnergyRecovered, + condTsType, + OutputProcessor::StoreType::Sum, + cond.Name); + } // not cascade because recovered energy on cascade systems passed up to higher temperature system - if (cond.CondenserType != DataHeatBalance::RefrigCondenserType::Cascade) { - SetupOutputVariable(state, - "Refrigeration System Condenser Total Recovered Heat Transfer Rate", - Constant::Units::W, - cond.TotalHeatRecoveredLoad, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration System Condenser Total Recovered Heat Transfer Energy", - Constant::Units::J, - cond.TotalHeatRecoveredEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - cond.Name); - SetupOutputVariable(state, - "Refrigeration System Condenser Non Refrigeration Recovered Heat Transfer Rate", - Constant::Units::W, - cond.ExternalHeatRecoveredLoad, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration System Condenser Non Refrigeration Recovered Heat Transfer Energy", - Constant::Units::J, - cond.ExternalEnergyRecovered, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - cond.Name); - SetupOutputVariable(state, - "Refrigeration System Condenser Defrost Recovered Heat Transfer Rate", - Constant::Units::W, - cond.InternalHeatRecoveredLoad, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration System Condenser Defrost Recovered Heat Transfer Energy", - Constant::Units::J, - cond.InternalEnergyRecovered, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - cond.Name); - } // not cascade because recovered energy on cascade systems passed up to higher temperature system - - if (cond.CondenserType == DataHeatBalance::RefrigCondenserType::Air) { - SetupOutputVariable(state, - "Refrigeration System Condenser Fan Electricity Rate", - Constant::Units::W, - cond.ActualFanPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration System Condenser Fan Electricity Energy", - Constant::Units::J, - cond.FanElecEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - cond.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - cond.EndUseSubcategory); - } // Air cooled - - if (cond.CondenserType == DataHeatBalance::RefrigCondenserType::Evap) { - SetupOutputVariable(state, - "Refrigeration System Condenser Fan Electricity Rate", - Constant::Units::W, - cond.ActualFanPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration System Condenser Fan Electricity Energy", - Constant::Units::J, - cond.FanElecEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - cond.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - cond.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration System Condenser Pump Electricity Rate", - Constant::Units::W, - cond.ActualEvapPumpPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration System Condenser Pump Electricity Energy", - Constant::Units::J, - cond.EvapPumpConsumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - cond.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - cond.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration System Condenser Basin Heater Electricity Rate", - Constant::Units::W, - cond.BasinHeaterPower, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration System Condenser Basin Heater Electricity Energy", - Constant::Units::J, - cond.BasinHeaterConsumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - cond.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - cond.EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration System Condenser Evaporated Water Volume Flow Rate", - Constant::Units::m3_s, - cond.EvapWaterConsumpRate, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - cond.Name); - SetupOutputVariable(state, - "Refrigeration System Condenser Evaporated Water Volume", - Constant::Units::m3, - cond.EvapWaterConsumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - cond.Name, - Constant::eResource::Water, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - cond.EndUseSubcategory); - } // Evaporative Condenser Variables + if (cond.CondenserType == DataHeatBalance::RefrigCondenserType::Air || cond.CondenserType == DataHeatBalance::RefrigCondenserType::Evap) { + // Fan electricity variables are common to both Air and Evap condensers + SetupOutputVariable(state, + condPrefix + " Fan Electricity Rate", + Constant::Units::W, + cond.ActualFanPower, + condTsType, + OutputProcessor::StoreType::Average, + cond.Name); + SetupOutputVariable(state, + condPrefix + " Fan Electricity Energy", + Constant::Units::J, + cond.FanElecEnergy, + condTsType, + OutputProcessor::StoreType::Sum, + cond.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::Plant, + OutputProcessor::EndUseCat::Refrigeration, + cond.EndUseSubcategory); + } // Air or Evap cooled fan variables - if (cond.CondenserType == DataHeatBalance::RefrigCondenserType::Water) { - SetupOutputVariable(state, - "Refrigeration System Condenser Water Mass Flow Rate", - Constant::Units::kg_s, - cond.MassFlowRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - cond.Name); + if (cond.CondenserType == DataHeatBalance::RefrigCondenserType::Evap) { + SetupOutputVariable(state, + condPrefix + " Pump Electricity Rate", + Constant::Units::W, + cond.ActualEvapPumpPower, + condTsType, + OutputProcessor::StoreType::Average, + cond.Name); + SetupOutputVariable(state, + condPrefix + " Pump Electricity Energy", + Constant::Units::J, + cond.EvapPumpConsumption, + condTsType, + OutputProcessor::StoreType::Sum, + cond.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::Plant, + OutputProcessor::EndUseCat::Refrigeration, + cond.EndUseSubcategory); + SetupOutputVariable(state, + condPrefix + " Basin Heater Electricity Rate", + Constant::Units::W, + cond.BasinHeaterPower, + condTsType, + OutputProcessor::StoreType::Average, + cond.Name); + SetupOutputVariable(state, + condPrefix + " Basin Heater Electricity Energy", + Constant::Units::J, + cond.BasinHeaterConsumption, + condTsType, + OutputProcessor::StoreType::Sum, + cond.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::Plant, + OutputProcessor::EndUseCat::Refrigeration, + cond.EndUseSubcategory); + SetupOutputVariable(state, + condPrefix + " Evaporated Water Volume Flow Rate", + Constant::Units::m3_s, + cond.EvapWaterConsumpRate, + condTsType, + OutputProcessor::StoreType::Average, + cond.Name); + SetupOutputVariable(state, + condPrefix + " Evaporated Water Volume", + Constant::Units::m3, + cond.EvapWaterConsumption, + condTsType, + OutputProcessor::StoreType::Sum, + cond.Name, + Constant::eResource::Water, + OutputProcessor::Group::Plant, + OutputProcessor::EndUseCat::Refrigeration, + cond.EndUseSubcategory); + } // Evaporative Condenser Variables - } // Water-cooled Condenser variables - } // Condenser%CoilFlag to distinguish HVAC vs Zone time steps + if (cond.CondenserType == DataHeatBalance::RefrigCondenserType::Water) { + // Water-cooled condensers always report on System time step; variable name differs by CoilFlag + const std::string waterCondVarName = cond.CoilFlag ? (condPrefix + " Fluid Mass Flow Rate") : (condPrefix + " Water Mass Flow Rate"); + SetupOutputVariable(state, + waterCondVarName, + Constant::Units::kg_s, + cond.MassFlowRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + cond.Name); + } // Water-cooled Condenser variables } // CondNum on DataHeatBalance::NumRefrigCondensers if (state.dataRefrigCase->NumSimulationSubcoolers > 0) { @@ -9703,41 +8142,26 @@ void SetupReportInput(EnergyPlusData &state) for (int subcoolNum = 1; subcoolNum <= state.dataRefrigCase->NumSimulationSubcoolers; ++subcoolNum) { auto &cooler = Subcooler(subcoolNum); // CurrentModuleObject='Refrigeration:Subcooler' - if (cooler.CoilFlag) { // Subcooler serving system with chillers on HVAC time step - if (cooler.subcoolerType == SubcoolerType::Mechanical) { - SetupOutputVariable(state, - "Refrigeration Air Chiller System Mechanical Subcooler Heat Transfer Rate", - Constant::Units::W, - cooler.MechSCTransLoad, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - cooler.Name); - SetupOutputVariable(state, - "Refrigeration Air Chiller System Mechanical Subcooler Heat Transfer Energy", - Constant::Units::J, - cooler.MechSCTransEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - cooler.Name); - } - } else { // Subcooler on system serving cases and/or walkins - if (cooler.subcoolerType == SubcoolerType::Mechanical) { - SetupOutputVariable(state, - "Refrigeration System Mechanical Subcooler Heat Transfer Rate", - Constant::Units::W, - cooler.MechSCTransLoad, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - cooler.Name); - SetupOutputVariable(state, - "Refrigeration System Mechanical Subcooler Heat Transfer Energy", - Constant::Units::J, - cooler.MechSCTransEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - cooler.Name); - } - } // Subcoolers on system serving chillers + if (cooler.subcoolerType == SubcoolerType::Mechanical) { + // Note: timestep types here are as in the original code (CoilFlag->Zone, !CoilFlag->System) + const std::string scPrefix = cooler.CoilFlag ? "Refrigeration Air Chiller System" : "Refrigeration System"; + const auto scTsType = cooler.CoilFlag ? OutputProcessor::TimeStepType::Zone : OutputProcessor::TimeStepType::System; + + SetupOutputVariable(state, + scPrefix + " Mechanical Subcooler Heat Transfer Rate", + Constant::Units::W, + cooler.MechSCTransLoad, + scTsType, + OutputProcessor::StoreType::Average, + cooler.Name); + SetupOutputVariable(state, + scPrefix + " Mechanical Subcooler Heat Transfer Energy", + Constant::Units::J, + cooler.MechSCTransEnergy, + scTsType, + OutputProcessor::StoreType::Sum, + cooler.Name); + } } // Subcoolnum on NumSimulationSubcoolers } // NumSimulationSubcoolers > 0 @@ -9969,95 +8393,17 @@ void SetupReportInput(EnergyPlusData &state) // LP compressors for (int compIndex = 1; compIndex <= sys.NumCompressorsLP; ++compIndex) { int compNum = sys.CompressorNumLP(compIndex); - // CurrentModuleObject='Refrigeration:Compressor' - if (Compressor(compNum).NumSysAttach == 1) { // only set up reports for compressors that are used once and only once - SetupOutputVariable(state, - "Refrigeration Compressor Electricity Rate", - Constant::Units::W, - Compressor(compNum).Power, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - Compressor(compNum).Name); - SetupOutputVariable(state, - "Refrigeration Compressor Electricity Energy", - Constant::Units::J, - Compressor(compNum).ElecConsumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - Compressor(compNum).Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - Compressor(compNum).EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Compressor Heat Transfer Rate", - Constant::Units::W, - Compressor(compNum).Capacity, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - Compressor(compNum).Name); - SetupOutputVariable(state, - "Refrigeration Compressor Heat Transfer Energy", - Constant::Units::J, - Compressor(compNum).CoolingEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - Compressor(compNum).Name); - SetupOutputVariable(state, - "Refrigeration Compressor Runtime Fraction", - Constant::Units::None, - Compressor(compNum).LoadFactor, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - Compressor(compNum).Name); - } // NumSysAttach + if (Compressor(compNum).NumSysAttach == 1) { + setupCompressorOutputVars(state, Compressor(compNum), "Refrigeration Compressor", OutputProcessor::TimeStepType::Zone); + } } // sys%NumCompressorsLP // HP compressors for (int compIndex = 1; compIndex <= sys.NumCompressorsHP; ++compIndex) { int compNum = sys.CompressorNumHP(compIndex); - // CurrentModuleObject='Refrigeration:Compressor' - if (Compressor(compNum).NumSysAttach == 1) { // only set up reports for compressors that are used once and only once - SetupOutputVariable(state, - "Refrigeration Compressor Electricity Rate", - Constant::Units::W, - Compressor(compNum).Power, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - Compressor(compNum).Name); - SetupOutputVariable(state, - "Refrigeration Compressor Electricity Energy", - Constant::Units::J, - Compressor(compNum).ElecConsumption, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - Compressor(compNum).Name, - Constant::eResource::Electricity, - OutputProcessor::Group::Plant, - OutputProcessor::EndUseCat::Refrigeration, - Compressor(compNum).EndUseSubcategory); - SetupOutputVariable(state, - "Refrigeration Compressor Heat Transfer Rate", - Constant::Units::W, - Compressor(compNum).Capacity, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - Compressor(compNum).Name); - SetupOutputVariable(state, - "Refrigeration Compressor Heat Transfer Energy", - Constant::Units::J, - Compressor(compNum).CoolingEnergy, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Sum, - Compressor(compNum).Name); - SetupOutputVariable(state, - "Refrigeration Compressor Runtime Fraction", - Constant::Units::None, - Compressor(compNum).LoadFactor, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - Compressor(compNum).Name); - } // NumSysAttach + if (Compressor(compNum).NumSysAttach == 1) { + setupCompressorOutputVars(state, Compressor(compNum), "Refrigeration Compressor", OutputProcessor::TimeStepType::Zone); + } } // sys%NumCompressorsHP } // NumTransRefrigSystems @@ -11477,130 +9823,130 @@ void RefrigCondenserData::onInitLoopEquip(EnergyPlusData &state, [[maybe_unused] InitRefrigerationPlantConnections(state); } -void RefrigCondenserData::simulate(EnergyPlusData &state, - [[maybe_unused]] const PlantLocation &calledFromLocation, - bool const FirstHVACIteration, - [[maybe_unused]] Real64 &CurLoad, - [[maybe_unused]] bool const RunFlag) +// Common water-cooled condenser simulation logic shared by RefrigCondenserData and RefrigRackData. +// Both classes have identical water-side simulation code; only the heat load source and type/error strings differ. +struct WaterCooledCondenserParams { - - // SUBROUTINE INFORMATION: - // AUTHOR Randy Hudson, ORNL - // DATE WRITTEN July 2007 - // MODIFIED Therese Stovall, ORNL May 2008 - // Brent Griffith, NREL Oct 2010, generalize fluid properties - // plant upgrades, moved where called from to SimPlantEquip from ManageNonZoneEquipment - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // Simulates the water-cooled refrigeration condenser object. - // Modified to add condensers for detailed refrigeration systems and to - // avoid double-counting heat rejection that has been used in desuperheater - // hvac coils or water heaters. - - // METHODOLOGY EMPLOYED: - // Called from SimPlantEquip in PlantLoopEquipment , previously was called from Non-Zone Equipment Manager - // Flow is requested and the actual available flow is set. The outlet temperature is calculated. - - static constexpr std::string_view RoutineName("SimRefrigCondenser"); - int PlantInletNode(0); - int PlantOutletNode(0); - PlantLocation PlantLoc{}; - - InitRefrigerationPlantConnections(state); - + std::string Name; std::string TypeName; std::string ErrIntro; + int InletNode; + int OutletNode; + PlantLocation plantLoc; + CndsrFlowType FlowType; + Sched::Schedule *outletTempSched; + Real64 InletTemp; + Real64 DesVolFlowRate; + Real64 MassFlowRateMax; + Real64 OutletTempMax; + // These are modified during simulation: + Real64 &OutletTemp; + Real64 &VolFlowRate; + Real64 &MassFlowRate; + int &HighInletWarnIndex; + int &HighFlowWarnIndex; + int &NoFlowWarnIndex; + int &HighTempWarnIndex; +}; + +static void simulateWaterCooledCondenser(EnergyPlusData &state, WaterCooledCondenserParams &p, bool FirstHVACIteration) +{ + static constexpr std::string_view RoutineName("SimRefrigCondenser"); - // set variables depending upon system type - PlantInletNode = this->InletNode; - PlantOutletNode = this->OutletNode; - PlantLoc = this->plantLoc; - - state.dataRefrigCase->TotalCondenserHeat = this->CondLoad; - TypeName = "Refrigeration:Condenser:WaterCooled"; - ErrIntro = "Condenser for refrigeration system "; - - // Current condenser is water cooled - // Make demand request on first HVAC iteration - - // get cooling fluid properties - Real64 rho = PlantLoc.loop->glycol->getDensity(state, this->InletTemp, RoutineName); - Real64 Cp = PlantLoc.loop->glycol->getSpecificHeat(state, this->InletTemp, RoutineName); - - if (this->FlowType == CndsrFlowType::Variable && state.dataRefrigCase->TotalCondenserHeat > 0.0) { - - this->OutletTemp = this->outletTempSched->getCurrentVal(); + Real64 rho = p.plantLoc.loop->glycol->getDensity(state, p.InletTemp, RoutineName); + Real64 Cp = p.plantLoc.loop->glycol->getSpecificHeat(state, p.InletTemp, RoutineName); - if (this->OutletTemp == this->InletTemp) { + if (p.FlowType == CndsrFlowType::Variable && state.dataRefrigCase->TotalCondenserHeat > 0.0) { + p.OutletTemp = p.outletTempSched->getCurrentVal(); - if (this->HighInletWarnIndex == 0) { + if (p.OutletTemp == p.InletTemp) { + if (p.HighInletWarnIndex == 0) { ShowSevereError(state, EnergyPlus::format("{}, \"{}\" : has inlet water temp equal to desired outlet temp. Excessive flow resulting. ", - ErrIntro, - this->Name)); + p.ErrIntro, + p.Name)); ShowContinueError(state, "cooling water is not cold enough to reach desired outlet temperature"); } - ShowRecurringWarningErrorAtEnd(state, - ErrIntro + ", \"" + this->Name + "\" : has inlet water temp equal to desired outlet temp.... continues. ", - this->HighInletWarnIndex); - this->VolFlowRate = 9999.0; - this->MassFlowRate = this->VolFlowRate * rho; + ShowRecurringWarningErrorAtEnd( + state, p.ErrIntro + ", \"" + p.Name + "\" : has inlet water temp equal to desired outlet temp.... continues. ", p.HighInletWarnIndex); + p.VolFlowRate = 9999.0; + p.MassFlowRate = p.VolFlowRate * rho; } else { - Real64 DeltaT = this->OutletTemp - this->InletTemp; - this->MassFlowRate = state.dataRefrigCase->TotalCondenserHeat / Cp / DeltaT; - // Check for maximum flow in the component - if (this->MassFlowRate > this->MassFlowRateMax) { - if (this->HighFlowWarnIndex == 0) { - ShowWarningMessage(state, EnergyPlus::format("{}{}", TypeName, this->Name)); + Real64 DeltaT = p.OutletTemp - p.InletTemp; + p.MassFlowRate = state.dataRefrigCase->TotalCondenserHeat / Cp / DeltaT; + if (p.MassFlowRate > p.MassFlowRateMax) { + if (p.HighFlowWarnIndex == 0) { + ShowWarningMessage(state, EnergyPlus::format("{}{}", p.TypeName, p.Name)); ShowContinueError(state, "Requested condenser water mass flow rate greater than maximum allowed value. "); ShowContinueError(state, "Flow reset to maximum value."); - } // HighFlowWarnIndex + } ShowRecurringWarningErrorAtEnd( - state, ErrIntro + this->Name + " - Flow rate higher than maximum allowed ... continues", this->HighFlowWarnIndex); - // END IF - this->MassFlowRate = this->MassFlowRateMax; + state, p.ErrIntro + p.Name + " - Flow rate higher than maximum allowed ... continues", p.HighFlowWarnIndex); + p.MassFlowRate = p.MassFlowRateMax; } - } // compare outlet T to inlet T - - } else if (this->FlowType == CndsrFlowType::Constant && state.dataRefrigCase->TotalCondenserHeat > 0.0) { - // this part for constant flow condition - this->VolFlowRate = this->DesVolFlowRate; - this->MassFlowRate = this->VolFlowRate * rho; - + } + } else if (p.FlowType == CndsrFlowType::Constant && state.dataRefrigCase->TotalCondenserHeat > 0.0) { + p.VolFlowRate = p.DesVolFlowRate; + p.MassFlowRate = p.VolFlowRate * rho; } else if (state.dataRefrigCase->TotalCondenserHeat == 0.0) { - this->MassFlowRate = 0.0; - - } // on flow type - // check against plant, might get changed. - PlantUtilities::SetComponentFlowRate(state, this->MassFlowRate, PlantInletNode, PlantOutletNode, PlantLoc); + p.MassFlowRate = 0.0; + } - this->VolFlowRate = this->MassFlowRate / rho; + PlantUtilities::SetComponentFlowRate(state, p.MassFlowRate, p.InletNode, p.OutletNode, p.plantLoc); + p.VolFlowRate = p.MassFlowRate / rho; - if (this->MassFlowRate > 0) { - this->OutletTemp = state.dataRefrigCase->TotalCondenserHeat / (this->MassFlowRate * Cp) + state.dataLoopNodes->Node(PlantInletNode).Temp; + if (p.MassFlowRate > 0) { + p.OutletTemp = state.dataRefrigCase->TotalCondenserHeat / (p.MassFlowRate * Cp) + state.dataLoopNodes->Node(p.InletNode).Temp; } else { - this->OutletTemp = this->InletTemp; + p.OutletTemp = p.InletTemp; if ((state.dataRefrigCase->TotalCondenserHeat > 0.0) && (!FirstHVACIteration)) { - ShowRecurringWarningErrorAtEnd( state, - TypeName + this->Name + - "Water-cooled condenser has no cooling water flow. Heat is not being rejected from compressor rack condenser.", - this->NoFlowWarnIndex); + p.TypeName + p.Name + "Water-cooled condenser has no cooling water flow. Heat is not being rejected from compressor rack condenser.", + p.NoFlowWarnIndex); } } - // Check outlet water temp for max value - if (this->OutletTemp > this->OutletTempMax) { - if (this->HighTempWarnIndex == 0) { - ShowWarningMessage(state, EnergyPlus::format("{}{}", TypeName, this->Name)); + if (p.OutletTemp > p.OutletTempMax) { + if (p.HighTempWarnIndex == 0) { + ShowWarningMessage(state, EnergyPlus::format("{}{}", p.TypeName, p.Name)); ShowContinueError(state, "Water-cooled condenser outlet temp higher than maximum allowed temp. Check flow rates and/or temperature setpoints."); } ShowRecurringWarningErrorAtEnd( - state, ErrIntro + this->Name + " - Condenser outlet temp higher than maximum allowed ... continues", this->HighTempWarnIndex); + state, p.ErrIntro + p.Name + " - Condenser outlet temp higher than maximum allowed ... continues", p.HighTempWarnIndex); } +} + +void RefrigCondenserData::simulate(EnergyPlusData &state, + [[maybe_unused]] const PlantLocation &calledFromLocation, + bool const FirstHVACIteration, + [[maybe_unused]] Real64 &CurLoad, + [[maybe_unused]] bool const RunFlag) +{ + InitRefrigerationPlantConnections(state); + + state.dataRefrigCase->TotalCondenserHeat = this->CondLoad; + WaterCooledCondenserParams params{this->Name, + "Refrigeration:Condenser:WaterCooled", + "Condenser for refrigeration system ", + this->InletNode, + this->OutletNode, + this->plantLoc, + this->FlowType, + this->outletTempSched, + this->InletTemp, + this->DesVolFlowRate, + this->MassFlowRateMax, + this->OutletTempMax, + this->OutletTemp, + this->VolFlowRate, + this->MassFlowRate, + this->HighInletWarnIndex, + this->HighFlowWarnIndex, + this->NoFlowWarnIndex, + this->HighTempWarnIndex}; + simulateWaterCooledCondenser(state, params, FirstHVACIteration); this->UpdateCondenserOutletNode(state); } @@ -11635,124 +9981,31 @@ void RefrigRackData::simulate(EnergyPlusData &state, [[maybe_unused]] Real64 &CurLoad, [[maybe_unused]] bool const RunFlag) { - - // SUBROUTINE INFORMATION: - // AUTHOR Randy Hudson, ORNL - // DATE WRITTEN July 2007 - // MODIFIED Therese Stovall, ORNL May 2008 - // Brent Griffith, NREL Oct 2010, generalize fluid properties - // plant upgrades, moved where called from to SimPlantEquip from ManageNonZoneEquipment - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // Simulates the water-cooled refrigeration condenser object. - // Modified to add condensers for detailed refrigeration systems and to - // avoid double-counting heat rejection that has been used in desuperheater - // hvac coils or water heaters. - - // METHODOLOGY EMPLOYED: - // Called from SimPlantEquip in PlantLoopEquipment , previously was called from Non-Zone Equipment Manager - // Flow is requested and the actual available flow is set. The outlet temperature is calculated. - - static constexpr std::string_view RoutineName("SimRefrigCondenser"); - int PlantInletNode(0); - int PlantOutletNode(0); - PlantLocation PlantLoc{}; - InitRefrigerationPlantConnections(state); - std::string TypeName; - std::string ErrIntro; - - // set variables depending upon system type - PlantInletNode = this->InletNode; - PlantOutletNode = this->OutletNode; - PlantLoc = this->plantLoc; - state.dataRefrigCase->TotalCondenserHeat = state.dataHeatBal->HeatReclaimRefrigeratedRack(this->MyIdx).AvailCapacity - this->LaggedUsedWaterHeater - this->LaggedUsedHVACCoil; - TypeName = "Refrigeration:CompressorRack:"; - ErrIntro = "Condenser for refrigeration rack "; - - // Current condenser is water cooled - // Make demand request on first HVAC iteration - - // get cooling fluid properties - Real64 rho = PlantLoc.loop->glycol->getDensity(state, this->InletTemp, RoutineName); - Real64 Cp = PlantLoc.loop->glycol->getSpecificHeat(state, this->InletTemp, RoutineName); - - if (this->FlowType == CndsrFlowType::Variable && state.dataRefrigCase->TotalCondenserHeat > 0.0) { - this->OutletTemp = this->outletTempSched->getCurrentVal(); - - if (this->OutletTemp == this->InletTemp) { - - if (this->HighInletWarnIndex == 0) { - ShowSevereError(state, - EnergyPlus::format("{}, \"{}\" : has inlet water temp equal to desired outlet temp. Excessive flow resulting. ", - ErrIntro, - this->Name)); - ShowContinueError(state, "cooling water is not cold enough to reach desired outlet temperature"); - } - ShowRecurringWarningErrorAtEnd(state, - ErrIntro + ", \"" + this->Name + "\" : has inlet water temp equal to desired outlet temp.... continues. ", - this->HighInletWarnIndex); - this->VolFlowRate = 9999.0; - this->MassFlowRate = this->VolFlowRate * rho; - } else { - Real64 DeltaT = this->OutletTemp - this->InletTemp; - this->MassFlowRate = state.dataRefrigCase->TotalCondenserHeat / Cp / DeltaT; - // Check for maximum flow in the component - if (this->MassFlowRate > this->MassFlowRateMax) { - if (this->HighFlowWarnIndex == 0) { - ShowWarningMessage(state, EnergyPlus::format("{}{}", TypeName, this->Name)); - ShowContinueError(state, "Requested condenser water mass flow rate greater than maximum allowed value. "); - ShowContinueError(state, "Flow reset to maximum value."); - } // HighFlowWarnIndex - ShowRecurringWarningErrorAtEnd( - state, ErrIntro + this->Name + " - Flow rate higher than maximum allowed ... continues", this->HighFlowWarnIndex); - // END IF - this->MassFlowRate = this->MassFlowRateMax; - } - } // compare outlet T to inlet T - - } else if (this->FlowType == CndsrFlowType::Constant && state.dataRefrigCase->TotalCondenserHeat > 0.0) { - // this part for constant flow condition - this->VolFlowRate = this->DesVolFlowRate; - this->MassFlowRate = this->VolFlowRate * rho; - - } else if (state.dataRefrigCase->TotalCondenserHeat == 0.0) { - this->MassFlowRate = 0.0; - - } // on flow type - // check against plant, might get changed. - PlantUtilities::SetComponentFlowRate(state, this->MassFlowRate, PlantInletNode, PlantOutletNode, PlantLoc); - - this->VolFlowRate = this->MassFlowRate / rho; - - if (this->MassFlowRate > 0) { - this->OutletTemp = state.dataRefrigCase->TotalCondenserHeat / (this->MassFlowRate * Cp) + state.dataLoopNodes->Node(PlantInletNode).Temp; - } else { - this->OutletTemp = this->InletTemp; - if ((state.dataRefrigCase->TotalCondenserHeat > 0.0) && (!FirstHVACIteration)) { - - ShowRecurringWarningErrorAtEnd( - state, - TypeName + this->Name + - "Water-cooled condenser has no cooling water flow. Heat is not being rejected from compressor rack condenser.", - this->NoFlowWarnIndex); - } - } - // Check outlet water temp for max value - if (this->OutletTemp > this->OutletTempMax) { - if (this->HighTempWarnIndex == 0) { - ShowWarningMessage(state, EnergyPlus::format("{}{}", TypeName, this->Name)); - ShowContinueError(state, - "Water-cooled condenser outlet temp higher than maximum allowed temp. Check flow rates and/or temperature setpoints."); - } - ShowRecurringWarningErrorAtEnd( - state, ErrIntro + this->Name + " - Condenser outlet temp higher than maximum allowed ... continues", HighTempWarnIndex); - } + WaterCooledCondenserParams params{this->Name, + "Refrigeration:CompressorRack:", + "Condenser for refrigeration rack ", + this->InletNode, + this->OutletNode, + this->plantLoc, + this->FlowType, + this->outletTempSched, + this->InletTemp, + this->DesVolFlowRate, + this->MassFlowRateMax, + this->OutletTempMax, + this->OutletTemp, + this->VolFlowRate, + this->MassFlowRate, + this->HighInletWarnIndex, + this->HighFlowWarnIndex, + this->NoFlowWarnIndex, + this->HighTempWarnIndex}; + simulateWaterCooledCondenser(state, params, FirstHVACIteration); this->UpdateCondenserOutletNode(state); } @@ -12272,88 +10525,63 @@ void SimulateDetailedTransRefrigSystems(EnergyPlusData &state) // TransCritSysFlag = .TRUE. for (auto &thisSys : TransSystem) { // Only do those systems appropriate for this analysis, supermarket type on load time step - if (thisSys.NumCasesMT > 0) { - for (int CaseIndex = 1; CaseIndex <= thisSys.NumCasesMT; ++CaseIndex) { - int CaseID = thisSys.CaseNumMT(CaseIndex); - RefrigCase(CaseID).CalculateCase(state); - // TEvapDesignMT calc in Get Input to meet lowest evap temp of any MT load on the system. - // TEvapNeededMT is fixed at this design value. - thisSys.TEvapNeededMT = thisSys.TEvapDesignMT; - // increment TotalCoolingLoad for Compressors/gas cooler on each system and defrost gas cooler credits for heat recovery - thisSys.TotalCoolingLoadMT += RefrigCase(CaseID).TotalCoolingLoad; - thisSys.TotalCondDefrostCredit += RefrigCase(CaseID).HotDefrostCondCredit; - } // NumCasesMT - } // Num of MT cases > 0 - - if (thisSys.NumCasesLT > 0) { - for (int CaseIndex = 1; CaseIndex <= thisSys.NumCasesLT; ++CaseIndex) { - int CaseID = thisSys.CaseNumLT(CaseIndex); - RefrigCase(CaseID).CalculateCase(state); - // TEvapDesignLT calc in Get Input to meet lowest evap temp of any LT load on the system. - // TEvapNeededLT is fixed at this design value. - thisSys.TEvapNeededLT = thisSys.TEvapDesignLT; - // increment TotalCoolingLoad for Compressors/gas cooler on each system and defrost gas cooler credits for heat recovery - thisSys.TotalCoolingLoadLT += RefrigCase(CaseID).TotalCoolingLoad; - thisSys.TotalCondDefrostCredit += RefrigCase(CaseID).HotDefrostCondCredit; - } // NumCasesLT - } // Num of LT cases > 0 - - if (thisSys.NumWalkInsMT > 0) { - for (int WalkInIndex = 1; WalkInIndex <= thisSys.NumWalkInsMT; ++WalkInIndex) { - int WalkInID = thisSys.WalkInNumMT(WalkInIndex); - WalkIn(WalkInID).CalculateWalkIn(state); - // TEvapDesignMT calc in Get Input to meet lowest evap temp of any MT load on the system. - // TEvapNeededMT is fixed at this design value. - thisSys.TEvapNeededMT = thisSys.TEvapDesignMT; - // increment TotalCoolingLoad for Compressors/gas cooler on each system - thisSys.TotalCoolingLoadMT += WalkIn(WalkInID).TotalCoolingLoad; - thisSys.TotalCondDefrostCredit += WalkIn(WalkInID).HotDefrostCondCredit; - } // NumWalkInsMT systems - } // thisSys%NumWalkInsMT > 0 - - if (thisSys.NumWalkInsLT > 0) { - for (int WalkInIndex = 1; WalkInIndex <= thisSys.NumWalkInsLT; ++WalkInIndex) { - int WalkInID = thisSys.WalkInNumLT(WalkInIndex); - WalkIn(WalkInID).CalculateWalkIn(state); - // TEvapDesignLT calc in Get Input to meet lowest evap temp of any LT load on the system. - // TEvapNeeded is fixed at this design value. - thisSys.TEvapNeededLT = thisSys.TEvapDesignLT; - // increment TotalCoolingLoad for Compressors/gas cooler on each system - thisSys.TotalCoolingLoadLT += WalkIn(WalkInID).TotalCoolingLoad; - thisSys.TotalCondDefrostCredit += WalkIn(WalkInID).HotDefrostCondCredit; - } // NumWalkInsLT systems - } // thisSys%NumWalkInsLT > 0 + // Calculate cases and walk-ins for both MT and LT temperature levels, accumulating loads + auto accumulateTransCaseLoads = + [&](int numCases, const Array1D_int &caseNums, Real64 &tEvapNeeded, Real64 tEvapDesign, Real64 &totalCoolingLoad) { + for (int CaseIndex = 1; CaseIndex <= numCases; ++CaseIndex) { + int CaseID = caseNums(CaseIndex); + RefrigCase(CaseID).CalculateCase(state); + tEvapNeeded = tEvapDesign; + totalCoolingLoad += RefrigCase(CaseID).TotalCoolingLoad; + thisSys.TotalCondDefrostCredit += RefrigCase(CaseID).HotDefrostCondCredit; + } + }; + auto accumulateTransWalkInLoads = + [&](int numWalkIns, const Array1D_int &walkInNums, Real64 &tEvapNeeded, Real64 tEvapDesign, Real64 &totalCoolingLoad) { + for (int WalkInIndex = 1; WalkInIndex <= numWalkIns; ++WalkInIndex) { + int WalkInID = walkInNums(WalkInIndex); + WalkIn(WalkInID).CalculateWalkIn(state); + tEvapNeeded = tEvapDesign; + totalCoolingLoad += WalkIn(WalkInID).TotalCoolingLoad; + thisSys.TotalCondDefrostCredit += WalkIn(WalkInID).HotDefrostCondCredit; + } + }; + + accumulateTransCaseLoads(thisSys.NumCasesMT, thisSys.CaseNumMT, thisSys.TEvapNeededMT, thisSys.TEvapDesignMT, thisSys.TotalCoolingLoadMT); + accumulateTransCaseLoads(thisSys.NumCasesLT, thisSys.CaseNumLT, thisSys.TEvapNeededLT, thisSys.TEvapDesignLT, thisSys.TotalCoolingLoadLT); + accumulateTransWalkInLoads( + thisSys.NumWalkInsMT, thisSys.WalkInNumMT, thisSys.TEvapNeededMT, thisSys.TEvapDesignMT, thisSys.TotalCoolingLoadMT); + accumulateTransWalkInLoads( + thisSys.NumWalkInsLT, thisSys.WalkInNumLT, thisSys.TEvapNeededLT, thisSys.TEvapDesignLT, thisSys.TotalCoolingLoadLT); // add suction pipe heat gains (W) if input by user // Suction pipe heat gains aren't included in the reported total system load, but are heat gains that must be met in // gas cooler and compressor loads. - thisSys.PipeHeatLoadMT = 0.0; - if (thisSys.SumUASuctionPipingMT > MySmallNumber) { - Real64 SuctionPipeZoneTemp = state.dataLoopNodes->Node(thisSys.SuctionPipeZoneNodeNumMT).Temp; - thisSys.PipeHeatLoadMT = thisSys.SumUASuctionPipingMT * (SuctionPipeZoneTemp - thisSys.TEvapNeededMT); - // pipe heat load is a positive number (ie. heat absorbed by pipe, so needs to be subtracted - // from refrigcasecredit (- for cooling zone, + for heating zone) - int SuctionPipeActualZoneNum = thisSys.SuctionPipeActualZoneNumMT; - // Can arrive here when load call to refrigeration looks for cases/walkin systems and usetimestep is .FALSE. - if ((!state.dataRefrigCase->UseSysTimeStep) && - ((state.dataRefrigCase->NumSimulationCases > 0) || (state.dataRefrigCase->NumSimulationWalkIns > 0))) { - state.dataHeatBal->RefrigCaseCredit(SuctionPipeActualZoneNum).SenCaseCreditToZone -= thisSys.PipeHeatLoadMT; - } // UseSysTimeStep - } - - thisSys.PipeHeatLoadLT = 0.0; - if (thisSys.SumUASuctionPipingLT > MySmallNumber) { - Real64 SuctionPipeZoneTemp = state.dataLoopNodes->Node(thisSys.SuctionPipeZoneNodeNumLT).Temp; - thisSys.PipeHeatLoadLT = thisSys.SumUASuctionPipingLT * (SuctionPipeZoneTemp - thisSys.TEvapNeededLT); - // pipe heat load is a positive number (ie. heat absorbed by pipe, so needs to be subtracted - // from refrigcasecredit (- for cooling zone, + for heating zone) - int SuctionPipeActualZoneNum = thisSys.SuctionPipeActualZoneNumLT; - // Can arrive here when load call to refrigeration looks for cases/walkin systems and usetimestep is .FALSE. - if ((!state.dataRefrigCase->UseSysTimeStep) && - ((state.dataRefrigCase->NumSimulationCases > 0) || (state.dataRefrigCase->NumSimulationWalkIns > 0))) { - state.dataHeatBal->RefrigCaseCredit(SuctionPipeActualZoneNum).SenCaseCreditToZone -= thisSys.PipeHeatLoadLT; - } // UseSysTimeStep - } + // pipe heat load is a positive number (ie. heat absorbed by pipe, so needs to be subtracted + // from refrigcasecredit (- for cooling zone, + for heating zone) + auto calcPipeHeatLoad = + [&](Real64 &pipeHeatLoad, Real64 sumUASuctionPiping, int suctionPipeZoneNodeNum, Real64 tEvapNeeded, int suctionPipeActualZoneNum) { + pipeHeatLoad = 0.0; + if (sumUASuctionPiping > MySmallNumber) { + Real64 SuctionPipeZoneTemp = state.dataLoopNodes->Node(suctionPipeZoneNodeNum).Temp; + pipeHeatLoad = sumUASuctionPiping * (SuctionPipeZoneTemp - tEvapNeeded); + // Can arrive here when load call to refrigeration looks for cases/walkin systems and usetimestep is .FALSE. + if ((!state.dataRefrigCase->UseSysTimeStep) && + ((state.dataRefrigCase->NumSimulationCases > 0) || (state.dataRefrigCase->NumSimulationWalkIns > 0))) { + state.dataHeatBal->RefrigCaseCredit(suctionPipeActualZoneNum).SenCaseCreditToZone -= pipeHeatLoad; + } + } + }; + calcPipeHeatLoad(thisSys.PipeHeatLoadMT, + thisSys.SumUASuctionPipingMT, + thisSys.SuctionPipeZoneNodeNumMT, + thisSys.TEvapNeededMT, + thisSys.SuctionPipeActualZoneNumMT); + calcPipeHeatLoad(thisSys.PipeHeatLoadLT, + thisSys.SumUASuctionPipingLT, + thisSys.SuctionPipeZoneNodeNumLT, + thisSys.TEvapNeededLT, + thisSys.SuctionPipeActualZoneNumLT); } // SysNum @@ -13276,20 +11504,9 @@ void RefrigSystemData::CalculateCompressors(EnergyPlusData &state) this->TotHiStageCompPower = 0.0; } - for (int CompIndex = 1; CompIndex <= this->NumCompressors; ++CompIndex) { - int CompID = this->CompressorNum(CompIndex); - auto &compressor = Compressor(CompID); - compressor.Power = 0.0; - compressor.MassFlow = 0.0; - compressor.Capacity = 0.0; - compressor.ElecConsumption = 0.0; - compressor.CoolingEnergy = 0.0; - compressor.LoadFactor = 0.0; - } - if (this->NumStages == 2) { - for (int CompIndex = 1; CompIndex <= this->NumHiStageCompressors; ++CompIndex) { - int CompID = this->HiStageCompressorNum(CompIndex); - auto &compressor = Compressor(CompID); + auto zeroCompressors = [&Compressor](const Array1D_int &compNums, int numComps) { + for (int CompIndex = 1; CompIndex <= numComps; ++CompIndex) { + auto &compressor = Compressor(compNums(CompIndex)); compressor.Power = 0.0; compressor.MassFlow = 0.0; compressor.Capacity = 0.0; @@ -13297,6 +11514,10 @@ void RefrigSystemData::CalculateCompressors(EnergyPlusData &state) compressor.CoolingEnergy = 0.0; compressor.LoadFactor = 0.0; } + }; + zeroCompressors(this->CompressorNum, this->NumCompressors); + if (this->NumStages == 2) { + zeroCompressors(this->HiStageCompressorNum, this->NumHiStageCompressors); } // Determine properties at case inlet and compressor inlet @@ -13396,52 +11617,33 @@ void RefrigSystemData::CalculateCompressors(EnergyPlusData &state) auto &compressor = Compressor(CompID); // need to use indiv compressor's rated subcool and superheat to adjust capacity to actual conditions + // Determine base enthalpies and temperatures for this stage + // For single-stage or two-stage high-stage: base enthalpy for subcool is HSatLiqCond, reference temp is TCondense + // For two-stage low-stage: base enthalpy is HCaseInRated_base (sat liquid at intercooler), reference temp is TIntercooler + Real64 const HSubcoolBase = (this->NumStages == 2 && StageIndex == 1) ? HCaseInRated_base : this->HSatLiqCond; + Real64 const TSubcoolRef = (this->NumStages == 2 && StageIndex == 1) ? this->TIntercooler : this->TCondense; + // For superheat: single-stage and low-stage use HsatVaporforTevapneeded/TEvapNeeded; high-stage uses HCompInRated_base/TIntercooler + Real64 const HSuperheatBase = (StageIndex == 2) ? HCompInRated_base : HsatVaporforTevapneeded; + Real64 const TSuperheatRef = (StageIndex == 2) ? this->TIntercooler : this->TEvapNeeded; + switch (compressor.SubcoolRatingType) { case CompRatingType::Subcooling: { - if (this->NumStages == 1) { // Single-stage system - HCaseInRated = this->HSatLiqCond - this->CpSatLiqCond * compressor.RatedSubcool; - } else if (this->NumStages == 2 && StageIndex == 1) { // Two-stage system, low-stage side - HCaseInRated = HCaseInRated_base - this->CpSatLiqCond * compressor.RatedSubcool; - } else if (this->NumStages == 2 && StageIndex == 2) { // Two-stage system, high-stage side - HCaseInRated = this->HSatLiqCond - this->CpSatLiqCond * compressor.RatedSubcool; - } // NumStages + HCaseInRated = HSubcoolBase - this->CpSatLiqCond * compressor.RatedSubcool; } break; case CompRatingType::LiquidTemperature: { // have rated liquid temperature stored in "RatedSubcool" - if (this->NumStages == 1) { // Single-stage system - HCaseInRated = this->HSatLiqCond - this->CpSatLiqCond * (this->TCondense - compressor.RatedSubcool); - } else if (this->NumStages == 2 && StageIndex == 1) { // Two-stage system, low-stage side - HCaseInRated = HCaseInRated_base - this->CpSatLiqCond * (this->TIntercooler - compressor.RatedSubcool); - } else if (this->NumStages == 2 && StageIndex == 2) { // Two-stage system, high-stage side - HCaseInRated = this->HSatLiqCond - this->CpSatLiqCond * (this->TCondense - compressor.RatedSubcool); - } // NumStages + HCaseInRated = HSubcoolBase - this->CpSatLiqCond * (TSubcoolRef - compressor.RatedSubcool); } break; default: break; } // Compressor SubcoolRatingType switch (compressor.SuperheatRatingType) { case CompRatingType::Superheat: { - if (this->NumStages == 1) { // Single-stage system - HCompInRated = HsatVaporforTevapneeded + this->CpSatVapEvap * compressor.RatedSuperheat; - TempInRated = this->TEvapNeeded + compressor.RatedSuperheat; - } else if (this->NumStages == 2 && StageIndex == 1) { // Two-stage system, low-stage side - HCompInRated = HsatVaporforTevapneeded + this->CpSatVapEvap * compressor.RatedSuperheat; - TempInRated = this->TEvapNeeded + compressor.RatedSuperheat; - } else if (this->NumStages == 2 && StageIndex == 2) { // Two-stage system, high-stage side - HCompInRated = HCompInRated_base + this->CpSatVapEvap * compressor.RatedSuperheat; - TempInRated = this->TIntercooler + compressor.RatedSuperheat; - } // NumStages + HCompInRated = HSuperheatBase + this->CpSatVapEvap * compressor.RatedSuperheat; + TempInRated = TSuperheatRef + compressor.RatedSuperheat; } break; case CompRatingType::ReturnGasTemperature: { // have rated compressor inlet temperature stored in "RatedSuperheat" - if (this->NumStages == 1) { // Single-stage system - TempInRated = compressor.RatedSuperheat; - HCompInRated = HsatVaporforTevapneeded + this->CpSatVapEvap * (TempInRated - this->TEvapNeeded); - } else if (this->NumStages == 2 && StageIndex == 1) { // Two-stage system, low-stage side - TempInRated = compressor.RatedSuperheat; - HCompInRated = HsatVaporforTevapneeded + this->CpSatVapEvap * (TempInRated - this->TEvapNeeded); - } else if (this->NumStages == 2 && StageIndex == 2) { // Two-stage system, high-stage side - TempInRated = compressor.RatedSuperheat; - HCompInRated = HsatVaporforTevapneeded + this->CpSatVapEvap * (TempInRated - this->TIntercooler); - } // NumStages + TempInRated = compressor.RatedSuperheat; + HCompInRated = HSuperheatBase + this->CpSatVapEvap * (TempInRated - TSuperheatRef); } break; default: break; @@ -13459,44 +11661,29 @@ void RefrigSystemData::CalculateCompressors(EnergyPlusData &state) // calculate load factor for last compressor added // assumes either cycling or part load eff = full load eff for last compressor - if (StageIndex == 1) { // Single-stage or low-stage compressors - if ((this->TotCompCapacity + compressor.Capacity) >= NeededCapacity) { - LFLastComp = (NeededCapacity - this->TotCompCapacity) / compressor.Capacity; - compressor.Power *= LFLastComp; - compressor.MassFlow *= LFLastComp; - compressor.Capacity *= LFLastComp; - this->TotCompCapacity += compressor.Capacity; - this->RefMassFlowComps += compressor.MassFlow; - this->TotCompPower += compressor.Power; - compressor.ElecConsumption = compressor.Power * localTimeStepSec; - compressor.CoolingEnergy = compressor.Capacity * localTimeStepSec; - compressor.LoadFactor = LFLastComp; - break; // numcomps do - } //>= needed capacity - this->TotCompCapacity += compressor.Capacity; - this->RefMassFlowComps += compressor.MassFlow; - this->TotCompPower += compressor.Power; - //>= needed capacity - } else { // high-stage compressors (for two-stage systems only) - if ((this->TotHiStageCompCapacity + compressor.Capacity) >= NeededCapacity) { - LFLastComp = (NeededCapacity - this->TotHiStageCompCapacity) / compressor.Capacity; - compressor.Power *= LFLastComp; - compressor.MassFlow *= LFLastComp; - compressor.Capacity *= LFLastComp; - this->TotHiStageCompCapacity += compressor.Capacity; - this->RefMassFlowHiStageComps += compressor.MassFlow; - this->TotHiStageCompPower += compressor.Power; + Real64 &totCapacity = (StageIndex == 1) ? this->TotCompCapacity : this->TotHiStageCompCapacity; + Real64 &refMassFlow = (StageIndex == 1) ? this->RefMassFlowComps : this->RefMassFlowHiStageComps; + Real64 &totPower = (StageIndex == 1) ? this->TotCompPower : this->TotHiStageCompPower; + + if ((totCapacity + compressor.Capacity) >= NeededCapacity) { + LFLastComp = (NeededCapacity - totCapacity) / compressor.Capacity; + compressor.Power *= LFLastComp; + compressor.MassFlow *= LFLastComp; + compressor.Capacity *= LFLastComp; + totCapacity += compressor.Capacity; + refMassFlow += compressor.MassFlow; + totPower += compressor.Power; + if (StageIndex == 2) { this->FlowRatioIntercooler = this->RefMassFlowComps / this->RefMassFlowHiStageComps; - compressor.ElecConsumption = compressor.Power * localTimeStepSec; - compressor.CoolingEnergy = compressor.Capacity * localTimeStepSec; - compressor.LoadFactor = LFLastComp; - break; // numcomps do - } //>= needed capacity - this->TotHiStageCompCapacity += compressor.Capacity; - this->RefMassFlowHiStageComps += compressor.MassFlow; - this->TotHiStageCompPower += compressor.Power; - //>= needed capacity - } // StageIndex + } + compressor.ElecConsumption = compressor.Power * localTimeStepSec; + compressor.CoolingEnergy = compressor.Capacity * localTimeStepSec; + compressor.LoadFactor = LFLastComp; + break; // numcomps do + } //>= needed capacity + totCapacity += compressor.Capacity; + refMassFlow += compressor.MassFlow; + totPower += compressor.Power; compressor.ElecConsumption = compressor.Power * localTimeStepSec; compressor.CoolingEnergy = compressor.Capacity * localTimeStepSec; compressor.LoadFactor = 1.0; @@ -13619,7 +11806,6 @@ void TransRefrigSystemData::CalculateTransCompressors(EnergyPlusData &state) Real64 TotalRefMassFlow; // Total mass flow through high pressure side of system, kg/s Real64 Xu; // Initial upper guess for iterative search Real64 Xl; // Initial lower guess for iterative search - Real64 Xnew(0.0); // New guess for iterative search auto &Compressor = state.dataRefrigCase->Compressor; auto &GasCooler = state.dataRefrigCase->GasCooler; @@ -13646,6 +11832,18 @@ void TransRefrigSystemData::CalculateTransCompressors(EnergyPlusData &state) // Enthalpy at the receiver bypass, J/kg Real64 HReceiverBypass = this->refrig->getSatEnthalpy(state, this->TReceiver, 1.0, RoutineName); + auto zeroCompressors = [&Compressor](const Array1D_int &compNums, int numComps) { + for (int CompIndex = 1; CompIndex <= numComps; ++CompIndex) { + auto &comp = Compressor(compNums(CompIndex)); + comp.Power = 0.0; + comp.MassFlow = 0.0; + comp.Capacity = 0.0; + comp.ElecConsumption = 0.0; + comp.CoolingEnergy = 0.0; + comp.LoadFactor = 0.0; + } + }; + // Determine refrigerant properties at low temperature (LT) loads (if present) // Dispatch low pressure (LP) compressors as necessary if (this->transSysType == TransSysType::TwoStage) { // LT side of TwoStage transcritical system @@ -13666,16 +11864,7 @@ void TransRefrigSystemData::CalculateTransCompressors(EnergyPlusData &state) this->TotCompCapacityLP = 0.0; this->RefMassFlowCompsLP = 0.0; this->TotCompPowerLP = 0.0; - - for (int CompIndex = 1; CompIndex <= this->NumCompressorsLP; ++CompIndex) { - int CompID = this->CompressorNumLP(CompIndex); - Compressor(CompID).Power = 0.0; - Compressor(CompID).MassFlow = 0.0; - Compressor(CompID).Capacity = 0.0; - Compressor(CompID).ElecConsumption = 0.0; - Compressor(CompID).CoolingEnergy = 0.0; - Compressor(CompID).LoadFactor = 0.0; - } + zeroCompressors(this->CompressorNumLP, this->NumCompressorsLP); for (int CompIndex = 1; CompIndex <= this->NumCompressorsLP; ++CompIndex) { int CompID = this->CompressorNumLP(CompIndex); @@ -13788,22 +11977,28 @@ void TransRefrigSystemData::CalculateTransCompressors(EnergyPlusData &state) this->HCompInHP = (HCaseOutLTMT * (this->RefMassFlowtoLTLoads + this->RefMassFlowtoMTLoads) + HReceiverBypass * this->RefMassFlowReceiverBypass) / (this->RefMassFlowtoLTLoads + this->RefMassFlowtoMTLoads + this->RefMassFlowReceiverBypass); - // Iterate to find the suction temperature entering subcooler - Xl = this->refrig->getSatTemperature(state, PSuctionMT, RoutineName); - Xu = Xl + 50.0; - for (Iter = 1; Iter <= 15; ++Iter) { // Maximum of 15 iterations - Xnew = (Xu + Xl) / 2.0; - Real64 Hnew = this->refrig->getSupHeatEnthalpy(state, Xnew, PSuctionMT, RoutineName); - if (Hnew > this->HCompInHP) { // xnew is too high - Xu = Xnew; - } else { // xnew is too low - Xl = Xnew; - } - if (std::abs((Hnew - this->HCompInHP) / Hnew) < ErrorTol) { - break; + // Bisection search to find temperature from enthalpy at a given suction pressure + auto findTempFromEnthalpy = [&](Real64 targetH) -> Real64 { + Real64 lo = this->refrig->getSatTemperature(state, PSuctionMT, RoutineName); + Real64 hi = lo + 50.0; + Real64 result = lo; + for (int iter = 1; iter <= 15; ++iter) { + result = (hi + lo) / 2.0; + Real64 Hnew = this->refrig->getSupHeatEnthalpy(state, result, PSuctionMT, RoutineName); + if (Hnew > targetH) { + hi = result; + } else { + lo = result; + } + if (std::abs((Hnew - targetH) / Hnew) < ErrorTol) { + break; + } } - } - TSubcoolerColdIn = Xnew; + return result; + }; + + // Iterate to find the suction temperature entering subcooler + TSubcoolerColdIn = findTempFromEnthalpy(this->HCompInHP); // Modify receiver inlet enthalpy and HP compressor inlet enthalpy to account for subcooler HIdeal = this->refrig->getSupHeatEnthalpy(state, GasCooler(this->GasCoolerNum(1)).TGasCoolerOut, PSuctionMT, RoutineName); @@ -13818,21 +12013,7 @@ void TransRefrigSystemData::CalculateTransCompressors(EnergyPlusData &state) this->DelHSubcoolerDis = -this->DelHSubcoolerSuc; // Iterate to find the temperature at the inlet of the high pressure (HP) compressors - Xl = this->refrig->getSatTemperature(state, PSuctionMT, RoutineName); - Xu = Xl + 50.0; - for (Iter = 1; Iter <= 15; ++Iter) { // Maximum of 15 iterations - Xnew = (Xu + Xl) / 2.0; - Real64 Hnew = this->refrig->getSupHeatEnthalpy(state, Xnew, PSuctionMT, RoutineName); - if (Hnew > this->HCompInHP) { // xnew is too high - Xu = Xnew; - } else { // xnew is too low - Xl = Xnew; - } - if (std::abs((Hnew - this->HCompInHP) / Hnew) < ErrorTol) { - break; - } - } - this->TCompInHP = Xnew; + this->TCompInHP = findTempFromEnthalpy(this->HCompInHP); // For capacity correction of HP compressors, consider subcooler, receiver, MT loads, LT loads and LP compressors // to constitute the "load". The actual and rated conditions at the exit of the gas cooler and the inlet of the @@ -13845,17 +12026,7 @@ void TransRefrigSystemData::CalculateTransCompressors(EnergyPlusData &state) this->TotCompCapacityHP = 0.0; this->RefMassFlowCompsHP = 0.0; this->TotCompPowerHP = 0.0; - - for (int CompIndex = 1; CompIndex <= this->NumCompressorsHP; ++CompIndex) { - int CompID = this->CompressorNumHP(CompIndex); - auto &compressor = Compressor(CompID); - compressor.Power = 0.0; - compressor.MassFlow = 0.0; - compressor.Capacity = 0.0; - compressor.ElecConsumption = 0.0; - compressor.CoolingEnergy = 0.0; - compressor.LoadFactor = 0.0; - } + zeroCompressors(this->CompressorNumHP, this->NumCompressorsHP); // Dispatch High Pressure compressors to meet load, note they were listed in compressor list in dispatch order for (int CompIndex = 1; CompIndex <= this->NumCompressorsHP; ++CompIndex) { @@ -13976,25 +12147,31 @@ void RefrigSystemData::CalculateSubcoolers(EnergyPlusData &state) // HCaseIn has to be recalculated as the starting point for the subcoolers here because // of the multiple number of iterations through this subroutine and because Tcondense is evolving. + // HSatLiqCond and CpSatLiqCond are always based on TCondense regardless of stage/intercooler configuration + this->HSatLiqCond = this->refrig->getSatEnthalpy(state, this->TCondense, 0.0, RoutineName); + this->CpSatLiqCond = this->refrig->getSatSpecificHeat(state, this->TCondense, 0.0, RoutineName); + + // Compute the actual liquid inlet temperature based on stage/intercooler configuration + // This helper is used both for HCaseIn initialization and inside the subcooler loop + auto calcTLiqInActual = [&]() -> Real64 { + if (this->NumStages == 1) { // Single-stage compression system + return this->TCondense - Condenser(this->CondenserNum(1)).RatedSubcool; + } else if (this->intercoolerType == IntercoolerType::Flash) { // Two-stage with flash intercooler + return this->TIntercooler; + } else { // Two-stage with shell-and-coil intercooler + return this->TCondense - Condenser(this->CondenserNum(1)).RatedSubcool - + this->IntercoolerEffectiveness * (this->TCondense - Condenser(this->CondenserNum(1)).RatedSubcool - this->TIntercooler); + } + }; + if (this->NumStages == 1) { // Single-stage compression system - this->HSatLiqCond = this->refrig->getSatEnthalpy(state, this->TCondense, 0.0, RoutineName); - this->CpSatLiqCond = this->refrig->getSatSpecificHeat(state, this->TCondense, 0.0, RoutineName); this->HCaseIn = this->HSatLiqCond - this->CpSatLiqCond * Condenser(this->CondenserNum(1)).RatedSubcool; - - // Two-stage compression with flash intercooler - } else if (this->NumStages == 2 && this->intercoolerType == IntercoolerType::Flash) { - this->HSatLiqCond = this->refrig->getSatEnthalpy(state, this->TCondense, 0.0, RoutineName); - this->CpSatLiqCond = this->refrig->getSatSpecificHeat(state, this->TCondense, 0.0, RoutineName); + } else if (this->intercoolerType == IntercoolerType::Flash) { // Two-stage with flash intercooler this->HCaseIn = this->refrig->getSatEnthalpy(state, this->TIntercooler, 0.0, RoutineName); - - // Two-stage compression with shell-and-coil intercooler - } else if (this->NumStages == 2 && this->intercoolerType == IntercoolerType::ShellAndCoil) { - TLiqInActualLocal = this->TCondense - Condenser(this->CondenserNum(1)).RatedSubcool - - this->IntercoolerEffectiveness * (this->TCondense - Condenser(this->CondenserNum(1)).RatedSubcool - this->TIntercooler); - this->HSatLiqCond = this->refrig->getSatEnthalpy(state, this->TCondense, 0.0, RoutineName); - this->CpSatLiqCond = this->refrig->getSatSpecificHeat(state, this->TCondense, 0.0, RoutineName); + } else { // Two-stage with shell-and-coil intercooler + TLiqInActualLocal = calcTLiqInActual(); this->HCaseIn = this->HSatLiqCond - this->CpSatLiqCond * (this->TCondense - TLiqInActualLocal); - } // NumStages and IntercoolerType + } for (int SubcoolerIndex = 1; SubcoolerIndex <= this->NumSubcoolers; ++SubcoolerIndex) { int SubcoolerID = this->SubcoolerNum(SubcoolerIndex); @@ -14006,19 +12183,7 @@ void RefrigSystemData::CalculateSubcoolers(EnergyPlusData &state) Real64 ControlTLiqOut = cooler.MechControlTliqOut; Real64 CpLiquid = this->CpSatLiqCond; Real64 CpVapor = this->CpSatVapEvap; - if (this->NumStages == 1) { // Single-stage compression system - TLiqInActualLocal = this->TCondense - Condenser(this->CondenserNum(1)).RatedSubcool; - - // Two-stage compression with flash intercooler - } else if (this->NumStages == 2 && this->intercoolerType == IntercoolerType::Flash) { - TLiqInActualLocal = this->TIntercooler; - - // Two-stage compression with shell-and-coil intercooler - } else if (this->NumStages == 2 && this->intercoolerType == IntercoolerType::ShellAndCoil) { - TLiqInActualLocal = - this->TCondense - Condenser(this->CondenserNum(1)).RatedSubcool - - this->IntercoolerEffectiveness * (this->TCondense - Condenser(this->CondenserNum(1)).RatedSubcool - this->TIntercooler); - } // NumStages and IntercoolerType + TLiqInActualLocal = calcTLiqInActual(); switch (cooler.subcoolerType) { // Mechanical subcoolers required to come first in order to take advantage of delT @@ -14223,6 +12388,29 @@ void ReportRefrigerationComponents(EnergyPlusData &state) } //(NumSimulationGasCooler > 0) } //(NumTransRefrigSystems > 0) + // Helper to print refrigeration case details - used by racks, detailed systems, trans systems, and secondary loops + auto printCaseReport = [&](std::string_view label, int CaseID) { + auto const &c = RefrigCase(CaseID); + if (c.ZoneNodeNum > 0) { + print(state.files.eio, + " {},{},{},{},{},{},{:.1R},{:.2R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R}\n", + label, + CaseID, + c.Name, + c.ZoneName, + c.ZoneNodeNum, + state.dataLoopNodes->NodeID(c.ZoneNodeNum), + c.RateTotCapPerLength, + c.RatedLHR, + c.Temperature, + c.Length, + c.OperatingFanPower, + c.LightingPower, + c.AntiSweatPower, + c.DefrostPower); + } + }; + if (state.dataRefrigCase->NumRefrigeratedRacks > 0) { print(state.files.eio, "#Refrigeration Compressor Racks, {}\n", state.dataRefrigCase->NumRefrigeratedRacks); std::string ChrOut2; @@ -14255,24 +12443,7 @@ void ReportRefrigerationComponents(EnergyPlusData &state) ChrOut2, RefrigRack(RackNum).RatedCOP); for (int CaseNum = 1; CaseNum <= RefrigRack(RackNum).NumCases; ++CaseNum) { - int CaseID = RefrigRack(RackNum).CaseNum(CaseNum); - if (RefrigCase(CaseID).ZoneNodeNum > 0) { - print(state.files.eio, - " Refrigeration Case,{},{},{},{},{},{:.1R},{:.2R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R}\n", - CaseID, - RefrigCase(CaseID).Name, - RefrigCase(CaseID).ZoneName, - RefrigCase(CaseID).ZoneNodeNum, - state.dataLoopNodes->NodeID(RefrigCase(CaseID).ZoneNodeNum), - RefrigCase(CaseID).RateTotCapPerLength, - RefrigCase(CaseID).RatedLHR, - RefrigCase(CaseID).Temperature, - RefrigCase(CaseID).Length, - RefrigCase(CaseID).OperatingFanPower, - RefrigCase(CaseID).LightingPower, - RefrigCase(CaseID).AntiSweatPower, - RefrigCase(CaseID).DefrostPower); // Installed lighting power, may not be rated power - } + printCaseReport("Refrigeration Case", RefrigRack(RackNum).CaseNum(CaseNum)); } // numcases for (int WalkInNum = 1; WalkInNum <= RefrigRack(RackNum).NumWalkIns; ++WalkInNum) { @@ -14336,24 +12507,7 @@ void ReportRefrigerationComponents(EnergyPlusData &state) System(SystemNum).TCondenseMin); for (int CaseNum = 1; CaseNum <= System(SystemNum).NumCases; ++CaseNum) { - int CaseID = System(SystemNum).CaseNum(CaseNum); - if (RefrigCase(CaseID).ZoneNodeNum > 0) { - print(state.files.eio, - " Refrigeration Case,{},{},{},{},{},{:.1R},{:.2R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R}\n", - CaseID, - RefrigCase(CaseID).Name, - RefrigCase(CaseID).ZoneName, - RefrigCase(CaseID).ZoneNodeNum, - state.dataLoopNodes->NodeID(RefrigCase(CaseID).ZoneNodeNum), - RefrigCase(CaseID).RateTotCapPerLength, - RefrigCase(CaseID).RatedLHR, - RefrigCase(CaseID).Temperature, - RefrigCase(CaseID).Length, - RefrigCase(CaseID).OperatingFanPower, - RefrigCase(CaseID).LightingPower, - RefrigCase(CaseID).AntiSweatPower, - RefrigCase(CaseID).DefrostPower); - } + printCaseReport("Refrigeration Case", System(SystemNum).CaseNum(CaseNum)); } // NumCases on system for (int WalkInNum = 1; WalkInNum <= System(SystemNum).NumWalkIns; ++WalkInNum) { int WalkInID = System(SystemNum).WalkInNum(WalkInNum); @@ -14536,44 +12690,10 @@ void ReportRefrigerationComponents(EnergyPlusData &state) GasCooler(TransSystem(TransSystemNum).GasCoolerNum(1)).MinCondTemp); for (int CaseNum = 1; CaseNum <= TransSystem(TransSystemNum).NumCasesMT; ++CaseNum) { - int CaseID = TransSystem(TransSystemNum).CaseNumMT(CaseNum); - if (RefrigCase(CaseID).ZoneNodeNum > 0) { - print(state.files.eio, - " Medium Temperature Refrigeration Case,{},{},{},{},{},{:.1R},{:.2R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R}\n", - CaseID, - RefrigCase(CaseID).Name, - RefrigCase(CaseID).ZoneName, - RefrigCase(CaseID).ZoneNodeNum, - state.dataLoopNodes->NodeID(RefrigCase(CaseID).ZoneNodeNum), - RefrigCase(CaseID).RateTotCapPerLength, - RefrigCase(CaseID).RatedLHR, - RefrigCase(CaseID).Temperature, - RefrigCase(CaseID).Length, - RefrigCase(CaseID).OperatingFanPower, - RefrigCase(CaseID).LightingPower, - RefrigCase(CaseID).AntiSweatPower, - RefrigCase(CaseID).DefrostPower); - } + printCaseReport("Medium Temperature Refrigeration Case", TransSystem(TransSystemNum).CaseNumMT(CaseNum)); } // NumCasesMT on system for (int CaseNum = 1; CaseNum <= TransSystem(TransSystemNum).NumCasesLT; ++CaseNum) { - int CaseID = TransSystem(TransSystemNum).CaseNumLT(CaseNum); - if (RefrigCase(CaseID).ZoneNodeNum > 0) { - print(state.files.eio, - " Low Temperature Refrigeration Case,{},{},{},{},{},{:.1R},{:.2R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R}\n", - CaseID, - RefrigCase(CaseID).Name, - RefrigCase(CaseID).ZoneName, - RefrigCase(CaseID).ZoneNodeNum, - state.dataLoopNodes->NodeID(RefrigCase(CaseID).ZoneNodeNum), - RefrigCase(CaseID).RateTotCapPerLength, - RefrigCase(CaseID).RatedLHR, - RefrigCase(CaseID).Temperature, - RefrigCase(CaseID).Length, - RefrigCase(CaseID).OperatingFanPower, - RefrigCase(CaseID).LightingPower, - RefrigCase(CaseID).AntiSweatPower, - RefrigCase(CaseID).DefrostPower); - } + printCaseReport("Low Temperature Refrigeration Case", TransSystem(TransSystemNum).CaseNumLT(CaseNum)); } // NumCasesLT on system for (int WalkInNum = 1; WalkInNum <= TransSystem(TransSystemNum).NumWalkInsMT; ++WalkInNum) { int WalkInID = TransSystem(TransSystemNum).WalkInNumMT(WalkInNum); @@ -14701,24 +12821,7 @@ void ReportRefrigerationComponents(EnergyPlusData &state) break; } for (int CaseNum = 1; CaseNum <= Secondary(SecondaryID).NumCases; ++CaseNum) { - int CaseID = Secondary(SecondaryID).CaseNum(CaseNum); - if (RefrigCase(CaseID).ZoneNodeNum > 0) { - print(state.files.eio, - " Refrigeration Case,{},{},{},{},{},{:.1R},{:.2R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R},{:.1R}\n", - CaseID, - RefrigCase(CaseID).Name, - RefrigCase(CaseID).ZoneName, - RefrigCase(CaseID).ZoneNodeNum, - state.dataLoopNodes->NodeID(RefrigCase(CaseID).ZoneNodeNum), - RefrigCase(CaseID).RateTotCapPerLength, - RefrigCase(CaseID).RatedLHR, - RefrigCase(CaseID).Temperature, - RefrigCase(CaseID).Length, - RefrigCase(CaseID).OperatingFanPower, - RefrigCase(CaseID).LightingPower, - RefrigCase(CaseID).AntiSweatPower, - RefrigCase(CaseID).DefrostPower); - } + printCaseReport("Refrigeration Case", Secondary(SecondaryID).CaseNum(CaseNum)); } // NumCases on secondary on secondary system for (int WalkInNum = 1; WalkInNum <= Secondary(SecondaryID).NumWalkIns; ++WalkInNum) { diff --git a/src/EnergyPlus/RefrigeratedCase.hh b/src/EnergyPlus/RefrigeratedCase.hh index d2911a0c80b..9f0f7fddd40 100644 --- a/src/EnergyPlus/RefrigeratedCase.hh +++ b/src/EnergyPlus/RefrigeratedCase.hh @@ -1275,6 +1275,75 @@ namespace RefrigeratedCase { bool ShowUnmetWIEnergyWarning = true; bool ShowWIFrostWarning = true; + // Allocate all per-zone arrays to size n if not already allocated. + // Called during input processing once NumZones is known. + void allocateZoneArrays(int n) + { + if (!allocated(ZoneName)) { + ZoneName.allocate(n); + } + if (!allocated(ZoneNum)) { + ZoneNum.allocate(n) = 0; + } + if (!allocated(ZoneNodeNum)) { + ZoneNodeNum.allocate(n) = 0; + } + if (!allocated(SurfaceArea)) { + SurfaceArea.allocate(n) = 0.0; + } + if (!allocated(UValue)) { + UValue.allocate(n) = 0.0; + } + if (!allocated(UValueGlassDr)) { + UValueGlassDr.allocate(n) = 0.0; + } + if (!allocated(glassDoorOpenScheds)) { + glassDoorOpenScheds.allocate(n) = nullptr; + } + if (!allocated(AreaGlassDr)) { + AreaGlassDr.allocate(n) = 0.0; + } + if (!allocated(HeightGlassDr)) { + HeightGlassDr.allocate(n) = 0.0; + } + if (!allocated(UValueStockDr)) { + UValueStockDr.allocate(n) = 0.0; + } + if (!allocated(stockDoorOpenScheds)) { + stockDoorOpenScheds.allocate(n) = nullptr; + } + if (!allocated(StockDoorProtectType)) { + StockDoorProtectType.allocate(n) = WIStockDoor::Invalid; + } + if (!allocated(AreaStockDr)) { + AreaStockDr.allocate(n) = 0.0; + } + if (!allocated(HeightStockDr)) { + HeightStockDr.allocate(n) = 0.0; + } + if (!allocated(SensZoneCreditRate)) { + SensZoneCreditRate.allocate(n) = 0.0; + } + if (!allocated(SensZoneCreditCoolRate)) { + SensZoneCreditCoolRate.allocate(n) = 0.0; + } + if (!allocated(SensZoneCreditCool)) { + SensZoneCreditCool.allocate(n) = 0.0; + } + if (!allocated(SensZoneCreditHeatRate)) { + SensZoneCreditHeatRate.allocate(n) = 0.0; + } + if (!allocated(SensZoneCreditHeat)) { + SensZoneCreditHeat.allocate(n) = 0.0; + } + if (!allocated(LatZoneCreditRate)) { + LatZoneCreditRate.allocate(n) = 0.0; + } + if (!allocated(LatZoneCredit)) { + LatZoneCredit.allocate(n) = 0.0; + } + } + // Reset Initialization Values to Zeros void reset_init() { diff --git a/src/EnergyPlus/ScheduleManager.cc b/src/EnergyPlus/ScheduleManager.cc index 08c597c345b..4a5be5961b0 100644 --- a/src/EnergyPlus/ScheduleManager.cc +++ b/src/EnergyPlus/ScheduleManager.cc @@ -326,6 +326,121 @@ namespace Sched { missingDaySchedule->isUsed = true; } + // Helper: check day-schedule values for limit violations and bad integers, issuing warnings. + static void warnDayScheduleValueIssues(EnergyPlusData &state, + ErrorObjectHeader const &eoh, + DaySchedule const *daySched, + Array1D_string const &Alphas, + Array1D_string const &cAlphaFields, + std::string_view badIntPreposition = "in") + { + if (daySched->checkValsForLimitViolations(state)) { + ShowWarningCustom(state, eoh, EnergyPlus::format("Values are outside of range for {}={}", cAlphaFields(2), Alphas(2))); + } + if (daySched->checkValsForBadIntegers(state)) { + ShowWarningCustom( + state, eoh, EnergyPlus::format("One or more values are not integer {} {}={}", badIntPreposition, cAlphaFields(2), Alphas(2))); + } + } + + // Helper: validate ScheduleType for a schedule or day-schedule object. + // Sets schedTypeNumOut to the type index if valid, or leaves it unchanged if blank/invalid. + // Returns true if valid, false if blank or not found (warnings are issued either way). + static void validateScheduleType(EnergyPlusData &state, + ErrorObjectHeader const &eoh, + Array1D_string const &Alphas, + Array1D_string const &cAlphaFields, + Array1D_bool const &lAlphaBlanks, + int &schedTypeNumOut) + { + if (lAlphaBlanks(2)) { + ShowWarningEmptyField(state, eoh, cAlphaFields(2)); + ShowContinueError(state, "Schedule will not be validated."); + } else if ((schedTypeNumOut = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) { + ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2)); + ShowContinueError(state, "Schedule will not be validated."); + } + } + + // Helper: process one ExternalInterface schedule object within ProcessScheduleInput. + // All three ExternalInterface schedule types (basic, FMU-Import, FMU-Export) share + // identical logic for creating the schedule, day-schedule, week-schedule, and + // filling weekScheds for all 366 days. + static void processExternalInterfaceSchedule(EnergyPlusData &state, + std::string_view routineName, + std::string const &CurrentModuleObject, + int numItems, + bool showDuplicateDetail, // true for FMU Import/Export types + int NumExternalInterfaceSchedules, + Array1D_string &Alphas, + Array1D_string &cAlphaFields, + Array1D_string &cNumericFields, + Array1D &Numbers, + Array1D_bool &lAlphaBlanks, + Array1D_bool &lNumericBlanks, + bool &ErrorsFound, + bool &NumErrorFlag) + { + auto const &s_ip = state.dataInputProcessing->inputProcessor; + auto const &s_sched = state.dataSched; + int NumAlphas; + int NumNumbers; + int Status; + + for (int Loop = 1; Loop <= numItems; ++Loop) { + s_ip->getObjectItem(state, + CurrentModuleObject, + Loop, + Alphas, + NumAlphas, + Numbers, + NumNumbers, + Status, + lNumericBlanks, + lAlphaBlanks, + cAlphaFields, + cNumericFields); + + ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; + + if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) { + ShowSevereDuplicateName(state, eoh); + if (showDuplicateDetail && NumExternalInterfaceSchedules >= 1) { + ShowContinueError( + state, + EnergyPlus::format("{} defined as an ExternalInterface:Schedule and ExternalInterface:FunctionalMockupUnitImport:To:Schedule." + "This will cause the schedule to be overwritten by PtolemyServer and FunctionalMockUpUnitImport)", + cAlphaFields(1))); + } + ErrorsFound = true; + continue; + } + + auto *sched = AddScheduleDetailed(state, Alphas(1)); + sched->type = SchedType::External; + + validateScheduleType(state, eoh, Alphas, cAlphaFields, lAlphaBlanks, sched->schedTypeNum); + + auto *daySched = AddDaySchedule(state, EnergyPlus::format("{}_xi_dy_", Alphas(1))); + daySched->isUsed = true; + daySched->schedTypeNum = sched->schedTypeNum; + + if (NumNumbers < 1) { + ShowWarningCustom(state, eoh, "Initial value is not numeric or is missing. Fix idf file."); + NumErrorFlag = true; + } + ExternalInterfaceSetSchedule(state, daySched->Num, Numbers(1)); + + auto *weekSched = AddWeekSchedule(state, EnergyPlus::format("{}_xi_wk_", Alphas(1))); + weekSched->isUsed = true; + for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) { + weekSched->dayScheds[iDayType] = daySched; + } + + std::fill(sched->weekScheds.begin() + 1, sched->weekScheds.end(), weekSched); + } // for (Loop) + } + void ProcessScheduleInput(EnergyPlusData &state) { // SUBROUTINE INFORMATION: @@ -416,105 +531,58 @@ namespace Sched { int MaxNums = 1; // Need at least 1 number because it's used as a local variable in the Schedule Types loop int MaxAlps = 0; - std::string CurrentModuleObject = "ScheduleTypeLimits"; - int NumScheduleTypes = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumScheduleTypes > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas); - } - CurrentModuleObject = "Schedule:Day:Hourly"; - int NumHrDaySchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumHrDaySchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas); - } - CurrentModuleObject = "Schedule:Day:Interval"; - int NumIntDaySchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumIntDaySchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas); - } - CurrentModuleObject = "Schedule:Day:List"; - int NumLstDaySchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumLstDaySchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas); - } - CurrentModuleObject = "Schedule:Week:Daily"; - int NumRegWeekSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumRegWeekSchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas); - } - CurrentModuleObject = "Schedule:Week:Compact"; - int NumCptWeekSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumCptWeekSchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas); - } - CurrentModuleObject = "Schedule:Year"; - int NumRegSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumRegSchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas); - } - CurrentModuleObject = "Schedule:Compact"; - int NumCptSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumCptSchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas + 1); - } - CurrentModuleObject = "Schedule:File"; - int NumCommaFileSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumCommaFileSchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas); + // Count objects and determine max alphas/numbers for all schedule object types + int NumScheduleTypes = 0; + int NumHrDaySchedules = 0; + int NumIntDaySchedules = 0; + int NumLstDaySchedules = 0; + int NumRegWeekSchedules = 0; + int NumCptWeekSchedules = 0; + int NumRegSchedules = 0; + int NumCptSchedules = 0; + int NumCommaFileSchedules = 0; + int NumConstantSchedules = 0; + int NumExternalInterfaceSchedules = 0; + int NumExternalInterfaceFunctionalMockupUnitImportSchedules = 0; + int NumExternalInterfaceFunctionalMockupUnitExportSchedules = 0; + + struct SchedObjInfo + { + const char *name; + int *count; + int alphaAdj; // added to NumAlphas for MaxAlps calculation + }; + + std::array schedObjs = {{ + {"ScheduleTypeLimits", &NumScheduleTypes, 0}, + {"Schedule:Day:Hourly", &NumHrDaySchedules, 0}, + {"Schedule:Day:Interval", &NumIntDaySchedules, 0}, + {"Schedule:Day:List", &NumLstDaySchedules, 0}, + {"Schedule:Week:Daily", &NumRegWeekSchedules, 0}, + {"Schedule:Week:Compact", &NumCptWeekSchedules, 0}, + {"Schedule:Year", &NumRegSchedules, 0}, + {"Schedule:Compact", &NumCptSchedules, 1}, + {"Schedule:File", &NumCommaFileSchedules, 0}, + {"Schedule:Constant", &NumConstantSchedules, 0}, + {"ExternalInterface:Schedule", &NumExternalInterfaceSchedules, 1}, + {"ExternalInterface:FunctionalMockupUnitImport:To:Schedule", &NumExternalInterfaceFunctionalMockupUnitImportSchedules, 1}, + {"ExternalInterface:FunctionalMockupUnitExport:To:Schedule", &NumExternalInterfaceFunctionalMockupUnitExportSchedules, 1}, + {"Output:Schedules", nullptr, 0}, + }}; + + for (auto &obj : schedObjs) { + int numFound = s_ip->getNumObjectsFound(state, obj.name); + if (obj.count != nullptr) { + *obj.count = numFound; + } + if (numFound > 0 || obj.count == nullptr) { + s_ip->getObjectDefMaxArgs(state, obj.name, Count, NumAlphas, NumNumbers); + MaxNums = max(MaxNums, NumNumbers); + MaxAlps = max(MaxAlps, NumAlphas + obj.alphaAdj); + } } - CurrentModuleObject = "Schedule:Constant"; - int NumConstantSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumConstantSchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas); - } - CurrentModuleObject = "ExternalInterface:Schedule"; - int NumExternalInterfaceSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - // added for FMI - if (NumExternalInterfaceSchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas + 1); - } - // added for FMU Import - CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Schedule"; - int NumExternalInterfaceFunctionalMockupUnitImportSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumExternalInterfaceFunctionalMockupUnitImportSchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas + 1); - } - // added for FMU Export - CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Schedule"; - int NumExternalInterfaceFunctionalMockupUnitExportSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject); - if (NumExternalInterfaceFunctionalMockupUnitExportSchedules > 0) { - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas + 1); - } - CurrentModuleObject = "Output:Schedules"; - s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers); - MaxNums = max(MaxNums, NumNumbers); - MaxAlps = max(MaxAlps, NumAlphas); + std::string CurrentModuleObject; Alphas.allocate(MaxAlps); // Maximum Alphas possible cAlphaFields.allocate(MaxAlps); @@ -825,14 +893,7 @@ namespace Sched { auto *daySched = AddDaySchedule(state, Alphas(1)); - // Validate ScheduleType - if (lAlphaBlanks(2)) { - ShowWarningEmptyField(state, eoh, cAlphaFields(2)); - ShowContinueError(state, "Schedule will not be validated."); - } else if ((daySched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) { - ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2)); - ShowContinueError(state, "Schedule will not be validated."); - } + validateScheduleType(state, eoh, Alphas, cAlphaFields, lAlphaBlanks, daySched->schedTypeNum); daySched->interpolation = Interpolation::No; @@ -843,13 +904,7 @@ namespace Sched { } } - if (daySched->checkValsForLimitViolations(state)) { - ShowWarningCustom(state, eoh, EnergyPlus::format("Values are outside of range for {}={}", cAlphaFields(2), Alphas(2))); - } - - if (daySched->checkValsForBadIntegers(state)) { - ShowWarningCustom(state, eoh, EnergyPlus::format("One or more values are not integer in {}={}", cAlphaFields(2), Alphas(2))); - } + warnDayScheduleValueIssues(state, eoh, daySched, Alphas, cAlphaFields); } // for (Loop) @@ -880,14 +935,7 @@ namespace Sched { auto *daySched = AddDaySchedule(state, Alphas(1)); - // Validate ScheduleType - if (lAlphaBlanks(2)) { - ShowWarningEmptyField(state, eoh, cAlphaFields(2)); - ShowContinueError(state, "Schedule will not be validated."); - } else if ((daySched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) { - ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2)); - ShowContinueError(state, "Schedule will not be validated."); - } + validateScheduleType(state, eoh, Alphas, cAlphaFields, lAlphaBlanks, daySched->schedTypeNum); NumFields = NumAlphas - 3; // check to see if numfield=0 @@ -922,13 +970,7 @@ namespace Sched { // Now parcel into TS Value.... tsVals.resize() was called in AddDaySchedule() daySched->populateFromMinuteVals(state, minuteVals); - if (daySched->checkValsForLimitViolations(state)) { - ShowWarningCustom(state, eoh, EnergyPlus::format("Values are outside of range for {}={}", cAlphaFields(2), Alphas(2))); - } - - if (daySched->checkValsForBadIntegers(state)) { - ShowWarningCustom(state, eoh, EnergyPlus::format("One or more values are not integer in {}={}", cAlphaFields(2), Alphas(2))); - } + warnDayScheduleValueIssues(state, eoh, daySched, Alphas, cAlphaFields); } //!! Get "DaySchedule:List" @@ -958,14 +1000,7 @@ namespace Sched { auto *daySched = AddDaySchedule(state, Alphas(1)); - // Validate ScheduleType - if (lAlphaBlanks(2)) { - ShowWarningEmptyField(state, eoh, cAlphaFields(2)); - ShowContinueError(state, "Schedule will not be validated."); - } else if ((daySched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) { - ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2)); - ShowContinueError(state, "Schedule will not be validated."); - } + validateScheduleType(state, eoh, Alphas, cAlphaFields, lAlphaBlanks, daySched->schedTypeNum); // Depending on value of "Interpolate" field, the value for each time step in each hour gets processed: daySched->interpolation = static_cast(getEnumValue(interpolationNamesUC, Alphas(3))); @@ -1032,13 +1067,7 @@ namespace Sched { // Now parcel into TS Value.... tsVals.resize() was called in AddDaySchedule() daySched->populateFromMinuteVals(state, minuteVals); - if (daySched->checkValsForLimitViolations(state)) { - ShowWarningCustom(state, eoh, EnergyPlus::format("Values are outside of range for {}={}", cAlphaFields(2), Alphas(2))); - } - - if (daySched->checkValsForBadIntegers(state)) { - ShowWarningCustom(state, eoh, EnergyPlus::format("One or more values are not integer for {}={}", cAlphaFields(2), Alphas(2))); - } + warnDayScheduleValueIssues(state, eoh, daySched, Alphas, cAlphaFields, "for"); } //!! Get Week Schedules - regular @@ -1172,13 +1201,7 @@ namespace Sched { auto *sched = AddScheduleDetailed(state, Alphas(1)); // Validate ScheduleType - if (lAlphaBlanks(2)) { - ShowWarningEmptyField(state, eoh, cAlphaFields(2)); - ShowContinueError(state, "Schedule will not be validated."); - } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) { - ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2)); - ShowContinueError(state, "Schedule will not be validated."); - } + validateScheduleType(state, eoh, Alphas, cAlphaFields, lAlphaBlanks, sched->schedTypeNum); int NumPointer = 0; @@ -1295,14 +1318,7 @@ namespace Sched { auto *sched = AddScheduleDetailed(state, Alphas(1)); sched->type = SchedType::Compact; - // Validate ScheduleType - if (lAlphaBlanks(2)) { - ShowWarningEmptyField(state, eoh, cAlphaFields(2)); - ShowContinueError(state, "Schedule will not be validated."); - } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) { - ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2)); - ShowContinueError(state, "Schedule will not be validated."); - } + validateScheduleType(state, eoh, Alphas, cAlphaFields, lAlphaBlanks, sched->schedTypeNum); std::array daysInYear; std::fill(daysInYear.begin() + 1, daysInYear.end(), 0); @@ -1596,14 +1612,7 @@ namespace Sched { auto *sched = AddScheduleDetailed(state, Alphas(1)); sched->type = SchedType::File; - // Validate ScheduleType - if (lAlphaBlanks(2)) { - ShowWarningEmptyField(state, eoh, cAlphaFields(2)); - ShowContinueError(state, "Schedule will not be validated."); - } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) { - ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2)); - ShowContinueError(state, "Schedule will not be validated."); - } + validateScheduleType(state, eoh, Alphas, cAlphaFields, lAlphaBlanks, sched->schedTypeNum); // Numbers(1) - which column curcolCount = Numbers(1); @@ -1985,13 +1994,7 @@ namespace Sched { auto *sched = AddScheduleConstant(state, Alphas(1), Numbers(1)); // Validate ScheduleType - if (lAlphaBlanks(2)) { // No warning here for constant schedules - ShowWarningEmptyField(state, eoh, cAlphaFields(2)); - ShowContinueError(state, "Schedule will not be validated."); - } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) { - ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2)); - ShowContinueError(state, "Schedule will not be validated."); - } + validateScheduleType(state, eoh, Alphas, cAlphaFields, lAlphaBlanks, sched->schedTypeNum); if (s_glob->AnyEnergyManagementSystemInModel) { // setup constant schedules as actuators SetupEMSActuator(state, "Schedule:Constant", sched->Name, "Schedule Value", "[ ]", sched->EMSActuatedOn, sched->EMSVal); @@ -2001,199 +2004,50 @@ namespace Sched { static_cast(s_sched->schedules[SchedNum_AlwaysOff])->tsVals.assign(Constant::iHoursInDay * s_glob->TimeStepsInHour, 0.0); static_cast(s_sched->schedules[SchedNum_AlwaysOn])->tsVals.assign(Constant::iHoursInDay * s_glob->TimeStepsInHour, 1.0); - CurrentModuleObject = "ExternalInterface:Schedule"; - for (int Loop = 1; Loop <= NumExternalInterfaceSchedules; ++Loop) { - s_ip->getObjectItem(state, - CurrentModuleObject, - Loop, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - Status, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); - - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) { - ShowSevereDuplicateName(state, eoh); - ErrorsFound = true; - continue; - } - - auto *sched = AddScheduleDetailed(state, Alphas(1)); - sched->type = SchedType::External; - - // Validate ScheduleType - if (lAlphaBlanks(2)) { - ShowWarningEmptyField(state, eoh, cAlphaFields(2)); - ShowContinueError(state, "Schedule will not be validated."); - } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) { - ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2)); - ShowContinueError(state, "Schedule will not be validated."); - } - - // TODO: I'm not sure this Jazz is necessary - // Add day schedule - auto *daySched = AddDaySchedule(state, EnergyPlus::format("{}_xi_dy_", Alphas(1))); - daySched->isUsed = true; - daySched->schedTypeNum = sched->schedTypeNum; - - // Initialize the ExternalInterface day schedule for the ExternalInterface compact schedule. - // It will be overwritten during run time stepping after the warm up period - if (NumNumbers < 1) { - ShowWarningCustom(state, eoh, "Initial value is not numeric or is missing. Fix idf file."); - NumErrorFlag = true; - } - ExternalInterfaceSetSchedule(state, daySched->Num, Numbers(1)); - - auto *weekSched = AddWeekSchedule(state, EnergyPlus::format("{}_xi_wk_", Alphas(1))); - weekSched->isUsed = true; - for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) { - weekSched->dayScheds[iDayType] = daySched; - } - - for (int iDay = 1; iDay <= 366; ++iDay) { - sched->weekScheds[iDay] = weekSched; - } - } // for (Loop) - - // added for FMU Import - CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Schedule"; - for (int Loop = 1; Loop <= NumExternalInterfaceFunctionalMockupUnitImportSchedules; ++Loop) { - s_ip->getObjectItem(state, - CurrentModuleObject, - Loop, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - Status, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); - - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) { - ShowSevereDuplicateName(state, eoh); - if (NumExternalInterfaceSchedules >= 1) { - ShowContinueError( - state, - EnergyPlus::format("{} defined as an ExternalInterface:Schedule and ExternalInterface:FunctionalMockupUnitImport:To:Schedule." - "This will cause the schedule to be overwritten by PtolemyServer and FunctionalMockUpUnitImport)", - cAlphaFields(1))); - } - ErrorsFound = true; - continue; - } - - auto *sched = AddScheduleDetailed(state, Alphas(1)); - sched->type = SchedType::External; - - // Validate ScheduleType - if (lAlphaBlanks(2)) { - ShowWarningEmptyField(state, eoh, cAlphaFields(2)); - ShowContinueError(state, "Schedule will not be validated."); - } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) { - ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2)); - ShowContinueError(state, "Schedule will not be validated."); - } - - // TODO: I'm not sure this Jazz is necessary - // Add day schedule - auto *daySched = AddDaySchedule(state, EnergyPlus::format("{}_xi_dy_", Alphas(1))); - daySched->isUsed = true; - daySched->schedTypeNum = sched->schedTypeNum; - - // Initialize the ExternalInterface day schedule for the ExternalInterface compact schedule. - // It will be overwritten during run time stepping after the warm up period - if (NumNumbers < 1) { - ShowWarningCustom(state, eoh, "Initial value is not numeric or is missing. Fix idf file."); - NumErrorFlag = true; - } - ExternalInterfaceSetSchedule(state, daySched->Num, Numbers(1)); - - auto *weekSched = AddWeekSchedule(state, EnergyPlus::format("{}_xi_wk_", Alphas(1))); - weekSched->isUsed = true; - for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) { - weekSched->dayScheds[iDayType] = daySched; - } - - for (int iDay = 1; iDay <= 366; ++iDay) { - sched->weekScheds[iDay] = weekSched; - } - } - - // added for FMU Export - CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Schedule"; - for (int Loop = 1; Loop <= NumExternalInterfaceFunctionalMockupUnitExportSchedules; ++Loop) { - s_ip->getObjectItem(state, - CurrentModuleObject, - Loop, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - Status, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields); - - ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)}; - - if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) { - ShowSevereDuplicateName(state, eoh); - if (NumExternalInterfaceSchedules >= 1) { - ShowContinueError( - state, - EnergyPlus::format("{} defined as an ExternalInterface:Schedule and ExternalInterface:FunctionalMockupUnitImport:To:Schedule." - "This will cause the schedule to be overwritten by PtolemyServer and FunctionalMockUpUnitImport)", - cAlphaFields(1))); - } - ErrorsFound = true; - continue; - } - - auto *sched = AddScheduleDetailed(state, Alphas(1)); - sched->type = SchedType::External; - - // Validate ScheduleType - if (lAlphaBlanks(2)) { - ShowWarningEmptyField(state, eoh, cAlphaFields(2)); - ShowContinueError(state, "Schedule will not be validated."); - } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) { - ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2)); - ShowContinueError(state, "Schedule will not be validated."); - } - - // TODO: I'm not sure this Jazz is necessary - // Add day schedule - auto *daySched = AddDaySchedule(state, EnergyPlus::format("{}_xi_dy_", Alphas(1))); - daySched->isUsed = true; - daySched->schedTypeNum = sched->schedTypeNum; - - // Initialize the ExternalInterface day schedule for the ExternalInterface compact schedule. - // It will be overwritten during run time stepping after the warm up period - if (NumNumbers < 1) { - ShowWarningCustom(state, eoh, "Initial value is not numeric or is missing. Fix idf file."); - NumErrorFlag = true; - } - ExternalInterfaceSetSchedule(state, daySched->Num, Numbers(1)); - - auto *weekSched = AddWeekSchedule(state, EnergyPlus::format("{}_xi_wk_", Alphas(1))); - weekSched->isUsed = true; - for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) { - weekSched->dayScheds[iDayType] = daySched; - } - - std::fill(sched->weekScheds.begin() + 1, sched->weekScheds.end(), weekSched); - } // for (Loop) + processExternalInterfaceSchedule(state, + routineName, + "ExternalInterface:Schedule", + NumExternalInterfaceSchedules, + false, + NumExternalInterfaceSchedules, + Alphas, + cAlphaFields, + cNumericFields, + Numbers, + lAlphaBlanks, + lNumericBlanks, + ErrorsFound, + NumErrorFlag); + + processExternalInterfaceSchedule(state, + routineName, + "ExternalInterface:FunctionalMockupUnitImport:To:Schedule", + NumExternalInterfaceFunctionalMockupUnitImportSchedules, + true, + NumExternalInterfaceSchedules, + Alphas, + cAlphaFields, + cNumericFields, + Numbers, + lAlphaBlanks, + lNumericBlanks, + ErrorsFound, + NumErrorFlag); + + processExternalInterfaceSchedule(state, + routineName, + "ExternalInterface:FunctionalMockupUnitExport:To:Schedule", + NumExternalInterfaceFunctionalMockupUnitExportSchedules, + true, + NumExternalInterfaceSchedules, + Alphas, + cAlphaFields, + cNumericFields, + Numbers, + lAlphaBlanks, + lNumericBlanks, + ErrorsFound, + NumErrorFlag); // Validate by ScheduleLimitsType for (auto *sched : s_sched->schedules) { diff --git a/src/EnergyPlus/SetPointManager.cc b/src/EnergyPlus/SetPointManager.cc index db871abea2c..4a6fff42b44 100644 --- a/src/EnergyPlus/SetPointManager.cc +++ b/src/EnergyPlus/SetPointManager.cc @@ -311,6 +311,85 @@ void GetSetPointManagerInputs(EnergyPlusData &state) } } // GetSetPointManagerInputs() +// Helper: apply a setpoint value to the appropriate node field based on the +// control variable type. Covers temperature, humidity ratio, and mass-flow-rate +// variants so that callers can avoid repeating the same 9-arm switch. +static void applySetPointToNode(Node::NodeData &node, HVAC::CtrlVarType ctrlVar, Real64 value) +{ + switch (ctrlVar) { + case HVAC::CtrlVarType::Temp: + node.TempSetPoint = value; + break; + case HVAC::CtrlVarType::MaxTemp: + node.TempSetPointHi = value; + break; + case HVAC::CtrlVarType::MinTemp: + node.TempSetPointLo = value; + break; + case HVAC::CtrlVarType::HumRat: + node.HumRatSetPoint = value; + break; + case HVAC::CtrlVarType::MaxHumRat: + node.HumRatMax = value; + break; + case HVAC::CtrlVarType::MinHumRat: + node.HumRatMin = value; + break; + case HVAC::CtrlVarType::MassFlowRate: + node.MassFlowRateSetPoint = value; + break; + case HVAC::CtrlVarType::MaxMassFlowRate: + node.MassFlowRateMax = value; + break; + case HVAC::CtrlVarType::MinMassFlowRate: + node.MassFlowRateMin = value; + break; + default: + break; + } +} + +// Helper: resolve and validate the HVAC air loop for SPMs that require one. +// Sets spm->airLoopNum and returns true when the loop is found, false otherwise +// (setting ErrorsFound = true in both failure modes). +static bool findSPMAirLoop( + EnergyPlusData &state, SPMBase *spm, std::string_view spmTypeName, std::string_view spmName, ErrorObjectHeader const &eoh, bool &ErrorsFound) +{ + if (state.dataHVACGlobal->NumPrimaryAirSys <= 0) { + ShowSevereError(state, EnergyPlus::format("{}=\"{}\", no AirLoopHVAC objects found:", spmTypeName, spmName)); + ShowContinueError(state, "Setpoint Manager needs an AirLoopHVAC to operate."); + ErrorsFound = true; + return false; + } + spm->airLoopNum = Util::FindItemInList(spm->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName); + if (spm->airLoopNum == 0) { + ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spm->airLoopName); + ErrorsFound = true; + return false; + } + return true; +} + +// Helper to look up a single sensor node for a SetPointManager, avoiding 8 lines of +// boilerplate per call to GetOnlySingleNode. +static int getSPMSensorNode(EnergyPlusData &state, + std::string const &nodeName, + bool &errorsFound, + SPMType spmType, + std::string const &spmName, + Node::FluidType fluidType = Node::FluidType::Air) +{ + return Node::GetOnlySingleNode(state, + nodeName, + errorsFound, + spmNodeObjectTypes[(int)spmType], + spmName, + fluidType, + Node::ConnectionType::Sensor, + Node::CompFluidStream::Primary, + Node::ObjectIsNotParent); +} + void GetSetPointManagerInputData(EnergyPlusData &state, bool &ErrorsFound) { @@ -587,14 +666,6 @@ void GetSetPointManagerInputData(EnergyPlusData &state, bool &ErrorsFound) case SPMType::FollowGroundTemp: { spm->minSetTemp = ip->getRealFieldValue(fields, props, "minimum_setpoint_temperature"); spm->maxSetTemp = ip->getRealFieldValue(fields, props, "maximum_setpoint_temperature"); - if (spm->maxSetTemp < spm->minSetTemp) { - ShowWarningError(state, EnergyPlus::format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spm->Name)); - ShowContinueError( - state, - EnergyPlus::format("...maximum_supply_air_temperature=[{:.1R}] is less than minimum_supply_air_temperature=[{:.1R}].", - spm->maxSetTemp, - spm->minSetTemp)); - } } break; case SPMType::SZReheat: @@ -602,33 +673,31 @@ void GetSetPointManagerInputData(EnergyPlusData &state, bool &ErrorsFound) case SPMType::SZCooling: { spm->minSetTemp = ip->getRealFieldValue(fields, props, "minimum_supply_air_temperature"); spm->maxSetTemp = ip->getRealFieldValue(fields, props, "maximum_supply_air_temperature"); - if (spm->maxSetTemp < spm->minSetTemp) { - ShowWarningError(state, EnergyPlus::format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spm->Name)); - ShowContinueError( - state, - EnergyPlus::format("...maximum_supply_air_temperature=[{:.1R}] is less than minimum_supply_air_temperature=[{:.1R}].", - spm->maxSetTemp, - spm->minSetTemp)); - } } break; case SPMType::FollowSystemNodeTemp: { spm->minSetTemp = ip->getRealFieldValue(fields, props, "minimum_limit_setpoint_temperature"); spm->maxSetTemp = ip->getRealFieldValue(fields, props, "maximum_limit_setpoint_temperature"); - if (spm->maxSetTemp < spm->minSetTemp) { - ShowWarningError(state, EnergyPlus::format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spm->Name)); - ShowContinueError( - state, - EnergyPlus::format("...maximum_supply_air_temperature=[{:.1R}] is less than minimum_supply_air_temperature=[{:.1R}].", - spm->maxSetTemp, - spm->minSetTemp)); - } } break; default: break; } // switch (spm->type) + // Warn once for all three variants that loaded minSetTemp/maxSetTemp above + if (spm->maxSetTemp < spm->minSetTemp && + (spm->type == SPMType::OutsideAirPretreat || spm->type == SPMType::Warmest || spm->type == SPMType::Coldest || + spm->type == SPMType::WarmestTempFlow || spm->type == SPMType::MZCoolingAverage || spm->type == SPMType::MZHeatingAverage || + spm->type == SPMType::FollowOutsideAirTemp || spm->type == SPMType::FollowGroundTemp || spm->type == SPMType::SZReheat || + spm->type == SPMType::SZHeating || spm->type == SPMType::SZCooling || spm->type == SPMType::FollowSystemNodeTemp)) { + ShowWarningError(state, EnergyPlus::format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spm->Name)); + ShowContinueError( + state, + EnergyPlus::format("...maximum_supply_air_temperature=[{:.1R}] is less than minimum_supply_air_temperature=[{:.1R}].", + spm->maxSetTemp, + spm->minSetTemp)); + } + // Read Min and Max HumRat for some SPMs switch (spm->type) { @@ -803,24 +872,10 @@ void GetSetPointManagerInputData(EnergyPlusData &state, bool &ErrorsFound) } spmSZR->setPt = 0.0; - spmSZR->zoneNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "zone_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmSZR->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - spmSZR->zoneInletNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "zone_inlet_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmSZR->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); + spmSZR->zoneNodeNum = + getSPMSensorNode(state, ip->getAlphaFieldValue(fields, props, "zone_node_name"), ErrorsFound, spm->type, spmSZR->Name); + spmSZR->zoneInletNodeNum = + getSPMSensorNode(state, ip->getAlphaFieldValue(fields, props, "zone_inlet_node_name"), ErrorsFound, spm->type, spmSZR->Name); } break; // SetpointManager:SingleZone:Heating @@ -843,24 +898,10 @@ void GetSetPointManagerInputData(EnergyPlusData &state, bool &ErrorsFound) } spmSZTemp->setPt = 0.0; - spmSZTemp->zoneNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "zone_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmSZTemp->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - spmSZTemp->zoneInletNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "zone_inlet_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmSZTemp->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); + spmSZTemp->zoneNodeNum = + getSPMSensorNode(state, ip->getAlphaFieldValue(fields, props, "zone_node_name"), ErrorsFound, spm->type, spmSZTemp->Name); + spmSZTemp->zoneInletNodeNum = + getSPMSensorNode(state, ip->getAlphaFieldValue(fields, props, "zone_inlet_node_name"), ErrorsFound, spm->type, spmSZTemp->Name); } break; @@ -913,33 +954,12 @@ void GetSetPointManagerInputData(EnergyPlusData &state, bool &ErrorsFound) ErrorsFound = true; } - spmMA->refNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "reference_setpoint_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmMA->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - spmMA->fanInNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "fan_inlet_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmMA->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - spmMA->fanOutNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "fan_outlet_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmMA->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); + spmMA->refNodeNum = getSPMSensorNode( + state, ip->getAlphaFieldValue(fields, props, "reference_setpoint_node_name"), ErrorsFound, spm->type, spmMA->Name); + spmMA->fanInNodeNum = + getSPMSensorNode(state, ip->getAlphaFieldValue(fields, props, "fan_inlet_node_name"), ErrorsFound, spm->type, spmMA->Name); + spmMA->fanOutNodeNum = + getSPMSensorNode(state, ip->getAlphaFieldValue(fields, props, "fan_outlet_node_name"), ErrorsFound, spm->type, spmMA->Name); } break; // SetpointManager:OutdoorAirPretreat @@ -947,42 +967,14 @@ void GetSetPointManagerInputData(EnergyPlusData &state, bool &ErrorsFound) auto *spmOAP = dynamic_cast(spm); assert(spmOAP != nullptr); - spmOAP->refNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "reference_setpoint_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmOAP->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - spmOAP->mixedOutNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "mixed_air_stream_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmOAP->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - spmOAP->oaInNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "outdoor_air_stream_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmOAP->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - spmOAP->returnInNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "return_air_stream_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmOAP->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); + spmOAP->refNodeNum = getSPMSensorNode( + state, ip->getAlphaFieldValue(fields, props, "reference_setpoint_node_name"), ErrorsFound, spm->type, spmOAP->Name); + spmOAP->mixedOutNodeNum = getSPMSensorNode( + state, ip->getAlphaFieldValue(fields, props, "mixed_air_stream_node_name"), ErrorsFound, spm->type, spmOAP->Name); + spmOAP->oaInNodeNum = getSPMSensorNode( + state, ip->getAlphaFieldValue(fields, props, "outdoor_air_stream_node_name"), ErrorsFound, spm->type, spmOAP->Name); + spmOAP->returnInNodeNum = getSPMSensorNode( + state, ip->getAlphaFieldValue(fields, props, "return_air_stream_node_name"), ErrorsFound, spm->type, spmOAP->Name); if (std::find(spmOAP->ctrlNodeNums.begin(), spmOAP->ctrlNodeNums.end(), spmOAP->refNodeNum) != spmOAP->ctrlNodeNums.end()) { ShowSevereError(state, EnergyPlus::format("{}: {}=\"{}\", reference node.", routineName, cCurrentModuleObject, spmOAP->Name)); @@ -1093,15 +1085,12 @@ void GetSetPointManagerInputData(EnergyPlusData &state, bool &ErrorsFound) ErrorsFound = true; } - spmFNT->refNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "reference_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmFNT->Name, - Node::FluidType::Blank, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); + spmFNT->refNodeNum = getSPMSensorNode(state, + ip->getAlphaFieldValue(fields, props, "reference_node_name"), + ErrorsFound, + spm->type, + spmFNT->Name, + Node::FluidType::Blank); spmFNT->refTempType = static_cast(getEnumValue(nodeTempTypeNamesUC, ip->getAlphaFieldValue(fields, props, "reference_temperature_type"))); @@ -1323,57 +1312,39 @@ void GetSetPointManagerInputData(EnergyPlusData &state, bool &ErrorsFound) } break; // SetpointManager:SystemNodeReset:Temperature - case SPMType::SystemNodeTemp: { - auto *spmSNRTemp = dynamic_cast(spm); - assert(spmSNRTemp != nullptr); - - if (spmSNRTemp->ctrlVar != HVAC::CtrlVarType::Temp && spmSNRTemp->ctrlVar != HVAC::CtrlVarType::MaxTemp && - spmSNRTemp->ctrlVar != HVAC::CtrlVarType::MinTemp) { - ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName); - ErrorsFound = true; - } - - spmSNRTemp->lowRefSetPt = ip->getRealFieldValue(fields, props, "setpoint_at_low_reference_temperature"); - spmSNRTemp->highRefSetPt = ip->getRealFieldValue(fields, props, "setpoint_at_high_reference_temperature"); - spmSNRTemp->lowRef = ip->getRealFieldValue(fields, props, "low_reference_temperature"); - spmSNRTemp->highRef = ip->getRealFieldValue(fields, props, "high_reference_temperature"); - - spmSNRTemp->refNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "reference_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmSNRTemp->Name, - Node::FluidType::Blank, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - } break; - // SetpointManager:SystemNodeReset:Humidity + case SPMType::SystemNodeTemp: case SPMType::SystemNodeHum: { - auto *spmSNRHum = dynamic_cast(spm); - assert(spmSNRHum != nullptr); - - if (spmSNRHum->ctrlVar != HVAC::CtrlVarType::HumRat && spmSNRHum->ctrlVar != HVAC::CtrlVarType::MaxHumRat && - spmSNRHum->ctrlVar != HVAC::CtrlVarType::MinHumRat) { - ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName); - ErrorsFound = true; + auto *spmSNR = dynamic_cast(spm); + assert(spmSNR != nullptr); + + bool const isTemp = (spm->type == SPMType::SystemNodeTemp); + if (isTemp) { + if (spmSNR->ctrlVar != HVAC::CtrlVarType::Temp && spmSNR->ctrlVar != HVAC::CtrlVarType::MaxTemp && + spmSNR->ctrlVar != HVAC::CtrlVarType::MinTemp) { + ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName); + ErrorsFound = true; + } + } else { + if (spmSNR->ctrlVar != HVAC::CtrlVarType::HumRat && spmSNR->ctrlVar != HVAC::CtrlVarType::MaxHumRat && + spmSNR->ctrlVar != HVAC::CtrlVarType::MinHumRat) { + ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName); + ErrorsFound = true; + } } - spmSNRHum->lowRefSetPt = ip->getRealFieldValue(fields, props, "setpoint_at_low_reference_humidity_ratio"); - spmSNRHum->highRefSetPt = ip->getRealFieldValue(fields, props, "setpoint_at_high_reference_humidity_ratio"); - spmSNRHum->lowRef = ip->getRealFieldValue(fields, props, "low_reference_humidity_ratio"); - spmSNRHum->highRef = ip->getRealFieldValue(fields, props, "high_reference_humidity_ratio"); + std::string_view const suffix = isTemp ? "temperature" : "humidity_ratio"; + spmSNR->lowRefSetPt = ip->getRealFieldValue(fields, props, EnergyPlus::format("setpoint_at_low_reference_{}", suffix)); + spmSNR->highRefSetPt = ip->getRealFieldValue(fields, props, EnergyPlus::format("setpoint_at_high_reference_{}", suffix)); + spmSNR->lowRef = ip->getRealFieldValue(fields, props, EnergyPlus::format("low_reference_{}", suffix)); + spmSNR->highRef = ip->getRealFieldValue(fields, props, EnergyPlus::format("high_reference_{}", suffix)); - spmSNRHum->refNodeNum = GetOnlySingleNode(state, - ip->getAlphaFieldValue(fields, props, "reference_node_name"), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmSNRHum->Name, - Node::FluidType::Blank, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); + spmSNR->refNodeNum = getSPMSensorNode(state, + ip->getAlphaFieldValue(fields, props, "reference_node_name"), + ErrorsFound, + spm->type, + spmSNR->Name, + Node::FluidType::Blank); } break; // SetpointManager:MultiZone:Cooling:Average @@ -1421,27 +1392,13 @@ void GetSetPointManagerInputData(EnergyPlusData &state, bool &ErrorsFound) auto *spmMA = dynamic_cast(spm); assert(spmMA != nullptr); if (auto found = fields.find("cooling_coil_inlet_node_name"); found != fields.end()) { - spmMA->coolCoilInNodeNum = GetOnlySingleNode(state, - Util::makeUPPER(found.value().get()), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmMA->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); + spmMA->coolCoilInNodeNum = + getSPMSensorNode(state, Util::makeUPPER(found.value().get()), ErrorsFound, spm->type, spmMA->Name); } if (auto found = fields.find("cooling_coil_outlet_node_name"); found != fields.end()) { - spmMA->coolCoilOutNodeNum = GetOnlySingleNode(state, - Util::makeUPPER(found.value().get()), - ErrorsFound, - spmNodeObjectTypes[(int)spm->type], - spmMA->Name, - Node::FluidType::Air, - Node::ConnectionType::Sensor, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); + spmMA->coolCoilOutNodeNum = + getSPMSensorNode(state, Util::makeUPPER(found.value().get()), ErrorsFound, spm->type, spmMA->Name); } if (auto found = fields.find("minimum_temperature_at_cooling_coil_outlet_node"); found != fields.end()) { @@ -1909,21 +1866,12 @@ void InitSetPointManagers(EnergyPlusData &state) case SPMType::Coldest: { auto *spmT = dynamic_cast(spm); assert(spmT != nullptr); - if (state.dataHVACGlobal->NumPrimaryAirSys > 0) { - spmT->airLoopNum = - Util::FindItemInList(spmT->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName); - if (spmT->airLoopNum == 0) { - ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmT->airLoopName); - ErrorsFound = true; - } else if (state.dataAirLoop->AirToZoneNodeInfo(spmT->airLoopNum).NumZonesCooled == 0) { + if (findSPMAirLoop(state, spm, spmTypeName, spmName, eoh, ErrorsFound)) { + if (state.dataAirLoop->AirToZoneNodeInfo(spmT->airLoopNum).NumZonesCooled == 0) { ShowSevereError(state, EnergyPlus::format("{}=\"{}\", no zones with cooling found:", spmTypeName, spmName)); ShowContinueError(state, EnergyPlus::format("Air Loop provides no cooling, Air Loop=\"{}\".", spmT->airLoopName)); ErrorsFound = true; } - } else { - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", no AirLoopHVAC objects found:", spmTypeName, spmName)); - ShowContinueError(state, "Setpoint Manager needs an AirLoopHVAC to operate."); - ErrorsFound = true; } } break; @@ -1931,24 +1879,13 @@ void InitSetPointManagers(EnergyPlusData &state) auto *spmWTF = dynamic_cast(spm); assert(spmWTF != nullptr); - if (state.dataHVACGlobal->NumPrimaryAirSys > 0) { - spmWTF->airLoopNum = Util::FindItemInList( - spmWTF->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName); - if (spmWTF->airLoopNum == 0) { - ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmWTF->airLoopName); - ErrorsFound = true; - } else { - spmWTF->simReady = true; - } + if (findSPMAirLoop(state, spm, spmTypeName, spmName, eoh, ErrorsFound)) { + spmWTF->simReady = true; if (state.dataAirLoop->AirToZoneNodeInfo(spmWTF->airLoopNum).NumZonesCooled == 0) { ShowSevereError(state, EnergyPlus::format("{}=\"{}\", no zones with cooling found:", spmTypeName, spmName)); ShowContinueError(state, EnergyPlus::format("Air Loop provides no cooling, Air Loop=\"{}\".", spmWTF->airLoopName)); ErrorsFound = true; } - } else { - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", no AirLoopHVAC objects found:", spmTypeName, spmName)); - ShowContinueError(state, "Setpoint Manager needs an AirLoopHVAC to operate."); - ErrorsFound = true; } } break; @@ -1956,14 +1893,7 @@ void InitSetPointManagers(EnergyPlusData &state) auto *spmRAB = dynamic_cast(spm); assert(spmRAB != nullptr); - if (state.dataHVACGlobal->NumPrimaryAirSys > 0) { - spmRAB->airLoopNum = Util::FindItemInList( - spmRAB->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName); - if (spmRAB->airLoopNum == 0) { - ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmRAB->airLoopName); - ErrorsFound = true; - } - + if (findSPMAirLoop(state, spm, spmTypeName, spmName, eoh, ErrorsFound)) { auto const &primaryAirSystem = state.dataAirSystemsData->PrimaryAirSystems(spmRAB->airLoopNum); if (primaryAirSystem.RABExists) { spmRAB->rabMixInNodeNum = primaryAirSystem.RABMixInNode; @@ -1977,10 +1907,6 @@ void InitSetPointManagers(EnergyPlusData &state) ShowContinueError(state, EnergyPlus::format("Air Loop=\"{}\".", spmRAB->airLoopName)); ErrorsFound = true; } - } else { - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", no AirLoopHVAC objects found:", spmTypeName, spmName)); - ShowContinueError(state, "Setpoint Manager needs an AirLoopHVAC to operate."); - ErrorsFound = true; } } break; @@ -1989,23 +1915,12 @@ void InitSetPointManagers(EnergyPlusData &state) auto *spmMZTemp = dynamic_cast(spm); assert(spmMZTemp != nullptr); - if (state.dataHVACGlobal->NumPrimaryAirSys > 0) { - spmMZTemp->airLoopNum = Util::FindItemInList( - spmMZTemp->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName); - if (spmMZTemp->airLoopNum == 0) { - ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmMZTemp->airLoopName); - ErrorsFound = true; - } - + if (findSPMAirLoop(state, spm, spmTypeName, spmName, eoh, ErrorsFound)) { if (state.dataAirLoop->AirToZoneNodeInfo(spmMZTemp->airLoopNum).NumZonesCooled == 0) { ShowSevereError(state, EnergyPlus::format("{}=\"{}\", no zones with cooling found:", spmTypeName, spmName)); ShowContinueError(state, EnergyPlus::format("Air Loop provides no cooling, Air Loop=\"{}\".", spmMZTemp->airLoopName)); ErrorsFound = true; } - } else { - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", no AirLoopHVAC objects found:", spmTypeName, spmName)); - ShowContinueError(state, "Setpoint Manager needs an AirLoopHVAC to operate."); - ErrorsFound = true; } } break; @@ -2016,38 +1931,27 @@ void InitSetPointManagers(EnergyPlusData &state) auto *spmMZHum = dynamic_cast(spm); assert(spmMZHum != nullptr); - if (state.dataHVACGlobal->NumPrimaryAirSys > 0) { - spmMZHum->airLoopNum = Util::FindItemInList( - spmMZHum->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName); - if (spmMZHum->airLoopNum == 0) { - ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmMZHum->airLoopName); - ErrorsFound = true; - } else { - // make sure humidity controlled zone - auto const &primaryAirSystem = state.dataAirSystemsData->PrimaryAirSystems(spmMZHum->airLoopNum); - auto const &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(spmMZHum->airLoopNum); - bool HstatZoneFound = false; - for (int iZone = 1; iZone <= state.dataZoneCtrls->NumHumidityControlZones; ++iZone) { - for (int jZone = 1; jZone <= airToZoneNode.NumZonesCooled; ++jZone) { - if (state.dataZoneCtrls->HumidityControlZone(iZone).ActualZoneNum == airToZoneNode.CoolCtrlZoneNums(jZone)) { - HstatZoneFound = true; - break; - } + if (findSPMAirLoop(state, spm, spmTypeName, spmName, eoh, ErrorsFound)) { + // make sure humidity controlled zone + auto const &primaryAirSystem = state.dataAirSystemsData->PrimaryAirSystems(spmMZHum->airLoopNum); + auto const &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(spmMZHum->airLoopNum); + bool HstatZoneFound = false; + for (int iZone = 1; iZone <= state.dataZoneCtrls->NumHumidityControlZones; ++iZone) { + for (int jZone = 1; jZone <= airToZoneNode.NumZonesCooled; ++jZone) { + if (state.dataZoneCtrls->HumidityControlZone(iZone).ActualZoneNum == airToZoneNode.CoolCtrlZoneNums(jZone)) { + HstatZoneFound = true; + break; } } + } - if (!HstatZoneFound) { - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", invalid humidistat specification", spmTypeName, spmName)); - ShowContinueError(state, - EnergyPlus::format("could not locate Humidistat in any of the zones served by the Air loop={}", - primaryAirSystem.Name)); - ErrorsFound = true; - } + if (!HstatZoneFound) { + ShowSevereError(state, EnergyPlus::format("{}=\"{}\", invalid humidistat specification", spmTypeName, spmName)); + ShowContinueError(state, + EnergyPlus::format("could not locate Humidistat in any of the zones served by the Air loop={}", + primaryAirSystem.Name)); + ErrorsFound = true; } - } else { - ShowSevereError(state, EnergyPlus::format("{}=\"{}\", no AirLoopHVAC objects found:", spmTypeName, spmName)); - ShowContinueError(state, "Setpoint Manager needs an AirLoopHVAC to operate."); - ErrorsFound = true; } } break; @@ -2267,41 +2171,10 @@ void InitSetPointManagers(EnergyPlusData &state) auto *spmS = dynamic_cast(spm); assert(spmS != nullptr); + Real64 SchedValue = spmS->sched->getCurrentVal(); for (int ctrlNodeNum : spmS->ctrlNodeNums) { - auto &node = state.dataLoopNodes->Node(ctrlNodeNum); - Real64 SchedValue = spmS->sched->getCurrentVal(); // Initialize scheduled setpoints - switch (spmS->ctrlVar) { - case HVAC::CtrlVarType::Temp: { - node.TempSetPoint = SchedValue; - } break; - case HVAC::CtrlVarType::MaxTemp: { - node.TempSetPointHi = SchedValue; - } break; - case HVAC::CtrlVarType::MinTemp: { - node.TempSetPointLo = SchedValue; - } break; - case HVAC::CtrlVarType::HumRat: { - node.HumRatSetPoint = SchedValue; - } break; - case HVAC::CtrlVarType::MaxHumRat: { - node.HumRatMax = SchedValue; - } break; - case HVAC::CtrlVarType::MinHumRat: { - node.HumRatMin = SchedValue; - } break; - case HVAC::CtrlVarType::MassFlowRate: { - node.MassFlowRateSetPoint = SchedValue; - } break; - case HVAC::CtrlVarType::MaxMassFlowRate: { - node.MassFlowRateMax = SchedValue; - } break; - case HVAC::CtrlVarType::MinMassFlowRate: { - node.MassFlowRateMin = SchedValue; - } break; - default: - break; - } + applySetPointToNode(state.dataLoopNodes->Node(ctrlNodeNum), spmS->ctrlVar, SchedValue); } } break; @@ -2633,31 +2506,9 @@ void InitSetPointManagers(EnergyPlusData &state) case SPMType::SystemNodeTemp: case SPMType::SystemNodeHum: { + spm->calculate(state); for (int ctrlNodeNum : spm->ctrlNodeNums) { - auto &node = state.dataLoopNodes->Node(ctrlNodeNum); - spm->calculate(state); - switch (spm->ctrlVar) { - case HVAC::CtrlVarType::Temp: { - node.TempSetPoint = spm->setPt; - } break; - case HVAC::CtrlVarType::MaxTemp: { - node.TempSetPointHi = spm->setPt; - } break; - case HVAC::CtrlVarType::MinTemp: { - node.TempSetPointLo = spm->setPt; - } break; - case HVAC::CtrlVarType::HumRat: { - node.HumRatSetPoint = spm->setPt; - } break; - case HVAC::CtrlVarType::MaxHumRat: { - node.HumRatMax = spm->setPt; - } break; - case HVAC::CtrlVarType::MinHumRat: { - node.HumRatMin = spm->setPt; - } break; - default: - break; - } + applySetPointToNode(state.dataLoopNodes->Node(ctrlNodeNum), spm->ctrlVar, spm->setPt); } } break; @@ -4184,39 +4035,8 @@ void UpdateSetPointManagers(EnergyPlusData &state) case SPMType::SystemNodeTemp: case SPMType::SystemNodeHum: { for (int ctrlNodeNum : spm->ctrlNodeNums) { - auto &node = state.dataLoopNodes->Node(ctrlNodeNum); - switch (spm->ctrlVar) { // set the setpoint depending on the type of variable being controlled - case HVAC::CtrlVarType::Temp: { - node.TempSetPoint = spm->setPt; - } break; - case HVAC::CtrlVarType::MaxTemp: { - node.TempSetPointHi = spm->setPt; - } break; - case HVAC::CtrlVarType::MinTemp: { - node.TempSetPointLo = spm->setPt; - } break; - case HVAC::CtrlVarType::HumRat: { - node.HumRatSetPoint = spm->setPt; - } break; - case HVAC::CtrlVarType::MaxHumRat: { - node.HumRatMax = spm->setPt; - } break; - case HVAC::CtrlVarType::MinHumRat: { - node.HumRatMin = spm->setPt; - } break; - case HVAC::CtrlVarType::MassFlowRate: { - node.MassFlowRateSetPoint = spm->setPt; - } break; - case HVAC::CtrlVarType::MaxMassFlowRate: { - node.MassFlowRateMax = spm->setPt; - } break; - case HVAC::CtrlVarType::MinMassFlowRate: { - node.MassFlowRateMin = spm->setPt; - } break; - default: - break; - } + applySetPointToNode(state.dataLoopNodes->Node(ctrlNodeNum), spm->ctrlVar, spm->setPt); } // for (CtrlNodeNum) } break; diff --git a/src/EnergyPlus/SimAirServingZones.cc b/src/EnergyPlus/SimAirServingZones.cc index c8bcd45147f..b80171a4456 100644 --- a/src/EnergyPlus/SimAirServingZones.cc +++ b/src/EnergyPlus/SimAirServingZones.cc @@ -49,6 +49,8 @@ #include #include #include +#include +#include // ObjexxFCL Headers #include @@ -134,6 +136,128 @@ using namespace DataSizing; using namespace DataZoneEquipment; using namespace DataAirSystems; +// Local struct used by GetAirPathData for tracking unique node names across air loops. +struct AirUniqueNodes +{ + std::string NodeName; + std::string AirLoopName; + std::string FieldName; + bool NodeNameUsed = false; +}; + +// Check that a node name is unique across all air loops; register it if new, or report an error if duplicate. +static void checkUniqueAirNode(EnergyPlusData &state, + std::string_view RoutineName, + std::string_view CurrentModuleObject, + std::string const &airLoopName, + std::string const &nodeName, + std::string const &fieldName, + std::string_view duplicateSuffix, + Array1D &TestUniqueNodes, + bool &ErrorsFound) +{ + int test = Util::FindItemInList(nodeName, TestUniqueNodes, &AirUniqueNodes::NodeName, state.dataSimAirServingZones->TestUniqueNodesNum); + if (test == 0) { + ++state.dataSimAirServingZones->TestUniqueNodesNum; + auto &newNode = TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum); + newNode.NodeName = nodeName; + newNode.AirLoopName = airLoopName; + newNode.FieldName = fieldName; + newNode.NodeNameUsed = true; + } else { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", duplicate {}.", RoutineName, CurrentModuleObject, airLoopName, duplicateSuffix)); + ShowContinueError(state, EnergyPlus::format("...used for {}=\"{}\"", fieldName, nodeName)); + ShowContinueError( + state, + EnergyPlus::format( + "...first used in {}=\"{}\" for {}", CurrentModuleObject, TestUniqueNodes(test).AirLoopName, TestUniqueNodes(test).FieldName)); + ErrorsFound = true; + } +} + +// Lookup table mapping uppercased component type strings to CompType enum values. +// Only includes simple mapping entries; special cases (FAN:SYSTEMMODEL, UNITARYSYSTEM, +// COILSYSTEM:COOLING:WATER) are handled separately. +static const std::unordered_map airLoopCompTypeMap = { + {"AIRLOOPHVAC:OUTDOORAIRSYSTEM", CompType::OAMixer_Num}, + {"FAN:CONSTANTVOLUME", CompType::Fan_Simple_CV}, + {"FAN:VARIABLEVOLUME", CompType::Fan_Simple_VAV}, + {"FAN:COMPONENTMODEL", CompType::Fan_ComponentModel}, + {"COILSYSTEM:COOLING:WATER:HEATEXCHANGERASSISTED", CompType::WaterCoil_CoolingHXAsst}, + {"COIL:HEATING:WATER", CompType::WaterCoil_SimpleHeat}, + {"COIL:HEATING:STEAM", CompType::SteamCoil_AirHeat}, + {"COIL:COOLING:WATER:DETAILEDGEOMETRY", CompType::WaterCoil_DetailedCool}, + {"COIL:COOLING:WATER", CompType::WaterCoil_Cooling}, + {"COIL:HEATING:ELECTRIC", CompType::Coil_ElectricHeat}, + {"COIL:HEATING:FUEL", CompType::Coil_GasHeat}, + {"COIL:HEATING:DESUPERHEATER", CompType::Coil_DeSuperHeat}, + {"COILSYSTEM:COOLING:DX", CompType::DXSystem}, + {"COILSYSTEM:HEATING:DX", CompType::DXHeatPumpSystem}, + {"COIL:USERDEFINED", CompType::CoilUserDefined}, + {"AIRLOOPHVAC:UNITARY:FURNACE:HEATONLY", CompType::Furnace_UnitarySys_HeatOnly}, + {"AIRLOOPHVAC:UNITARY:FURNACE:HEATCOOL", CompType::Furnace_UnitarySys_HeatCool}, + {"AIRLOOPHVAC:UNITARYHEATONLY", CompType::Furnace_UnitarySys_HeatOnly}, + {"AIRLOOPHVAC:UNITARYHEATCOOL", CompType::Furnace_UnitarySys_HeatCool}, + {"AIRLOOPHVAC:UNITARYHEATPUMP:AIRTOAIR", CompType::Furnace_UnitarySys_HeatCool}, + {"AIRLOOPHVAC:UNITARYHEATPUMP:WATERTOAIR", CompType::Furnace_UnitarySys_HeatCool}, + {"AIRLOOPHVAC:UNITARYHEATCOOL:VAVCHANGEOVERBYPASS", CompType::UnitarySystem_BypassVAVSys}, + {"HUMIDIFIER:STEAM:ELECTRIC", CompType::Humidifier}, + {"HUMIDIFIER:STEAM:GAS", CompType::Humidifier}, + {"EVAPORATIVECOOLER:DIRECT:CELDEKPAD", CompType::EvapCooler}, + {"EVAPORATIVECOOLER:INDIRECT:CELDEKPAD", CompType::EvapCooler}, + {"EVAPORATIVECOOLER:INDIRECT:WETCOIL", CompType::EvapCooler}, + {"EVAPORATIVECOOLER:INDIRECT:RESEARCHSPECIAL", CompType::EvapCooler}, + {"EVAPORATIVECOOLER:DIRECT:RESEARCHSPECIAL", CompType::EvapCooler}, + {"DEHUMIDIFIER:DESICCANT:NOFANS", CompType::Desiccant}, + {"DEHUMIDIFIER:DESICCANT:SYSTEM", CompType::Desiccant}, + {"HEATEXCHANGER:AIRTOAIR:FLATPLATE", CompType::HeatXchngr}, + {"HEATEXCHANGER:AIRTOAIR:SENSIBLEANDLATENT", CompType::HeatXchngr}, + {"HEATEXCHANGER:DESICCANT:BALANCEDFLOW", CompType::HeatXchngr}, + {"DUCT", CompType::Duct}, + {"AIRLOOPHVAC:UNITARYHEATPUMP:AIRTOAIR:MULTISPEED", CompType::UnitarySystem_MSHeatPump}, + {"ZONEHVAC:TERMINALUNIT:VARIABLEREFRIGERANTFLOW", CompType::ZoneVRFasAirLoopEquip}, +}; + +// Component types that indicate a packaged unit on an air loop branch. +static const std::unordered_set packagedUnitCompTypes = { + "COILSYSTEM:COOLING:DX", + "COILSYSTEM:HEATING:DX", + "COILSYSTEM:COOLING:WATER", + "AIRLOOPHVAC:UNITARYSYSTEM", + "AIRLOOPHVAC:UNITARY:FURNACE:HEATONLY", + "AIRLOOPHVAC:UNITARY:FURNACE:HEATCOOL", + "AIRLOOPHVAC:UNITARYHEATONLY", + "AIRLOOPHVAC:UNITARYHEATCOOL", + "AIRLOOPHVAC:UNITARYHEATPUMP:AIRTOAIR", + "AIRLOOPHVAC:UNITARYHEATPUMP:WATERTOAIR", + "AIRLOOPHVAC:UNITARYHEATCOOL:VAVCHANGEOVERBYPASS", + "AIRLOOPHVAC:UNITARYHEATPUMP:AIRTOAIR:MULTISPEED", +}; + +// Component types that may only be referenced by a parent component (not directly on an air loop branch). +static constexpr std::array childOnlyCompTypes = { + "FAN:ONOFF", + "COIL:COOLING:DX:SINGLESPEED", + "COIL:HEATING:DX:SINGLESPEED", + "COIL:COOLING:DX:TWOSTAGEWITHHUMIDITYCONTROLMODE", + "COIL:COOLING:DX:MULTISPEED", + "COIL:HEATING:DX:MULTISPEED", +}; + +// Allocate and initialize controller arrays for a primary air system. +static void allocateControllerArrays(DataAirSystems::DefinePrimaryAirSystem &primaryAirSystems, int numControllers) +{ + primaryAirSystems.NumControllers = numControllers; + primaryAirSystems.ControllerName.allocate(numControllers); + primaryAirSystems.ControllerType.allocate(numControllers); + primaryAirSystems.ControllerIndex.allocate(numControllers); + primaryAirSystems.ControllerIndex = 0; + primaryAirSystems.ControlConverged.allocate(numControllers); + primaryAirSystems.ControlConverged = false; + primaryAirSystems.CanBeLockedOutByEcono.allocate(numControllers); + primaryAirSystems.CanBeLockedOutByEcono = false; +} + void ManageAirLoops(EnergyPlusData &state, bool const FirstHVACIteration, // TRUE if first full HVAC iteration in an HVAC timestep bool &SimAir, // TRUE means air loops must be (re)simulated @@ -340,20 +464,6 @@ void GetAirPathData(EnergyPlusData &state) int ActuatorNodeNum; // numeric equivalent for controller actuator node number Array1D_string MatchNodeName(3); - struct AirUniqueNodes - { - // Members - std::string NodeName; - std::string AirLoopName; - std::string FieldName; - bool NodeNameUsed; - - // Default Constructor - AirUniqueNodes() : NodeNameUsed(false) - { - } - }; - // Object Data Array1D TestUniqueNodes; @@ -496,73 +606,15 @@ void GetAirPathData(EnergyPlusData &state) } // work on unique nodes - test = Util::FindItemInList(Alphas(6), TestUniqueNodes, &AirUniqueNodes::NodeName, state.dataSimAirServingZones->TestUniqueNodesNum); - if (test == 0) { - ++state.dataSimAirServingZones->TestUniqueNodesNum; - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).NodeName = Alphas(6); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).AirLoopName = Alphas(1); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).FieldName = cAlphaFields(6); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).NodeNameUsed = true; - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", duplicate node name.", RoutineName, CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("...used for {}=\"{}\"", cAlphaFields(6), Alphas(6))); - ShowContinueError( - state, - EnergyPlus::format( - "...first used in {}=\"{}\" for {}", CurrentModuleObject, TestUniqueNodes(test).AirLoopName, TestUniqueNodes(test).FieldName)); - ErrorsFound = true; - } + checkUniqueAirNode(state, RoutineName, CurrentModuleObject, Alphas(1), Alphas(6), cAlphaFields(6), "node name", TestUniqueNodes, ErrorsFound); if (!lAlphaBlanks(7)) { - test = Util::FindItemInList(Alphas(7), TestUniqueNodes, &AirUniqueNodes::NodeName, state.dataSimAirServingZones->TestUniqueNodesNum); - if (test == 0) { - ++state.dataSimAirServingZones->TestUniqueNodesNum; - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).NodeName = Alphas(7); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).AirLoopName = Alphas(1); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).FieldName = cAlphaFields(7); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).NodeNameUsed = true; - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", duplicate node name.", RoutineName, CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("...used for {}=\"{}\"", cAlphaFields(7), Alphas(7))); - ShowContinueError(state, - EnergyPlus::format("...first used in {}=\"{}\" for {}", - CurrentModuleObject, - TestUniqueNodes(test).AirLoopName, - TestUniqueNodes(test).FieldName)); - ErrorsFound = true; - } - } - test = Util::FindItemInList(Alphas(8), TestUniqueNodes, &AirUniqueNodes::NodeName, state.dataSimAirServingZones->TestUniqueNodesNum); - if (test == 0) { - ++state.dataSimAirServingZones->TestUniqueNodesNum; - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).NodeName = Alphas(8); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).AirLoopName = Alphas(1); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).FieldName = cAlphaFields(8); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).NodeNameUsed = true; - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", duplicate node name/list.", RoutineName, CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("...used for {}=\"{}\"", cAlphaFields(8), Alphas(8))); - ShowContinueError( - state, - EnergyPlus::format( - "...first used in {}=\"{}\" for {}", CurrentModuleObject, TestUniqueNodes(test).AirLoopName, TestUniqueNodes(test).FieldName)); - ErrorsFound = true; - } - test = Util::FindItemInList(Alphas(9), TestUniqueNodes, &AirUniqueNodes::NodeName, state.dataSimAirServingZones->TestUniqueNodesNum); - if (test == 0) { - ++state.dataSimAirServingZones->TestUniqueNodesNum; - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).NodeName = Alphas(9); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).AirLoopName = Alphas(1); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).FieldName = cAlphaFields(9); - TestUniqueNodes(state.dataSimAirServingZones->TestUniqueNodesNum).NodeNameUsed = true; - } else { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", duplicate node name/list.", RoutineName, CurrentModuleObject, Alphas(1))); - ShowContinueError(state, EnergyPlus::format("...used for {}=\"{}\"", cAlphaFields(9), Alphas(9))); - ShowContinueError( - state, - EnergyPlus::format( - "...first used in {}=\"{}\" for {}", CurrentModuleObject, TestUniqueNodes(test).AirLoopName, TestUniqueNodes(test).FieldName)); - ErrorsFound = true; + checkUniqueAirNode( + state, RoutineName, CurrentModuleObject, Alphas(1), Alphas(7), cAlphaFields(7), "node name", TestUniqueNodes, ErrorsFound); } + checkUniqueAirNode( + state, RoutineName, CurrentModuleObject, Alphas(1), Alphas(8), cAlphaFields(8), "node name/list", TestUniqueNodes, ErrorsFound); + checkUniqueAirNode( + state, RoutineName, CurrentModuleObject, Alphas(1), Alphas(9), cAlphaFields(9), "node name/list", TestUniqueNodes, ErrorsFound); // this test depends on the controlled zone input having been "gotten" test = 0; for (count = 1; count <= state.dataZoneEquip->NumReturnAirPaths; ++count) { @@ -784,33 +836,8 @@ void GetAirPathData(EnergyPlusData &state) ErrorsFound = true; } } - { - std::string const componentType = uppercased(CompTypes(CompNum)); - if (componentType == "COILSYSTEM:COOLING:DX") { - PackagedUnit(AirSysNum) = true; - } else if (componentType == "COILSYSTEM:HEATING:DX") { - PackagedUnit(AirSysNum) = true; - } else if (componentType == "COILSYSTEM:COOLING:WATER") { - PackagedUnit(AirSysNum) = true; - } else if (componentType == "AIRLOOPHVAC:UNITARYSYSTEM") { - PackagedUnit(AirSysNum) = true; - } else if (componentType == "AIRLOOPHVAC:UNITARY:FURNACE:HEATONLY") { - PackagedUnit(AirSysNum) = true; - } else if (componentType == "AIRLOOPHVAC:UNITARY:FURNACE:HEATCOOL") { - PackagedUnit(AirSysNum) = true; - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATONLY") { - PackagedUnit(AirSysNum) = true; - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATCOOL") { - PackagedUnit(AirSysNum) = true; - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATPUMP:AIRTOAIR") { - PackagedUnit(AirSysNum) = true; - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATPUMP:WATERTOAIR") { - PackagedUnit(AirSysNum) = true; - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATCOOL:VAVCHANGEOVERBYPASS") { - PackagedUnit(AirSysNum) = true; - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATPUMP:AIRTOAIR:MULTISPEED") { - PackagedUnit(AirSysNum) = true; - } + if (packagedUnitCompTypes.count(uppercased(CompTypes(CompNum))) > 0) { + PackagedUnit(AirSysNum) = true; } } // end of component loop @@ -1037,13 +1064,7 @@ void GetAirPathData(EnergyPlusData &state) // Check the current controller list and if it matches input names NumControllers = (NumAlphas - 1) / 2; // Subtract off the controller list name first // store all the controller data - primaryAirSystems.NumControllers = NumControllers + NumOASysSimpControllers; - primaryAirSystems.ControllerName.allocate(NumControllers + NumOASysSimpControllers); - primaryAirSystems.ControllerType.allocate(NumControllers + NumOASysSimpControllers); - primaryAirSystems.ControllerIndex.allocate(NumControllers + NumOASysSimpControllers); - primaryAirSystems.ControllerIndex = 0; - primaryAirSystems.ControlConverged.allocate(NumControllers + NumOASysSimpControllers); - primaryAirSystems.CanBeLockedOutByEcono.allocate(NumControllers + NumOASysSimpControllers); + allocateControllerArrays(primaryAirSystems, NumControllers + NumOASysSimpControllers); for (ControllerNum = NumOASysSimpControllers + 1; ControllerNum <= NumOASysSimpControllers + NumControllers; ++ControllerNum) { ControllerName = Alphas((ControllerNum - NumOASysSimpControllers) * 2 + 1); ControllerType = Alphas((ControllerNum - NumOASysSimpControllers) * 2); @@ -1075,15 +1096,7 @@ void GetAirPathData(EnergyPlusData &state) state, "AirLoopHVAC:ControllerList", OASysContListNum, Alphas, NumAlphas, Numbers, NumNumbers, IOStat); // allocate air primary system controller lists if not already done if (NumControllers == 0) { - primaryAirSystems.NumControllers = NumOASysSimpControllers; - primaryAirSystems.ControllerName.allocate(NumOASysSimpControllers); - primaryAirSystems.ControllerType.allocate(NumOASysSimpControllers); - primaryAirSystems.ControllerIndex.allocate(NumOASysSimpControllers); - primaryAirSystems.ControllerIndex = 0; - primaryAirSystems.ControlConverged.allocate(NumOASysSimpControllers); - primaryAirSystems.CanBeLockedOutByEcono.allocate(NumOASysSimpControllers); - primaryAirSystems.ControlConverged = false; - primaryAirSystems.CanBeLockedOutByEcono = false; + allocateControllerArrays(primaryAirSystems, NumOASysSimpControllers); } // loop over the OA Sys controllers and move them up to the primary air system controller lists OASysControllerNum = 0; @@ -1148,11 +1161,7 @@ void GetAirPathData(EnergyPlusData &state) ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\" has no Controllers.", RoutineName, CurrentModuleObject, primaryAirSystems.Name)); } - primaryAirSystems.NumControllers = 0; - primaryAirSystems.ControllerName.allocate(0); - primaryAirSystems.ControllerType.allocate(0); - primaryAirSystems.ControlConverged.allocate(0); - primaryAirSystems.CanBeLockedOutByEcono.allocate(0); + allocateControllerArrays(primaryAirSystems, 0); } errFlag = false; @@ -1179,155 +1188,43 @@ void GetAirPathData(EnergyPlusData &state) for (CompNum = 1; CompNum <= primaryAirSystems.Branch(BranchNum).TotalComponents; ++CompNum) { { - std::string const componentType = uppercased(primaryAirSystems.Branch(BranchNum).Comp(CompNum).TypeOf); - - if (componentType == "AIRLOOPHVAC:OUTDOORAIRSYSTEM") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::OAMixer_Num; - - // Fan Types for the air sys simulation - } else if (componentType == "FAN:CONSTANTVOLUME") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Fan_Simple_CV; - - } else if (componentType == "FAN:VARIABLEVOLUME") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Fan_Simple_VAV; + auto &comp = primaryAirSystems.Branch(BranchNum).Comp(CompNum); + std::string const componentType = uppercased(comp.TypeOf); + auto it = airLoopCompTypeMap.find(componentType); + if (it != airLoopCompTypeMap.end()) { + comp.CompType_Num = it->second; } else if (componentType == "FAN:SYSTEMMODEL") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Fan_System_Object; - auto &comp = primaryAirSystems.Branch(BranchNum).Comp(CompNum); + comp.CompType_Num = CompType::Fan_System_Object; if (comp.CompIndex == 0) { comp.CompIndex = Fans::GetFanIndex(state, comp.Name); // TODO: get rid of this if (comp.CompIndex == 0) { ShowSevereError(state, EnergyPlus::format("Component {} of type {} not found.", comp.Name, comp.TypeOf)); } } - state.dataFans->fans(comp.CompIndex)->airPathFlag = true; - } else if (componentType == "FAN:COMPONENTMODEL") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Fan_ComponentModel; - - // Coil Types for the air sys simulation - // HX Assisted coils are not allowed on a branch at this time - // CASE('COILSYSTEM:COOLING:DX:HEATEXCHANGERASSISTED') - // PrimaryAirSystem(AirSysNum)%Branch(BranchNum)%Comp(CompNum)%CompType_Num=DXCoil_CoolingHXAsst - } else if (componentType == "COILSYSTEM:COOLING:WATER:HEATEXCHANGERASSISTED") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::WaterCoil_CoolingHXAsst; - } else if (componentType == "COIL:HEATING:WATER") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::WaterCoil_SimpleHeat; - } else if (componentType == "COIL:HEATING:STEAM") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::SteamCoil_AirHeat; - } else if (componentType == "COIL:COOLING:WATER:DETAILEDGEOMETRY") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::WaterCoil_DetailedCool; - } else if (componentType == "COIL:COOLING:WATER") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::WaterCoil_Cooling; - } else if (componentType == "COIL:HEATING:ELECTRIC") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Coil_ElectricHeat; - } else if (componentType == "COIL:HEATING:FUEL") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Coil_GasHeat; - - // Heat reclaim - } else if (componentType == "COIL:HEATING:DESUPERHEATER") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Coil_DeSuperHeat; - - } else if (componentType == "COILSYSTEM:COOLING:DX") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::DXSystem; - } else if (componentType == "COILSYSTEM:HEATING:DX") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::DXHeatPumpSystem; - } else if (componentType == "COIL:USERDEFINED") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::CoilUserDefined; } else if (componentType == "AIRLOOPHVAC:UNITARYSYSTEM") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::UnitarySystemModel; + comp.CompType_Num = CompType::UnitarySystemModel; UnitarySystems::UnitarySys thisSys; - primaryAirSystems.Branch(BranchNum).Comp(CompNum).compPointer = thisSys.factory( - state, HVAC::UnitarySysType::Unitary_AnyCoilType, primaryAirSystems.Branch(BranchNum).Comp(CompNum).Name, false, 0); + comp.compPointer = thisSys.factory(state, HVAC::UnitarySysType::Unitary_AnyCoilType, comp.Name, false, 0); } else if (componentType == "COILSYSTEM:COOLING:WATER") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::CoilSystemWater; + comp.CompType_Num = CompType::CoilSystemWater; UnitarySystems::UnitarySys thisSys; - primaryAirSystems.Branch(BranchNum).Comp(CompNum).compPointer = thisSys.factory( - state, HVAC::UnitarySysType::Unitary_AnyCoilType, primaryAirSystems.Branch(BranchNum).Comp(CompNum).Name, false, 0); - } else if (componentType == "AIRLOOPHVAC:UNITARY:FURNACE:HEATONLY") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Furnace_UnitarySys_HeatOnly; - } else if (componentType == "AIRLOOPHVAC:UNITARY:FURNACE:HEATCOOL") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Furnace_UnitarySys_HeatCool; - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATONLY") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Furnace_UnitarySys_HeatOnly; - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATCOOL") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Furnace_UnitarySys_HeatCool; - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATPUMP:AIRTOAIR") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Furnace_UnitarySys_HeatCool; - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATPUMP:WATERTOAIR") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Furnace_UnitarySys_HeatCool; - - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATCOOL:VAVCHANGEOVERBYPASS") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::UnitarySystem_BypassVAVSys; - - // Humidifier Types for the air system simulation - } else if (componentType == "HUMIDIFIER:STEAM:ELECTRIC") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Humidifier; - - } else if (componentType == "HUMIDIFIER:STEAM:GAS") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Humidifier; - - // Evap Cooler Types for the air system simulation - } else if (componentType == "EVAPORATIVECOOLER:DIRECT:CELDEKPAD") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::EvapCooler; - } else if (componentType == "EVAPORATIVECOOLER:INDIRECT:CELDEKPAD") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::EvapCooler; - } else if (componentType == "EVAPORATIVECOOLER:INDIRECT:WETCOIL") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::EvapCooler; - } else if (componentType == "EVAPORATIVECOOLER:INDIRECT:RESEARCHSPECIAL") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::EvapCooler; - } else if (componentType == "EVAPORATIVECOOLER:DIRECT:RESEARCHSPECIAL") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::EvapCooler; - - // Desiccant Dehumidifier Types for the air system simulation - } else if (componentType == "DEHUMIDIFIER:DESICCANT:NOFANS") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Desiccant; - } else if (componentType == "DEHUMIDIFIER:DESICCANT:SYSTEM") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Desiccant; - - // Heat recovery - } else if (componentType == "HEATEXCHANGER:AIRTOAIR:FLATPLATE") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::HeatXchngr; - - } else if (componentType == "HEATEXCHANGER:AIRTOAIR:SENSIBLEANDLATENT") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::HeatXchngr; - - } else if (componentType == "HEATEXCHANGER:DESICCANT:BALANCEDFLOW") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::HeatXchngr; - - // Ducts - } else if (componentType == "DUCT") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::Duct; - - } else if (componentType == "AIRLOOPHVAC:UNITARYHEATPUMP:AIRTOAIR:MULTISPEED") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::UnitarySystem_MSHeatPump; - - } else if (componentType == "ZONEHVAC:TERMINALUNIT:VARIABLEREFRIGERANTFLOW") { - primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num = CompType::ZoneVRFasAirLoopEquip; - - } else if (componentType == "FAN:ONOFF" || componentType == "COIL:COOLING:DX:SINGLESPEED" || - componentType == "COIL:HEATING:DX:SINGLESPEED" || componentType == "COIL:COOLING:DX:TWOSTAGEWITHHUMIDITYCONTROLMODE" || - componentType == "COIL:COOLING:DX:MULTISPEED" || componentType == "COIL:HEATING:DX:MULTISPEED") { - ShowSevereError(state, EnergyPlus::format("{}{} = \"{}\".", RoutineName, CurrentModuleObject, primaryAirSystems.Name)); - ShowContinueError(state, - EnergyPlus::format("..Invalid Air Loop Component Type = \"{}\".", - primaryAirSystems.Branch(BranchNum).Comp(CompNum).TypeOf)); - ShowContinueError( - state, EnergyPlus::format("..Air Loop Component Name = \"{}\".", primaryAirSystems.Branch(BranchNum).Comp(CompNum).Name)); - ShowContinueError(state, EnergyPlus::format("..reference Branch = \"{}\".", primaryAirSystems.Branch(BranchNum).Name)); - ShowContinueError(state, - "...This component may only be referenced by a parent component such as " - "AirLoopHVAC:Unitary:Furnace:HeatCool or similar."); - ErrorsFound = true; - + comp.compPointer = thisSys.factory(state, HVAC::UnitarySysType::Unitary_AnyCoilType, comp.Name, false, 0); } else { + // Check if this is a child-only component type + bool isChildOnly = std::any_of(childOnlyCompTypes.begin(), childOnlyCompTypes.end(), [&componentType](std::string_view s) { + return componentType == s; + }); ShowSevereError(state, EnergyPlus::format("{}{} = \"{}\".", RoutineName, CurrentModuleObject, primaryAirSystems.Name)); - ShowContinueError(state, - EnergyPlus::format("..Invalid Air Loop Component Type = \"{}\".", - primaryAirSystems.Branch(BranchNum).Comp(CompNum).TypeOf)); - ShowContinueError( - state, EnergyPlus::format("..Air Loop Component Name = \"{}\".", primaryAirSystems.Branch(BranchNum).Comp(CompNum).Name)); + ShowContinueError(state, EnergyPlus::format("..Invalid Air Loop Component Type = \"{}\".", comp.TypeOf)); + ShowContinueError(state, EnergyPlus::format("..Air Loop Component Name = \"{}\".", comp.Name)); ShowContinueError(state, EnergyPlus::format("..reference Branch = \"{}\".", primaryAirSystems.Branch(BranchNum).Name)); + if (isChildOnly) { + ShowContinueError(state, + "...This component may only be referenced by a parent component such as " + "AirLoopHVAC:Unitary:Furnace:HeatCool or similar."); + } ErrorsFound = true; } } @@ -5074,257 +4971,1213 @@ void SizeSysOutdoorAir(EnergyPlusData &state) // have moved std 62.1 table report writing to ManageSystemVentilationAdjustments in SizingManager } -void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIndicator) +// Compute zone ventilation efficiency (Evz) for Std 62.1 VRP or SP method. +// Used in the EndDay block of UpdateSysSizing for both cooling and heating modes. +// Returns the computed Evz value and updates Fa/Fb/Fc arrays and min-Evz tracker. +static Real64 calcZoneVentEfficiency(EnergyPlusData &state, + DataSizing::SystemSizingData const &finalSysSizing, + int TermUnitSizingIndex, + int AirLoopNum, + Real64 Xs, + bool isCooling, + Real64 &minEvz) { - - // SUBROUTINE INFORMATION: - // AUTHOR Fred Buhl - // DATE WRITTEN February 2001 - - // PURPOSE OF THIS SUBROUTINE: - // Update the result variables of the zone sizing calculation - - // METHODOLOGY EMPLOYED: - // CallIndicator = 1 (BeginDay) zero the result arrays - // CallIndicator = 2 (DuringDay) fill arrays, averaging over 1 zone time step - // CallIndicator = 3 (EndDay) calculate daily maxima - // CallIndicator = 5 (EndSysSizingCalc) write out results - - // Using/Aliasing - using EMSManager::ManageEMS; - using General::FindNumberInList; - using Psychrometrics::PsyCpAirFnW; - using Psychrometrics::PsyHFnTdbW; - using Psychrometrics::PsyRhoAirFnPbTdbW; - using namespace OutputReportPredefined; - using namespace DataSizing; - - // Locals - int numOfTimeStepInDay; // number of zone time steps in a day - - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - int AirLoopNum; // primary air system index - Real64 SysCoolRetTemp; // system cooling return temperature for a time step [C] - Real64 SysHeatRetTemp; // system heating return temperature for a time step [C] - Real64 RhoAir; // density of air kg/m3 - Real64 OutAirFrac; // outside air fraction - Real64 SysCoolMixTemp; // system cooling mixed air temperature [C] - Real64 SysHeatMixTemp; // system heating mixed air temperature [C] - Real64 SysSensCoolCap; // system sensible cooling capacity [W] - Real64 SysTotCoolCap; // system total cooling capacity [W] - Real64 SysCoolZoneAvgTemp; // system cooling zone average temperature [C] - Real64 SysHeatZoneAvgTemp; // system heating zone average temperature [C] - Real64 SysHeatCap; // system heating capacity [W] - Real64 OutAirTemp; // outside air temperature - Real64 OutAirHumRat; // outside air humifity ratio - Real64 SysCoolMixHumRat; // system cooling mixed air humidity ratio [kg water/kg dry air] - Real64 SysCoolRetHumRat; // system coolingreturn air humifity ratio [kg water/kg dry air] - Real64 SysHeatMixHumRat; // system heating mixed air humidity ratio [kg water/kg dry air] - Real64 SysHeatRetHumRat; // system heatingreturn air humifity ratio [kg water/kg dry air] - Real64 SysCoolOutTemp; // system cooling outside air temperature [C] - Real64 SysCoolOutHumRat; // system cooling outside air humidity ratio [kg water/kg dry air] - Real64 SysHeatOutTemp; // system heating outside air temperature [C] - Real64 SysHeatOutHumRat; // system heating outside air humidity ratio [kg water/kg dry air] - Real64 SysDOASHeatAdd; // system DOAS heat addition rate [W] - Real64 SysDOASLatAdd; // system DOAS latent heat addition rate [W] - Real64 SysCoolSizingRat; // ratio of user input design flow for cooling divided by calculated design cooling flow - Real64 SysHeatSizingRat; // ratio of user input design flow for heating divided by calculated design heating flow - Real64 ZoneOARatio; // ratio of zone OA flow to zone design cooling or heating flow - Real64 RetTempRise; // difference between zone return temperature and zone temperature [delta K] - Real64 SysCoolingEv; // System level ventilation effectiveness for cooling mode - Real64 SysHeatingEv; // System level ventilation effectiveness for heating mode - Real64 SysHtgPeakAirflow; // Peak heating airflow - Real64 termunitsizingtempfrac; // 1.0/(1.0+termunitsizing(ctrlzone)%inducrat) - Real64 termunitsizingtemp; // (1.0+termunitsizing(ctrlzone)%inducrat) - Real64 VozClg(0.0); // corrected (for ventilation efficiency) zone outside air flow rate [m3/s] - - numOfTimeStepInDay = state.dataGlobal->TimeStepsInHour * Constant::iHoursInDay; - - // allocate scratch arrays - if (!allocated(state.dataSize->SensCoolCapTemp)) { - state.dataSize->SensCoolCapTemp.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); - state.dataSize->TotCoolCapTemp.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); + auto const &tzFinalSizing = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex); + Real64 Er = tzFinalSizing.ZoneSecondaryRecirculation; + Real64 Ep = isCooling ? tzFinalSizing.ZonePrimaryAirFraction : tzFinalSizing.ZonePrimaryAirFractionHtg; + Real64 ZoneOAFrac = isCooling ? tzFinalSizing.ZpzClgByZone : tzFinalSizing.ZpzHtgByZone; + Real64 ZoneEz = isCooling ? tzFinalSizing.ZoneADEffCooling : tzFinalSizing.ZoneADEffHeating; + + Real64 Evz = 1.0; + + if (finalSysSizing.SystemOAMethod == DataSizing::SysOAMethod::SP) { + // ASHRAE 62.1 simplified procedure + if (state.dataSize->DBySys(AirLoopNum) < 0.60) { + Evz = 0.88 * state.dataSize->DBySys(AirLoopNum) + 0.22; + } else { + Evz = 0.75; + } + if (isCooling) { + state.dataSize->EvzByZoneCool(TermUnitSizingIndex) = Evz; + } else { + state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = Evz; + } + minEvz = Evz; + } else { + // VRP method + if (Er > 0.0) { + // multi-path ventilation system + Real64 Fa = Ep + (1.0 - Ep) * Er; + Real64 Fb = Ep; + Real64 Fc = 1.0 - (1.0 - ZoneEz) * (1.0 - Er) * (1.0 - Ep); + if (isCooling) { + state.dataSize->FaByZoneCool(TermUnitSizingIndex) = Fa; + state.dataSize->FbByZoneCool(TermUnitSizingIndex) = Fb; + state.dataSize->FcByZoneCool(TermUnitSizingIndex) = Fc; + } else { + state.dataSize->FaByZoneHeat(TermUnitSizingIndex) = Fa; + state.dataSize->FbByZoneHeat(TermUnitSizingIndex) = Fb; + state.dataSize->FcByZoneHeat(TermUnitSizingIndex) = Fc; + } + if (Fa > 0.0) { + Evz = 1.0 + Xs * Fb / Fa - ZoneOAFrac * Ep * Fc / Fa; + } else { + Evz = 1.0; + } + } else { + // single-path ventilation system + Evz = 1.0 + Xs - ZoneOAFrac; + if (isCooling) { + Real64 VozClg = tzFinalSizing.VozClgByZone; + LimitZoneVentEff(state, Xs, VozClg, TermUnitSizingIndex, Evz); + } + } + if (Evz < minEvz) { + minEvz = Evz; + } + if (isCooling) { + state.dataSize->EvzByZoneCoolPrev(TermUnitSizingIndex) = state.dataSize->EvzByZoneCool(TermUnitSizingIndex); + state.dataSize->EvzByZoneCool(TermUnitSizingIndex) = Evz; + } else { + state.dataSize->EvzByZoneHeatPrev(TermUnitSizingIndex) = state.dataSize->EvzByZoneHeat(TermUnitSizingIndex); + state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = Evz; + } } + return Evz; +} - // allocate arrays used to store values for standard 62.1 tabular report - if (!allocated(state.dataSize->FaByZoneCool)) { - state.dataSize->FaByZoneCool.dimension(state.dataSize->NumAirTerminalUnits, 0.0); - state.dataSize->FaByZoneHeat.dimension(state.dataSize->NumAirTerminalUnits, 0.0); - state.dataSize->FbByZoneCool.dimension(state.dataSize->NumAirTerminalUnits, 0.0); - state.dataSize->FbByZoneHeat.dimension(state.dataSize->NumAirTerminalUnits, 0.0); - state.dataSize->FcByZoneCool.dimension(state.dataSize->NumAirTerminalUnits, 0.0); - state.dataSize->FcByZoneHeat.dimension(state.dataSize->NumAirTerminalUnits, 0.0); - state.dataSimAirServingZones->EvBySysCool.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); - state.dataSimAirServingZones->EvBySysHeat.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); - state.dataSize->XsBySysCool.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); - state.dataSize->XsBySysHeat.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); - state.dataSize->EvzByZoneCool.dimension(state.dataSize->NumAirTerminalUnits, 1.0); - state.dataSize->EvzByZoneCoolPrev.dimension(state.dataSize->NumAirTerminalUnits, 1.0); - state.dataSize->EvzByZoneHeat.dimension(state.dataSize->NumAirTerminalUnits, 1.0); - state.dataSize->EvzByZoneHeatPrev.dimension(state.dataSize->NumAirTerminalUnits, 1.0); - state.dataSize->EvzMinBySysCool.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); - state.dataSize->EvzMinBySysHeat.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); - state.dataSize->VotClgBySys.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); - state.dataSize->VotHtgBySys.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); - state.dataSize->VozSumClgBySys.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); - state.dataSize->VozSumHtgBySys.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); +// Compute the cooling VRP/SP ventilation efficiency and update system-level Vot. +// Shared between Coincident and NonCoincident sizing in the EndDay block of UpdateSysSizing. +// Assumes sysSizing.DesCoolVolFlow has already been set by the caller. +static void updateCoolVRPEvzVot(EnergyPlusData &state, + DataSizing::SystemSizingData &sysSizing, + DataSizing::SystemSizingData const &finalSysSizing, + int AirLoopNum) +{ + Real64 OutAirFrac; + if (sysSizing.DesCoolVolFlow > 0) { + OutAirFrac = sysSizing.DesOutAirVolFlow / sysSizing.DesCoolVolFlow; + } else { + OutAirFrac = 0.0; + } + OutAirFrac = min(1.0, max(0.0, OutAirFrac)); + if (sysSizing.DesCoolVolFlow > 0) { + state.dataSimAirServingZones->Xs = min(1.0, finalSysSizing.SysUncOA / sysSizing.DesCoolVolFlow); + } else { + state.dataSimAirServingZones->Xs = 0.0; } + if (finalSysSizing.OAAutoSized && sysSizing.DesCoolVolFlow > 0) { + int numZonesCooled = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled; + state.dataSimAirServingZones->MinCoolingEvz = 1.0; + state.dataSize->VozSumClgBySys(AirLoopNum) = 0.0; + for (int ZonesCooledNum = 1; ZonesCooledNum <= numZonesCooled; ++ZonesCooledNum) { + int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); + + calcZoneVentEfficiency(state, + finalSysSizing, + TermUnitSizingIndex, + AirLoopNum, + state.dataSimAirServingZones->Xs, + true, + state.dataSimAirServingZones->MinCoolingEvz); + state.dataSize->VozSumClgBySys(AirLoopNum) += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).VozClgByZone; + } - switch (CallIndicator) { - case Constant::CallIndicator::BeginDay: { - // Correct the zone return temperature in ZoneSizing for the case of induction units. The calc in - // ZoneEquipmentManager assumes all the air entering the zone goes into the return node. - for (int CtrlZoneNum = 1; CtrlZoneNum <= state.dataGlobal->NumOfZones; ++CtrlZoneNum) { - auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum); - auto &zoneSizing = state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum); - if (!zoneEquipConfig.IsControlled) { - continue; - } - // Use first non-zero airdistunit for now - int TermUnitSizingIndex = 0; - for (int InletNode = 1; InletNode <= zoneEquipConfig.NumInletNodes; ++InletNode) { - TermUnitSizingIndex = zoneEquipConfig.AirDistUnitCool(InletNode).TermUnitSizingIndex; - if (TermUnitSizingIndex == 0) { - continue; - } - termunitsizingtemp = (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); - termunitsizingtempfrac = (1.0 / termunitsizingtemp); - if (TermUnitSizingIndex > 0) { - break; + if (state.dataSimAirServingZones->MinCoolingEvz > 0) { + state.dataSimAirServingZones->Vou = finalSysSizing.SysUncOA; + state.dataSimAirServingZones->Vot = state.dataSimAirServingZones->Vou / state.dataSimAirServingZones->MinCoolingEvz; + if (state.dataSimAirServingZones->Vot > state.dataSize->VotClgBySys(AirLoopNum)) { + state.dataSize->VotClgBySys(AirLoopNum) = state.dataSimAirServingZones->Vot; + state.dataSize->XsBySysCool(AirLoopNum) = state.dataSimAirServingZones->Xs; + state.dataSize->EvzMinBySysCool(AirLoopNum) = state.dataSimAirServingZones->MinCoolingEvz; + } else { + for (int ZonesCooledNum = 1; ZonesCooledNum <= numZonesCooled; ++ZonesCooledNum) { + int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); + state.dataSize->EvzByZoneCool(TermUnitSizingIndex) = state.dataSize->EvzByZoneCoolPrev(TermUnitSizingIndex); } } - if (TermUnitSizingIndex == 0) { - continue; // Skip this if there are no terminal units - } - RetTempRise = zoneSizing.ZoneRetTempAtCoolPeak - zoneSizing.ZoneTempAtCoolPeak; - if (RetTempRise > 0.01) { - zoneSizing.ZoneRetTempAtCoolPeak = zoneSizing.ZoneTempAtCoolPeak + RetTempRise * termunitsizingtempfrac; - } - RetTempRise = zoneSizing.ZoneRetTempAtHeatPeak - zoneSizing.ZoneTempAtHeatPeak; - if (RetTempRise > 0.01) { - zoneSizing.ZoneRetTempAtHeatPeak = zoneSizing.ZoneTempAtHeatPeak + RetTempRise * termunitsizingtempfrac; - } } + } +} - for (AirLoopNum = 1; AirLoopNum <= state.dataHVACGlobal->NumPrimaryAirSys; ++AirLoopNum) { // start of begin day loop over primary air systems - auto &airToZoneNodeInfo = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum); - int NumZonesCooled = airToZoneNodeInfo.NumZonesCooled; - int NumZonesHeated = airToZoneNodeInfo.NumZonesHeated; - state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum).CoolDesDay = state.dataEnvrn->EnvironmentName; - state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum).HeatDesDay = state.dataEnvrn->EnvironmentName; - state.dataSize->SensCoolCapTemp(AirLoopNum) = 0.0; - state.dataSize->TotCoolCapTemp(AirLoopNum) = 0.0; - - for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { // loop over cooled zones - int CtrlZoneNum = airToZoneNodeInfo.CoolCtrlZoneNums(ZonesCooledNum); - int TermUnitSizingIndex = airToZoneNodeInfo.TermUnitCoolSizingIndex(ZonesCooledNum); - Real64 adjCoolMassFlow = - state.dataSize->TermUnitSizing(TermUnitSizingIndex) - .applyTermUnitSizingCoolFlow(state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum).DesCoolMassFlow, - state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum).DesCoolMassFlowNoOA); - state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum).NonCoinCoolMassFlow += - adjCoolMassFlow / (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); - if (state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum).loadSizingType == DataSizing::LoadSizing::Latent && - !state.dataSize->FinalZoneSizing.empty()) { - if (!state.dataSize->FinalZoneSizing(CtrlZoneNum).zoneLatentSizing && state.dataSize->CurOverallSimDay == 1) { - ShowWarningError( - state, - EnergyPlus::format("Latent Sizing for AirLoop = {} requires latent sizing in Sizing:Zone object for Zone = {}", - airToZoneNodeInfo.AirLoopName, - state.dataSize->FinalZoneSizing(CtrlZoneNum).ZoneName)); - } - } else if (!state.dataSize->FinalZoneSizing.empty()) { // not latent sizing for air loop - if (state.dataSize->FinalZoneSizing(CtrlZoneNum).zoneLatentSizing && state.dataSize->CurOverallSimDay == 1 && - state.dataSize->FinalZoneSizing(CtrlZoneNum).heatCoilSizingMethod == DataSizing::HeatCoilSizMethod::None) { - ShowWarningError(state, - EnergyPlus::format("Sizing for AirLoop = {} includes latent sizing in Sizing:Zone object for Zone = {}", - airToZoneNodeInfo.AirLoopName, - state.dataSize->FinalZoneSizing(CtrlZoneNum).ZoneName)); - } +// Update the heating system-level Vot based on MinHeatingEvz, and restore EvzByZoneHeat +// if the current design day did not produce the highest Vot. +// Shared between Coincident and NonCoincident sizing in the EndDay block of UpdateSysSizing. +static void +updateHeatVRPVot(EnergyPlusData &state, DataSizing::SystemSizingData const &finalSysSizing, int AirLoopNum, int numZonesHeated, int NumZonesCooled) +{ + if (state.dataSimAirServingZones->MinHeatingEvz > 0) { + state.dataSimAirServingZones->Vou = finalSysSizing.SysUncOA; + state.dataSimAirServingZones->Vot = state.dataSimAirServingZones->Vou / state.dataSimAirServingZones->MinHeatingEvz; + if (state.dataSimAirServingZones->Vot > state.dataSize->VotHtgBySys(AirLoopNum)) { + state.dataSize->VotHtgBySys(AirLoopNum) = state.dataSimAirServingZones->Vot; + state.dataSize->XsBySysHeat(AirLoopNum) = state.dataSimAirServingZones->Xs; + state.dataSize->EvzMinBySysHeat(AirLoopNum) = state.dataSimAirServingZones->MinHeatingEvz; + } else { + // Restore EvzByZoneHeat() since it was reset by the current (but not highest Vot) design day + if (numZonesHeated > 0) { + for (int ZonesHeatedNum = 1; ZonesHeatedNum <= numZonesHeated; ++ZonesHeatedNum) { + int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex(ZonesHeatedNum); + state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = state.dataSize->EvzByZoneHeatPrev(TermUnitSizingIndex); } - } // end of loop over cooled zones + } else { + for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesCooled; ++ZonesHeatedNum) { + int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesHeatedNum); + state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = state.dataSize->EvzByZoneHeatPrev(TermUnitSizingIndex); + } + } + } + } +} - if (NumZonesHeated > 0) { // if there are zones supplied with central hot air - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesHeated; ++ZonesHeatedNum) { // loop over heated zones - int CtrlZoneNum = airToZoneNodeInfo.HeatCtrlZoneNums(ZonesHeatedNum); - int TermUnitSizingIndex = airToZoneNodeInfo.TermUnitHeatSizingIndex(ZonesHeatedNum); - Real64 adjHeatMassFlow = state.dataSize->TermUnitSizing(TermUnitSizingIndex) - .applyTermUnitSizingHeatFlow( - state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum).DesHeatMassFlow, - state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum).DesHeatMassFlowNoOA); - state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum).NonCoinHeatMassFlow += - adjHeatMassFlow / (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); - } // end of loop over heated zones - } else { // otherwise use cool supply zones - for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { // loop over cooled zones - int CtrlZoneNum = airToZoneNodeInfo.CoolCtrlZoneNums(ZonesCooledNum); - int TermUnitSizingIndex = airToZoneNodeInfo.TermUnitCoolSizingIndex(ZonesCooledNum); - Real64 adjHeatMassFlow = state.dataSize->TermUnitSizing(TermUnitSizingIndex) - .applyTermUnitSizingHeatFlow( - state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum).DesHeatMassFlow, - state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum).DesHeatMassFlowNoOA); - state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum).NonCoinHeatMassFlow += - adjHeatMassFlow / (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); - } // end of loop over cooled zones - } // End of heat / cool zone if - else +// Update EvzMinBySysCool and EvzMinBySysHeat by scanning zone AD efficiencies +// for the given set of terminal unit sizing indices. Used in the ZoneSum branches +// of both Coincident and NonCoincident sizing in UpdateSysSizing EndDay. +static void updateMinADEffBySys(EnergyPlusData &state, Array1D_int const &termUnitSizingIndices, int numZones, int AirLoopNum) +{ + for (int zoneNum = 1; zoneNum <= numZones; ++zoneNum) { + int TermUnitSizingIndex = termUnitSizingIndices(zoneNum); + auto const &tzFinalSizing = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex); + if (tzFinalSizing.ZoneADEffCooling < state.dataSize->EvzMinBySysCool(AirLoopNum)) { + state.dataSize->EvzMinBySysCool(AirLoopNum) = tzFinalSizing.ZoneADEffCooling; + } + if (tzFinalSizing.ZoneADEffHeating < state.dataSize->EvzMinBySysHeat(AirLoopNum)) { + state.dataSize->EvzMinBySysHeat(AirLoopNum) = tzFinalSizing.ZoneADEffHeating; + } + } +} - } // End of begin day loop over primary air systems - } break; - case Constant::CallIndicator::DuringDay: { - int TimeStepInDay; // zone time step in day - TimeStepInDay = (state.dataGlobal->HourOfDay - 1) * state.dataGlobal->TimeStepsInHour + - state.dataGlobal->TimeStep; // calculate current zone time step index +// Accumulate NonCoinHeatMassFlow for the BeginDay block of UpdateSysSizing. +// Loops over the given zone index arrays (heated or cooled zones) and sums the +// adjusted heating mass flow into sysSizing.NonCoinHeatMassFlow. +static void accumulateBeginDayNonCoinHeatMassFlow(EnergyPlusData &state, + DataSizing::SystemSizingData &sysSizing, + int numZones, + Array1D_int const &ctrlZoneNums, + Array1D_int const &termUnitSizingIndices) +{ + for (int zoneNum = 1; zoneNum <= numZones; ++zoneNum) { + int CtrlZoneNum = ctrlZoneNums(zoneNum); + int TermUnitSizingIndex = termUnitSizingIndices(zoneNum); + Real64 adjHeatMassFlow = + state.dataSize->TermUnitSizing(TermUnitSizingIndex) + .applyTermUnitSizingHeatFlow(state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum).DesHeatMassFlow, + state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum).DesHeatMassFlowNoOA); + sysSizing.NonCoinHeatMassFlow += adjHeatMassFlow / (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); + } +} - // Correct the zone return temperature in ZoneSizing for the case of induction units. The calc in - // ZoneEquipmentManager assumes all the air entering the zone goes into the return node. - for (int CtrlZoneNum = 1; CtrlZoneNum <= state.dataGlobal->NumOfZones; ++CtrlZoneNum) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).IsControlled) { +// Compute heating ventilation efficiency and accumulate VozSumHtg for the given zones. +// When coolSizingIndices is non-null, zones that match a cooled zone are skipped +// (used for the heated-zones path where matching cooled zones were already handled). +static void computeHeatVentEffAndVozSum(EnergyPlusData &state, + DataSizing::SystemSizingData const &finalSysSizing, + int AirLoopNum, + int numZones, + Array1D_int const &termUnitSizingIndices, + int NumZonesCooled, + Array1D_int const *coolSizingIndices) +{ + for (int zoneNum = 1; zoneNum <= numZones; ++zoneNum) { + int TermUnitSizingIndex = termUnitSizingIndices(zoneNum); + if (coolSizingIndices != nullptr) { + int MatchingCooledZoneNum = General::FindNumberInList(TermUnitSizingIndex, *coolSizingIndices, NumZonesCooled); + if (MatchingCooledZoneNum != 0) { continue; } - // Use first non-zero airdistunit for now, if there is one - termunitsizingtempfrac = 1.0; - int TermUnitSizingIndex = 0; - for (int InletNode = 1; InletNode <= state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).NumInletNodes; ++InletNode) { - TermUnitSizingIndex = state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).AirDistUnitCool(InletNode).TermUnitSizingIndex; - if (TermUnitSizingIndex == 0) { - continue; - } - termunitsizingtemp = (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); - termunitsizingtempfrac = (1.0 / termunitsizingtemp); - if (TermUnitSizingIndex > 0) { - break; - } - } - if (TermUnitSizingIndex == 0) { - continue; // Skip this if there are no terminal units - } - auto &zoneSizing = state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum); - RetTempRise = zoneSizing.CoolZoneRetTempSeq(TimeStepInDay) - zoneSizing.CoolZoneTempSeq(TimeStepInDay); - if (RetTempRise > 0.01) { - zoneSizing.CoolZoneRetTempSeq(TimeStepInDay) = zoneSizing.CoolZoneTempSeq(TimeStepInDay) + RetTempRise * termunitsizingtempfrac; - } - RetTempRise = zoneSizing.HeatZoneRetTempSeq(TimeStepInDay) - zoneSizing.HeatZoneTempSeq(TimeStepInDay); - if (RetTempRise > 0.01) { - zoneSizing.HeatZoneRetTempSeq(TimeStepInDay) = zoneSizing.HeatZoneTempSeq(TimeStepInDay) + RetTempRise * termunitsizingtempfrac; - } } - // start of zone time step loop over primary air systems - for (AirLoopNum = 1; AirLoopNum <= state.dataHVACGlobal->NumPrimaryAirSys; ++AirLoopNum) { + calcZoneVentEfficiency(state, + finalSysSizing, + TermUnitSizingIndex, + AirLoopNum, + state.dataSimAirServingZones->Xs, + false, + state.dataSimAirServingZones->MinHeatingEvz); + state.dataSize->VozSumHtgBySys(AirLoopNum) += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).VozHtgByZone; + } +} - int NumZonesCooled = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled; - int NumZonesHeated = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated; +// Sum DesHeatVolFlow across the given terminal unit sizing indices. +static Real64 sumDesHeatVolFlow(EnergyPlusData &state, int numZones, Array1D_int const &termUnitSizingIndices) +{ + Real64 total = 0.0; + for (int zoneNum = 1; zoneNum <= numZones; ++zoneNum) { + total += state.dataSize->TermUnitFinalZoneSizing(termUnitSizingIndices(zoneNum)).DesHeatVolFlow; + } + return total; +} - SysCoolRetTemp = 0.0; - OutAirFrac = 0.0; - SysCoolMixTemp = 0.0; - SysSensCoolCap = 0.0; - SysCoolRetHumRat = 0.0; - SysCoolMixHumRat = 0.0; - SysCoolZoneAvgTemp = 0.0; - SysHeatZoneAvgTemp = 0.0; - SysTotCoolCap = 0.0; - SysDOASHeatAdd = 0.0; - SysDOASLatAdd = 0.0; +// Scale zone heating flows in EndSysSizingCalc when SysHeatSizingRat != 1. +// Loops over the given zone index array and applies ventilation-load or user-input sizing. +// When warnOnMissingOA is true (cooled-zones fallback path), a warning is emitted for zones +// with no design OA flow. +static void scaleZoneHeatFlows(EnergyPlusData &state, + DataSizing::SystemSizingData const &finalSysSizing, + int AirLoopNum, + int numZones, + Array1D_int const &termUnitSizingIndices, + Real64 SysHeatSizingRat, + bool warnOnMissingOA) +{ + for (int zoneNum = 1; zoneNum <= numZones; ++zoneNum) { + int TermUnitSizingIndex = termUnitSizingIndices(zoneNum); + auto &termUnitFinalZoneSizing = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex); + if (warnOnMissingOA && (SysHeatSizingRat != 1.0) && (finalSysSizing.loadSizingType == DataSizing::LoadSizing::Ventilation) && + (termUnitFinalZoneSizing.MinOA <= 0.0)) { + ShowWarningError(state, + EnergyPlus::format("FinalSystemSizing: AirLoop=\"{}\", Requested sizing on Ventilation,", + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).AirLoopName)); + ShowContinueError(state, EnergyPlus::format("but Zone has no design OA Flow. Zone=\"{}\".", termUnitFinalZoneSizing.ZoneName)); + } + if ((SysHeatSizingRat != 1.0) && (finalSysSizing.loadSizingType == DataSizing::LoadSizing::Ventilation) && + (termUnitFinalZoneSizing.MinOA > 0.0)) { + // size on ventilation load + Real64 ZoneOARatio = termUnitFinalZoneSizing.MinOA / max(termUnitFinalZoneSizing.DesHeatVolFlow, termUnitFinalZoneSizing.MinOA); + ZoneOARatio *= (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); + termUnitFinalZoneSizing.scaleZoneHeating(ZoneOARatio); + } else if ((SysHeatSizingRat > 1.0) || + (SysHeatSizingRat < 1.0 && finalSysSizing.SizingOption == DataSizing::SizingConcurrence::NonCoincident)) { + // size on user input system design flows + termUnitFinalZoneSizing.scaleZoneHeating(SysHeatSizingRat); + } + } +} + +// Compute design volume flows from mass flows and update Vot/Xs for ZoneSum OA method. +// Shared between Coincident and NonCoincident sizing in the EndDay block of UpdateSysSizing. +static void updateZoneSumVolFlows(EnergyPlusData &state, + DataSizing::SystemSizingData &sysSizing, + DataSizing::SystemSizingData const &finalSysSizing, + int AirLoopNum, + int NumZonesCooled, + int NumZonesHeated, + Real64 coolMassFlow, + Real64 heatMassFlow) +{ + sysSizing.DesCoolVolFlow = coolMassFlow / state.dataEnvrn->StdRhoAir; + sysSizing.DesHeatVolFlow = heatMassFlow / state.dataEnvrn->StdRhoAir; + state.dataSize->VotClgBySys(AirLoopNum) = finalSysSizing.SysUncOA; + state.dataSize->VotHtgBySys(AirLoopNum) = finalSysSizing.SysUncOA; + updateMinADEffBySys(state, state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex, NumZonesCooled, AirLoopNum); + updateMinADEffBySys(state, state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex, NumZonesHeated, AirLoopNum); + if (sysSizing.DesCoolVolFlow > 0) { + state.dataSize->XsBySysCool(AirLoopNum) = min(1.0, finalSysSizing.SysUncOA / sysSizing.DesCoolVolFlow); + } else { + state.dataSize->XsBySysCool(AirLoopNum) = 0.0; + } + if (sysSizing.DesHeatVolFlow > 0) { + state.dataSize->XsBySysHeat(AirLoopNum) = min(1.0, finalSysSizing.SysUncOA / sysSizing.DesHeatVolFlow); + } else { + state.dataSize->XsBySysHeat(AirLoopNum) = 0.0; + } +} + +// Copy cooling peak design data from a per-design-day SysSizing record into CalcSysSizing. +// Used in EndSysSizingCalc to pick the peak across all design days for both sensible and total cooling. +static void copyCoolPeakToCalcSysSizing(DataSizing::SystemSizingData &calcSS, DataSizing::SystemSizingData const &srcSS) +{ + calcSS.DesCoolVolFlow = srcSS.DesCoolVolFlow; + calcSS.CoolDesDay = srcSS.CoolDesDay; + calcSS.MassFlowAtCoolPeak = srcSS.MassFlowAtCoolPeak; + calcSS.SensCoolCap = srcSS.SensCoolCap; + calcSS.TotCoolCap = srcSS.TotCoolCap; + calcSS.CoolFlowSeq = srcSS.CoolFlowSeq; + calcSS.SumZoneCoolLoadSeq = srcSS.SumZoneCoolLoadSeq; + calcSS.CoolZoneAvgTempSeq = srcSS.CoolZoneAvgTempSeq; + calcSS.SensCoolCapSeq = srcSS.SensCoolCapSeq; + calcSS.TotCoolCapSeq = srcSS.TotCoolCapSeq; + calcSS.MixTempAtCoolPeak = srcSS.MixTempAtCoolPeak; + calcSS.RetTempAtCoolPeak = srcSS.RetTempAtCoolPeak; + calcSS.MixHumRatAtCoolPeak = srcSS.MixHumRatAtCoolPeak; + calcSS.RetHumRatAtCoolPeak = srcSS.RetHumRatAtCoolPeak; + calcSS.OutTempAtCoolPeak = srcSS.OutTempAtCoolPeak; + calcSS.OutHumRatAtCoolPeak = srcSS.OutHumRatAtCoolPeak; + calcSS.SysCoolRetTempSeq = srcSS.SysCoolRetTempSeq; + calcSS.SysCoolRetHumRatSeq = srcSS.SysCoolRetHumRatSeq; + calcSS.SysCoolOutTempSeq = srcSS.SysCoolOutTempSeq; + calcSS.SysCoolOutHumRatSeq = srcSS.SysCoolOutHumRatSeq; + calcSS.SysDOASHeatAddSeq = srcSS.SysDOASHeatAddSeq; + calcSS.SysDOASLatAddSeq = srcSS.SysDOASLatAddSeq; + calcSS.SysDesCoolLoad = srcSS.SysDesCoolLoad; + calcSS.SysCoolLoadTimeStepPk = srcSS.SysCoolLoadTimeStepPk; +} + +// Copy heating peak fields from a per-design-day SysSizing record into CalcSysSizing. +// Mirrors copyCoolPeakToCalcSysSizing but for the heating side. +static void copyHeatPeakToCalcSysSizing(DataSizing::SystemSizingData &calcSS, DataSizing::SystemSizingData const &srcSS, int DDNum) +{ + calcSS.DesHeatVolFlow = srcSS.DesHeatVolFlow; + calcSS.HeatDesDay = srcSS.HeatDesDay; + calcSS.CoinHeatMassFlow = srcSS.CoinHeatMassFlow; + calcSS.HeatCap = srcSS.HeatCap; + calcSS.PreheatCap = srcSS.PreheatCap; + calcSS.HeatFlowSeq = srcSS.HeatFlowSeq; + calcSS.SumZoneHeatLoadSeq = srcSS.SumZoneHeatLoadSeq; + calcSS.HeatCapSeq = srcSS.HeatCapSeq; + calcSS.HeatZoneAvgTempSeq = srcSS.HeatZoneAvgTempSeq; + calcSS.PreheatCapSeq = srcSS.PreheatCapSeq; + calcSS.HeatMixTemp = srcSS.HeatMixTemp; + calcSS.HeatRetTemp = srcSS.HeatRetTemp; + calcSS.HeatMixHumRat = srcSS.HeatMixHumRat; + calcSS.HeatRetHumRat = srcSS.HeatRetHumRat; + calcSS.HeatOutTemp = srcSS.HeatOutTemp; + calcSS.HeatOutHumRat = srcSS.HeatOutHumRat; + calcSS.SysHeatRetTempSeq = srcSS.SysHeatRetTempSeq; + calcSS.SysHeatRetHumRatSeq = srcSS.SysHeatRetHumRatSeq; + calcSS.SysHeatOutTempSeq = srcSS.SysHeatOutTempSeq; + calcSS.SysHeatOutHumRatSeq = srcSS.SysHeatOutHumRatSeq; + calcSS.SysHeatCoilTimeStepPk = srcSS.SysHeatCoilTimeStepPk; + calcSS.SysHeatAirTimeStepPk = srcSS.SysHeatAirTimeStepPk; + calcSS.HeatDDNum = DDNum; + calcSS.SysHeatCoinSpaceSens = srcSS.SysHeatCoinSpaceSens; + calcSS.SysDesHeatLoad = srcSS.SysDesHeatLoad; + calcSS.SysHeatLoadTimeStepPk = srcSS.SysHeatLoadTimeStepPk; +} + +// Copy computed system sizing scalars and sequences from CalcSysSizing to FinalSysSizing. +// Used once at the end of the EndSysSizingCalc block of UpdateSysSizing to propagate results. +static void copyCalcToFinalSysSizing(DataSizing::SystemSizingData &z, DataSizing::SystemSizingData const &c) +{ + // Scalar fields + z.CoolDesDay = c.CoolDesDay; + z.HeatDesDay = c.HeatDesDay; + z.CoinCoolMassFlow = c.CoinCoolMassFlow; + z.CoinHeatMassFlow = c.CoinHeatMassFlow; + z.NonCoinCoolMassFlow = c.NonCoinCoolMassFlow; + z.NonCoinHeatMassFlow = c.NonCoinHeatMassFlow; + z.DesMainVolFlow = c.DesMainVolFlow; + z.DesHeatVolFlow = c.DesHeatVolFlow; + z.DesCoolVolFlow = c.DesCoolVolFlow; + z.MassFlowAtCoolPeak = c.MassFlowAtCoolPeak; + z.SensCoolCap = c.SensCoolCap; + z.TotCoolCap = c.TotCoolCap; + z.HeatCap = c.HeatCap; + z.PreheatCap = c.PreheatCap; + z.MixTempAtCoolPeak = c.MixTempAtCoolPeak; + z.MixHumRatAtCoolPeak = c.MixHumRatAtCoolPeak; + z.RetTempAtCoolPeak = c.RetTempAtCoolPeak; + z.RetHumRatAtCoolPeak = c.RetHumRatAtCoolPeak; + z.OutTempAtCoolPeak = c.OutTempAtCoolPeak; + z.OutHumRatAtCoolPeak = c.OutHumRatAtCoolPeak; + z.HeatMixTemp = c.HeatMixTemp; + z.HeatMixHumRat = c.HeatMixHumRat; + z.HeatRetTemp = c.HeatRetTemp; + z.HeatRetHumRat = c.HeatRetHumRat; + z.HeatOutTemp = c.HeatOutTemp; + z.HeatOutHumRat = c.HeatOutHumRat; + z.SysHeatCoilTimeStepPk = c.SysHeatCoilTimeStepPk; + z.SysHeatAirTimeStepPk = c.SysHeatAirTimeStepPk; + z.HeatDDNum = c.HeatDDNum; + z.SysCoolCoinSpaceSens = c.SysCoolCoinSpaceSens; + z.SysHeatCoinSpaceSens = c.SysHeatCoinSpaceSens; + z.SysDesCoolLoad = c.SysDesCoolLoad; + z.SysCoolLoadTimeStepPk = c.SysCoolLoadTimeStepPk; + z.SysDesHeatLoad = c.SysDesHeatLoad; + z.SysHeatLoadTimeStepPk = c.SysHeatLoadTimeStepPk; + + // Sequence arrays (whole-array assignment) + z.HeatFlowSeq = c.HeatFlowSeq; + z.CoolFlowSeq = c.CoolFlowSeq; + z.SumZoneCoolLoadSeq = c.SumZoneCoolLoadSeq; + z.SumZoneHeatLoadSeq = c.SumZoneHeatLoadSeq; + z.CoolZoneAvgTempSeq = c.CoolZoneAvgTempSeq; + z.HeatZoneAvgTempSeq = c.HeatZoneAvgTempSeq; + z.SensCoolCapSeq = c.SensCoolCapSeq; + z.TotCoolCapSeq = c.TotCoolCapSeq; + z.HeatCapSeq = c.HeatCapSeq; + z.PreheatCapSeq = c.PreheatCapSeq; + z.SysCoolRetTempSeq = c.SysCoolRetTempSeq; + z.SysCoolRetHumRatSeq = c.SysCoolRetHumRatSeq; + z.SysHeatRetTempSeq = c.SysHeatRetTempSeq; + z.SysHeatRetHumRatSeq = c.SysHeatRetHumRatSeq; + z.SysCoolOutTempSeq = c.SysCoolOutTempSeq; + z.SysCoolOutHumRatSeq = c.SysCoolOutHumRatSeq; + z.SysHeatOutTempSeq = c.SysHeatOutTempSeq; + z.SysHeatOutHumRatSeq = c.SysHeatOutHumRatSeq; + z.SysDOASHeatAddSeq = c.SysDOASHeatAddSeq; + z.SysDOASLatAddSeq = c.SysDOASLatAddSeq; +} + +// Save cooling peak conditions into the per-design-day SysSizing record during DuringDay processing. +static void saveDuringDayCoolPeak(EnergyPlusData &state, + DataSizing::SystemSizingData &sysSizing, + Real64 SysSensCoolCap, + Real64 SysTotCoolCap, + Real64 SysCoolMixTemp, + Real64 SysCoolMixHumRat, + Real64 SysCoolRetTemp, + Real64 SysCoolRetHumRat, + int TimeStepInDay) +{ + sysSizing.SensCoolCap = SysSensCoolCap; + sysSizing.TotCoolCap = SysTotCoolCap; + sysSizing.MixTempAtCoolPeak = SysCoolMixTemp; + sysSizing.MixHumRatAtCoolPeak = SysCoolMixHumRat; + sysSizing.RetTempAtCoolPeak = SysCoolRetTemp; + sysSizing.RetHumRatAtCoolPeak = SysCoolRetHumRat; + sysSizing.OutTempAtCoolPeak = state.dataEnvrn->OutDryBulbTemp; + sysSizing.OutHumRatAtCoolPeak = state.dataEnvrn->OutHumRat; + sysSizing.MassFlowAtCoolPeak = sysSizing.CoolFlowSeq(TimeStepInDay); +} + +// Save DuringDay heating peak conditions when the current time step heating capacity exceeds the previous peak. +// Parameterised by the zone list used for coincident space sensible load summation. +static void saveDuringDayHeatPeak(EnergyPlusData &state, + DataSizing::SystemSizingData &sysSizing, + int AirLoopNum, + int TimeStepInDay, + Real64 SysHeatCap, + Real64 SysHeatMixTemp, + Real64 SysHeatMixHumRat, + Real64 SysHeatRetTemp, + Real64 SysHeatRetHumRat, + int numCoinZones, + Array1D_int const &coinCtrlZoneNums) +{ + if (SysHeatCap > sysSizing.HeatCap) { + state.dataSize->SysSizPeakDDNum(AirLoopNum).TimeStepAtHeatPk(state.dataSize->CurOverallSimDay) = TimeStepInDay; + sysSizing.HeatCap = SysHeatCap; + sysSizing.HeatMixTemp = SysHeatMixTemp; + sysSizing.HeatMixHumRat = SysHeatMixHumRat; + sysSizing.HeatRetTemp = SysHeatRetTemp; + sysSizing.HeatRetHumRat = SysHeatRetHumRat; + sysSizing.HeatOutTemp = state.dataEnvrn->OutDryBulbTemp; + sysSizing.HeatOutHumRat = state.dataEnvrn->OutHumRat; + // save time of system coincident heating coil peak + sysSizing.SysHeatCoilTimeStepPk = TimeStepInDay; + sysSizing.SysHeatCoinSpaceSens = 0.0; + for (int zoneLoop = 1; zoneLoop <= numCoinZones; ++zoneLoop) { + int zoneNum = coinCtrlZoneNums(zoneLoop); + sysSizing.SysHeatCoinSpaceSens += state.dataSize->CalcZoneSizing(state.dataSize->CurOverallSimDay, zoneNum).HeatLoadSeq(TimeStepInDay); + } + } + //! save time of system coincident heating airflow peak + if (sysSizing.HeatFlowSeq(TimeStepInDay) > sysSizing.CoinHeatMassFlow) { + sysSizing.SysHeatAirTimeStepPk = TimeStepInDay; + } + // Get the maximum system heating flow rate + sysSizing.CoinHeatMassFlow = max(sysSizing.CoinHeatMassFlow, sysSizing.HeatFlowSeq(TimeStepInDay)); +} + +// Complete DuringDay heating return/mix/capacity computation when system flow is nonzero. +// Called after the zone accumulation loop for both heated-zone and cooled-zone-for-heating paths. +static void computeHeatRetMixCap(EnergyPlusData &state, + DataSizing::SystemSizingData &sysSizing, + int TimeStepInDay, + Real64 &SysHeatRetTemp, + Real64 &SysHeatRetHumRat, + Real64 &SysHeatZoneAvgTemp, + Real64 &SysHeatMixTemp, + Real64 &SysHeatMixHumRat, + Real64 &SysHeatCap) +{ + using Psychrometrics::PsyCpAirFnW; + if (sysSizing.HeatFlowSeq(TimeStepInDay) > 0.0) { + // complete return air temp calc + SysHeatRetTemp /= sysSizing.HeatFlowSeq(TimeStepInDay); + SysHeatRetHumRat /= sysSizing.HeatFlowSeq(TimeStepInDay); + SysHeatZoneAvgTemp /= sysSizing.HeatFlowSeq(TimeStepInDay); + sysSizing.SysHeatRetTempSeq(TimeStepInDay) = SysHeatRetTemp; + sysSizing.SysHeatRetHumRatSeq(TimeStepInDay) = SysHeatRetHumRat; + sysSizing.HeatZoneAvgTempSeq(TimeStepInDay) = SysHeatZoneAvgTemp; + // calculate the outside air fraction for this time step + Real64 RhoAir = state.dataEnvrn->StdRhoAir; + Real64 OutAirFrac; + if (sysSizing.HeatOAOption == DataSizing::OAControl::MinOA) { + OutAirFrac = RhoAir * sysSizing.DesOutAirVolFlow / sysSizing.HeatFlowSeq(TimeStepInDay); + OutAirFrac = min(1.0, max(0.0, OutAirFrac)); + } else { + OutAirFrac = 1.0; + } + // calculate the mixed air temperature + SysHeatMixTemp = state.dataEnvrn->OutDryBulbTemp * OutAirFrac + SysHeatRetTemp * (1.0 - OutAirFrac); + SysHeatMixHumRat = state.dataEnvrn->OutHumRat * OutAirFrac + SysHeatRetHumRat * (1.0 - OutAirFrac); + sysSizing.SysHeatOutTempSeq(TimeStepInDay) = state.dataEnvrn->OutDryBulbTemp; + sysSizing.SysHeatOutHumRatSeq(TimeStepInDay) = state.dataEnvrn->OutHumRat; + // From the mixed air temp, heating supply air temp, and mass flow rate calculate the system heating capacity + SysHeatCap = + PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * sysSizing.HeatFlowSeq(TimeStepInDay) * (sysSizing.HeatSupTemp - SysHeatMixTemp); + SysHeatCap = max(0.0, SysHeatCap); + // save the system heating capacity for the time step + sysSizing.HeatCapSeq(TimeStepInDay) = SysHeatCap; + } +} + +// Accumulate non-coincident heating zone data in EndSysSizingCalc. +// Iterates over the given terminal unit sizing indices, accumulates mass flows, return temps/humrats, +// and outdoor conditions, then computes mix temps and heating capacity. +static void accumulateNonCoinHeatZoneData(EnergyPlusData &state, + int AirLoopNum, + int numZones, + Array1D_int const &termUnitSizingIndices, + Real64 &SysHeatRetTemp, + Real64 &SysHeatRetHumRat, + Real64 &OutAirTemp, + Real64 &OutAirHumRat, + Real64 &SysHeatOutTemp, + Real64 &SysHeatOutHumRat, + Real64 &SysHeatMixTemp, + Real64 &SysHeatMixHumRat, + Real64 &SysHeatCap) +{ + using Psychrometrics::PsyCpAirFnW; + auto &calcSysSizing = state.dataSize->CalcSysSizing(AirLoopNum); + + for (int zoneIdx = 1; zoneIdx <= numZones; ++zoneIdx) { + int TermUnitSizingIndex = termUnitSizingIndices(zoneIdx); + auto const &termUnitSizing = state.dataSize->TermUnitSizing(TermUnitSizingIndex); + // save the system heating supply air temp + state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatCoilInTempTU = calcSysSizing.HeatSupTemp; + // save the system heating supply air hum rat + state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatCoilInHumRatTU = calcSysSizing.HeatSupHumRat; + if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatMassFlow <= 0.0) { + continue; + } + Real64 heatMassFlow = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatMassFlow; + calcSysSizing.NonCoinHeatMassFlow += heatMassFlow / (1.0 + termUnitSizing.InducRat); + SysHeatRetTemp += + state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneRetTempAtHeatPeak * heatMassFlow / (1.0 + termUnitSizing.InducRat); + SysHeatRetHumRat += + state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneHumRatAtHeatPeak * heatMassFlow / (1.0 + termUnitSizing.InducRat); + int HeatDDNum = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).HeatDDNum; + int HeatTimeStepNum = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).TimeStepNumAtHeatMax; + if (HeatDDNum == 0) { + auto const &zoneCFS = state.dataSize->CalcFinalZoneSizing(state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneNum); + OutAirTemp += zoneCFS.HeatOutTemp * heatMassFlow / (1.0 + termUnitSizing.InducRat); + OutAirHumRat += zoneCFS.HeatOutHumRat * heatMassFlow / (1.0 + termUnitSizing.InducRat); + } else { + OutAirTemp += state.dataSize->DesDayWeath(HeatDDNum).Temp(HeatTimeStepNum) * heatMassFlow / (1.0 + termUnitSizing.InducRat); + OutAirHumRat += state.dataSize->DesDayWeath(HeatDDNum).HumRat(HeatTimeStepNum) * heatMassFlow / (1.0 + termUnitSizing.InducRat); + } + } + if (calcSysSizing.NonCoinHeatMassFlow > 0.0) { + SysHeatRetTemp /= calcSysSizing.NonCoinHeatMassFlow; + SysHeatRetHumRat /= calcSysSizing.NonCoinHeatMassFlow; + OutAirTemp /= calcSysSizing.NonCoinHeatMassFlow; + OutAirHumRat /= calcSysSizing.NonCoinHeatMassFlow; + SysHeatOutTemp = OutAirTemp; + SysHeatOutHumRat = OutAirHumRat; + Real64 RhoAir = state.dataEnvrn->StdRhoAir; + Real64 OutAirFrac; + if (calcSysSizing.HeatOAOption == DataSizing::OAControl::MinOA) { + OutAirFrac = RhoAir * calcSysSizing.DesOutAirVolFlow / calcSysSizing.NonCoinHeatMassFlow; + OutAirFrac = min(1.0, max(0.0, OutAirFrac)); + } else { + OutAirFrac = 1.0; + } + SysHeatMixTemp = OutAirTemp * OutAirFrac + SysHeatRetTemp * (1.0 - OutAirFrac); + SysHeatMixHumRat = OutAirHumRat * OutAirFrac + SysHeatRetHumRat * (1.0 - OutAirFrac); + SysHeatCap = + PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * calcSysSizing.NonCoinHeatMassFlow * (calcSysSizing.HeatSupTemp - SysHeatMixTemp); + SysHeatCap = max(0.0, SysHeatCap); + } +} + +// Apply the user-input cooling sizing ratio to final system sizing: scale mass flows, recompute +// timestep capacities, and adjust zone cooling flows. Extracted from the EndSysSizingCalc block. +static void applyCoolSizingRat(EnergyPlusData &state, + DataSizing::SystemSizingData &finalSysSizing, + DataSizing::SystemSizingData const &calcSysSizing, + int AirLoopNum, + int NumZonesCooled, + int numOfTimeStepInDay, + Real64 SysCoolSizingRat) +{ + using Psychrometrics::PsyCpAirFnW; + using Psychrometrics::PsyHFnTdbW; + + finalSysSizing.CoinCoolMassFlow = SysCoolSizingRat * calcSysSizing.CoinCoolMassFlow; + finalSysSizing.NonCoinCoolMassFlow = SysCoolSizingRat * calcSysSizing.NonCoinCoolMassFlow; + finalSysSizing.DesCoolVolFlow = SysCoolSizingRat * calcSysSizing.DesCoolVolFlow; + finalSysSizing.MassFlowAtCoolPeak = SysCoolSizingRat * calcSysSizing.MassFlowAtCoolPeak; + + if (finalSysSizing.DesCoolVolFlow > 0.0) { + Real64 RhoAir = state.dataEnvrn->StdRhoAir; + + for (int TimeStepIndex = 1; TimeStepIndex <= numOfTimeStepInDay; ++TimeStepIndex) { + if (calcSysSizing.CoolFlowSeq(TimeStepIndex) > 0.0) { + finalSysSizing.CoolFlowSeq(TimeStepIndex) = SysCoolSizingRat * calcSysSizing.CoolFlowSeq(TimeStepIndex); + Real64 OutAirFrac; + if (finalSysSizing.CoolOAOption == DataSizing::OAControl::MinOA) { + OutAirFrac = RhoAir * finalSysSizing.DesOutAirVolFlow / finalSysSizing.CoolFlowSeq(TimeStepIndex); + OutAirFrac = min(1.0, max(0.0, OutAirFrac)); + } else { + OutAirFrac = 1.0; + } + Real64 SysCoolMixTemp = finalSysSizing.SysCoolOutTempSeq(TimeStepIndex) * OutAirFrac + + finalSysSizing.SysCoolRetTempSeq(TimeStepIndex) * (1.0 - OutAirFrac); + Real64 SysCoolMixHumRat = finalSysSizing.SysCoolOutHumRatSeq(TimeStepIndex) * OutAirFrac + + finalSysSizing.SysCoolRetHumRatSeq(TimeStepIndex) * (1.0 - OutAirFrac); + Real64 SysSensCoolCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * finalSysSizing.CoolFlowSeq(TimeStepIndex) * + (SysCoolMixTemp - finalSysSizing.CoolSupTemp); + SysSensCoolCap = max(0.0, SysSensCoolCap); + Real64 SysTotCoolCap = + finalSysSizing.CoolFlowSeq(TimeStepIndex) * + (PsyHFnTdbW(SysCoolMixTemp, SysCoolMixHumRat) - PsyHFnTdbW(finalSysSizing.CoolSupTemp, finalSysSizing.CoolSupHumRat)); + SysTotCoolCap = max(0.0, SysTotCoolCap); + finalSysSizing.SensCoolCapSeq(TimeStepIndex) = SysSensCoolCap; + finalSysSizing.TotCoolCapSeq(TimeStepIndex) = SysTotCoolCap; + } + } + + Real64 OutAirFrac; + if (finalSysSizing.CoolOAOption == DataSizing::OAControl::MinOA) { + OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesCoolVolFlow; + OutAirFrac = min(1.0, max(0.0, OutAirFrac)); + } else { + OutAirFrac = 1.0; + } + finalSysSizing.MixTempAtCoolPeak = finalSysSizing.OutTempAtCoolPeak * OutAirFrac + finalSysSizing.RetTempAtCoolPeak * (1.0 - OutAirFrac); + finalSysSizing.MixHumRatAtCoolPeak = + finalSysSizing.OutHumRatAtCoolPeak * OutAirFrac + finalSysSizing.RetHumRatAtCoolPeak * (1.0 - OutAirFrac); + finalSysSizing.SensCoolCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * RhoAir * finalSysSizing.DesCoolVolFlow * + (finalSysSizing.MixTempAtCoolPeak - finalSysSizing.CoolSupTemp); + finalSysSizing.SensCoolCap = max(0.0, finalSysSizing.SensCoolCap); + finalSysSizing.TotCoolCap = RhoAir * finalSysSizing.DesCoolVolFlow * + (PsyHFnTdbW(finalSysSizing.MixTempAtCoolPeak, finalSysSizing.MixHumRatAtCoolPeak) - + PsyHFnTdbW(finalSysSizing.CoolSupTemp, finalSysSizing.CoolSupHumRat)); + finalSysSizing.TotCoolCap = max(0.0, finalSysSizing.TotCoolCap); + } + + // take account of the user input system flow rates and alter the zone flow rates to match + for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { + int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); + if ((SysCoolSizingRat != 1.0) && (finalSysSizing.loadSizingType == DataSizing::LoadSizing::Ventilation) && + (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).MinOA > 0.0)) { + // size on ventilation load + Real64 ZoneOARatio; + if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).MinOA > 0.0) { + ZoneOARatio = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).MinOA / + max(state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesCoolVolFlow, + state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).MinOA); + ZoneOARatio *= (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); + } else { + ZoneOARatio = 0.0; + } + state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).scaleZoneCooling(ZoneOARatio); + } else if ((SysCoolSizingRat > 1.0) || + (SysCoolSizingRat < 1.0 && finalSysSizing.SizingOption == DataSizing::SizingConcurrence::NonCoincident)) { + // size on user input system design flows + state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).scaleZoneCooling(SysCoolSizingRat); + } + } +} + +// Write the system sizing results file (.ssz): header, timestep data, and peak summaries. +// Extracted from the EndSysSizingCalc block of UpdateSysSizing. +static void writeSysSizingResults(EnergyPlusData &state) +{ + print(state.files.ssz, "Time"); + for (int I = 1; I <= state.dataHVACGlobal->NumPrimaryAirSys; ++I) { + for (int J = 1; J <= state.dataEnvrn->TotDesDays + state.dataEnvrn->TotRunDesPersDays; ++J) { + constexpr const char *SSizeFmt12("{}{}{}{:2}{}{}{}{}{:2}{}{}{}{}{:2}{}{}{}{}{:2}{}{}{}{}{:2}{}"); + print(state.files.ssz, + SSizeFmt12, + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).AirPriLoopName, + ":DesPer", + J, + ":Des Heat Mass Flow [kg/s]", + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).AirPriLoopName, + ":DesPer", + J, + ":Des Heat Cap [W]", + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).AirPriLoopName, + ":DesPer", + J, + ":Des Cool Mass Flow [kg/s]", + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).AirPriLoopName, + ":DesPer", + J, + ":Des Sens Cool Cap [W]", + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).AirPriLoopName, + ":DesPer", + J, + ":Des Tot Cool Cap [W]"); + } + } + print(state.files.ssz, "\n"); + int Minutes = 0; + int TimeStepIndex = 0; + for (int HourCounter = 1; HourCounter <= 24; ++HourCounter) { + for (int TimeStepCounter = 1; TimeStepCounter <= state.dataGlobal->TimeStepsInHour; ++TimeStepCounter) { + ++TimeStepIndex; + Minutes += state.dataGlobal->MinutesInTimeStep; + int HourPrint; + if (Minutes == 60) { + Minutes = 0; + HourPrint = HourCounter; + } else { + HourPrint = HourCounter - 1; + } + constexpr const char *SSizeFmt20("{:02}:{:02}:00"); + print(state.files.ssz, SSizeFmt20, HourPrint, Minutes); + for (int I = 1; I <= state.dataHVACGlobal->NumPrimaryAirSys; ++I) { + for (int J = 1; J <= state.dataEnvrn->TotDesDays + state.dataEnvrn->TotRunDesPersDays; ++J) { + constexpr const char *SSizeFmt22("{}{:12.6E}{}{:12.6E}{}{:12.6E}{}{:12.6E}{}{:12.6E}"); + print(state.files.ssz, + SSizeFmt22, + state.dataSize->SizingFileColSep, + state.dataSize->SysSizing(J, I).HeatFlowSeq(TimeStepIndex), + state.dataSize->SizingFileColSep, + state.dataSize->SysSizing(J, I).HeatCapSeq(TimeStepIndex), + state.dataSize->SizingFileColSep, + state.dataSize->SysSizing(J, I).CoolFlowSeq(TimeStepIndex), + state.dataSize->SizingFileColSep, + state.dataSize->SysSizing(J, I).SensCoolCapSeq(TimeStepIndex), + state.dataSize->SizingFileColSep, + state.dataSize->SysSizing(J, I).TotCoolCapSeq(TimeStepIndex)); + } + } + print(state.files.ssz, "\n"); + } + } + + constexpr const char *SSizeFmt31("{}{:12.6E}{}{:12.6E}{}{:12.6E}{}{:12.6E}"); + print(state.files.ssz, "Coinc Peak "); + for (int I = 1; I <= state.dataHVACGlobal->NumPrimaryAirSys; ++I) { + print(state.files.ssz, + SSizeFmt31, + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).CoinHeatMassFlow, + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).CoinCoolMassFlow, + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).HeatCap, + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).SensCoolCap); + } + print(state.files.ssz, "\n"); + + print(state.files.ssz, "NonCoinc Peak"); + for (int I = 1; I <= state.dataHVACGlobal->NumPrimaryAirSys; ++I) { + print(state.files.ssz, + SSizeFmt31, + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).NonCoinHeatMassFlow, + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).NonCoinCoolMassFlow, + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).HeatCap, + state.dataSize->SizingFileColSep, + state.dataSize->CalcSysSizing(I).SensCoolCap); + } + print(state.files.ssz, "\n"); +} + +// Apply the user-input heating sizing ratio to final system sizing: scale mass flows, recompute +// timestep heating capacities, and adjust zone heating flows. Extracted from the EndSysSizingCalc block. +static void applyHeatSizingRat(EnergyPlusData &state, + DataSizing::SystemSizingData &finalSysSizing, + DataSizing::SystemSizingData const &calcSysSizing, + int AirLoopNum, + int NumZonesCooled, + int NumZonesHeated, + int numOfTimeStepInDay, + Real64 SysHeatSizingRat) +{ + using Psychrometrics::PsyCpAirFnW; + + finalSysSizing.CoinHeatMassFlow = SysHeatSizingRat * calcSysSizing.CoinHeatMassFlow; + finalSysSizing.NonCoinHeatMassFlow = SysHeatSizingRat * calcSysSizing.NonCoinHeatMassFlow; + finalSysSizing.DesHeatVolFlow = SysHeatSizingRat * calcSysSizing.DesHeatVolFlow; + + if (finalSysSizing.DesHeatVolFlow > 0.0) { + Real64 RhoAir = state.dataEnvrn->StdRhoAir; + + for (int TimeStepIndex = 1; TimeStepIndex <= numOfTimeStepInDay; ++TimeStepIndex) { + if (calcSysSizing.HeatFlowSeq(TimeStepIndex) > 0.0) { + finalSysSizing.HeatFlowSeq(TimeStepIndex) = SysHeatSizingRat * calcSysSizing.HeatFlowSeq(TimeStepIndex); + Real64 OutAirFrac; + if (finalSysSizing.HeatOAOption == DataSizing::OAControl::MinOA) { + OutAirFrac = RhoAir * finalSysSizing.DesOutAirVolFlow / finalSysSizing.HeatFlowSeq(TimeStepIndex); + OutAirFrac = min(1.0, max(0.0, OutAirFrac)); + } else { + OutAirFrac = 1.0; + } + Real64 SysHeatMixTemp = finalSysSizing.SysHeatOutTempSeq(TimeStepIndex) * OutAirFrac + + finalSysSizing.SysHeatRetTempSeq(TimeStepIndex) * (1.0 - OutAirFrac); + Real64 SysHeatCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * finalSysSizing.HeatFlowSeq(TimeStepIndex) * + (finalSysSizing.HeatSupTemp - SysHeatMixTemp); + SysHeatCap = max(0.0, SysHeatCap); + finalSysSizing.HeatCapSeq(TimeStepIndex) = SysHeatCap; + } + } + + Real64 OutAirFrac; + if (finalSysSizing.HeatOAOption == DataSizing::OAControl::MinOA) { + OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesHeatVolFlow; + OutAirFrac = min(1.0, max(0.0, OutAirFrac)); + } else { + OutAirFrac = 1.0; + } + finalSysSizing.HeatMixTemp = finalSysSizing.HeatOutTemp * OutAirFrac + finalSysSizing.HeatRetTemp * (1.0 - OutAirFrac); + finalSysSizing.HeatMixHumRat = finalSysSizing.HeatOutHumRat * OutAirFrac + finalSysSizing.HeatRetHumRat * (1.0 - OutAirFrac); + finalSysSizing.HeatCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * RhoAir * finalSysSizing.DesHeatVolFlow * + (finalSysSizing.HeatSupTemp - finalSysSizing.HeatMixTemp); + finalSysSizing.HeatCap = max(0.0, finalSysSizing.HeatCap); + } + // take account of the user input system flow rates and alter the zone flow rates to match (for terminal unit sizing) + if (NumZonesHeated > 0) { // IF there are centrally heated zones + scaleZoneHeatFlows(state, + finalSysSizing, + AirLoopNum, + NumZonesHeated, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex, + SysHeatSizingRat, + false); + } else { // No centrally heated zones: use cooled zones + scaleZoneHeatFlows(state, + finalSysSizing, + AirLoopNum, + NumZonesCooled, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex, + SysHeatSizingRat, + true); + } +} + +// Accumulate non-coincident cooling zone data: weighted return temps, outside air conditions, +// and compute mixed-air conditions and cooling capacity. Parallels accumulateNonCoinHeatZoneData. +static void accumulateNonCoinCoolZoneData(EnergyPlusData &state, + int AirLoopNum, + int NumZonesCooled, + Real64 &SysCoolRetTemp, + Real64 &SysCoolRetHumRat, + Real64 &SysCoolOutTemp, + Real64 &SysCoolOutHumRat, + Real64 &SysCoolMixTemp, + Real64 &SysCoolMixHumRat, + Real64 &SysSensCoolCap, + Real64 &SysTotCoolCap) +{ + using Psychrometrics::PsyCpAirFnW; + using Psychrometrics::PsyHFnTdbW; + auto &calcSysSizing = state.dataSize->CalcSysSizing(AirLoopNum); + Real64 OutAirTemp = 0.0; + Real64 OutAirHumRat = 0.0; + + for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { + int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); + auto const &termUnitSizing = state.dataSize->TermUnitSizing(TermUnitSizingIndex); + // save the system cooling supply air temp + state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesCoolCoilInTempTU = calcSysSizing.CoolSupTemp; + // save the system cooling supply air hum rat + state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesCoolCoilInHumRatTU = calcSysSizing.CoolSupHumRat; + if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesCoolMassFlow <= 0.0) { + continue; + } + Real64 coolMassFlow = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesCoolMassFlow; + calcSysSizing.NonCoinCoolMassFlow += coolMassFlow / (1.0 + termUnitSizing.InducRat); + SysCoolRetTemp += + state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneRetTempAtCoolPeak * coolMassFlow / (1.0 + termUnitSizing.InducRat); + SysCoolRetHumRat += + state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneHumRatAtCoolPeak * coolMassFlow / (1.0 + termUnitSizing.InducRat); + int CoolDDNum = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).CoolDDNum; + int CoolTimeStepNum = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).TimeStepNumAtCoolMax; + if (CoolDDNum == 0) { + auto const &zoneCFS = state.dataSize->CalcFinalZoneSizing(state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneNum); + OutAirTemp += zoneCFS.CoolOutTemp * coolMassFlow / (1.0 + termUnitSizing.InducRat); + OutAirHumRat += zoneCFS.CoolOutHumRat * coolMassFlow / (1.0 + termUnitSizing.InducRat); + } else { + OutAirTemp += state.dataSize->DesDayWeath(CoolDDNum).Temp(CoolTimeStepNum) * coolMassFlow / (1.0 + termUnitSizing.InducRat); + OutAirHumRat += state.dataSize->DesDayWeath(CoolDDNum).HumRat(CoolTimeStepNum) * coolMassFlow / (1.0 + termUnitSizing.InducRat); + } + } + if (calcSysSizing.NonCoinCoolMassFlow > 0.0) { + SysCoolRetTemp /= calcSysSizing.NonCoinCoolMassFlow; + SysCoolRetHumRat /= calcSysSizing.NonCoinCoolMassFlow; + OutAirTemp /= calcSysSizing.NonCoinCoolMassFlow; + OutAirHumRat /= calcSysSizing.NonCoinCoolMassFlow; + SysCoolOutTemp = OutAirTemp; + SysCoolOutHumRat = OutAirHumRat; + Real64 RhoAir = state.dataEnvrn->StdRhoAir; + Real64 OutAirFrac; + if (calcSysSizing.CoolOAOption == DataSizing::OAControl::MinOA) { + OutAirFrac = RhoAir * calcSysSizing.DesOutAirVolFlow / calcSysSizing.NonCoinCoolMassFlow; + OutAirFrac = min(1.0, max(0.0, OutAirFrac)); + } else { + OutAirFrac = 1.0; + } + SysCoolMixTemp = OutAirTemp * OutAirFrac + SysCoolRetTemp * (1.0 - OutAirFrac); + SysCoolMixHumRat = OutAirHumRat * OutAirFrac + SysCoolRetHumRat * (1.0 - OutAirFrac); + SysSensCoolCap = + PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * calcSysSizing.NonCoinCoolMassFlow * (SysCoolMixTemp - calcSysSizing.CoolSupTemp); + SysSensCoolCap = max(0.0, SysSensCoolCap); + SysTotCoolCap = calcSysSizing.NonCoinCoolMassFlow * + (PsyHFnTdbW(SysCoolMixTemp, SysCoolMixHumRat) - PsyHFnTdbW(calcSysSizing.CoolSupTemp, calcSysSizing.CoolSupHumRat)); + SysTotCoolCap = max(0.0, SysTotCoolCap); + } +} + +// Accumulate heating zone flows, loads, and weighted return-air conditions for the DuringDay time step. +// Used for both the centrally-heated-zones path and the cooled-zones-used-for-heating path. +static void accumulateHeatZoneFlowsDuringDay(EnergyPlusData &state, + DataSizing::SystemSizingData &sysSizing, + int numZones, + Array1D_int const &ctrlZoneNums, + Array1D_int const &termUnitSizingIndices, + int TimeStepInDay, + Real64 &SysHeatRetTemp, + Real64 &SysHeatRetHumRat, + Real64 &SysHeatZoneAvgTemp) +{ + for (int zoneIdx = 1; zoneIdx <= numZones; ++zoneIdx) { + int CtrlZoneNum = ctrlZoneNums(zoneIdx); + int TermUnitSizingIndex = termUnitSizingIndices(zoneIdx); + auto &termUnitSizing = state.dataSize->TermUnitSizing(TermUnitSizingIndex); + auto &zoneSizing = state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum); + // sum up the heating mass flow rate for this time step + Real64 adjHeatFlowSeq = + termUnitSizing.applyTermUnitSizingHeatFlow(zoneSizing.HeatFlowSeq(TimeStepInDay), zoneSizing.HeatFlowSeqNoOA(TimeStepInDay)); + Real64 adjustedFlow = adjHeatFlowSeq / (1.0 + termUnitSizing.InducRat); + sysSizing.HeatFlowSeq(TimeStepInDay) += adjustedFlow; + // sum up the zone heating load to be met by this system for this time step + sysSizing.SumZoneHeatLoadSeq(TimeStepInDay) += + termUnitSizing.applyTermUnitSizingHeatLoad(zoneSizing.HeatLoadSeq(TimeStepInDay) / (1.0 + termUnitSizing.InducRat)); + // calculate the return air temperature for this time step + SysHeatRetTemp += zoneSizing.HeatZoneRetTempSeq(TimeStepInDay) * adjustedFlow; + SysHeatRetHumRat += zoneSizing.HeatZoneHumRatSeq(TimeStepInDay) * adjustedFlow; + SysHeatZoneAvgTemp += zoneSizing.HeatZoneTempSeq(TimeStepInDay) * adjustedFlow; + } +} + +// Find the induction ratio temperature fraction for a zone's terminal unit. +// Returns the fraction 1/(1+InducRat) if a terminal unit with non-zero sizing index +// is found, or 0 if no terminal unit exists (caller should skip the zone). +// Optionally returns the TermUnitSizingIndex via the output parameter. +static Real64 getInducRatTempFrac(EnergyPlusData &state, int CtrlZoneNum, int &termUnitSizingIndexOut) +{ + termUnitSizingIndexOut = 0; + auto const &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum); + if (!zoneEquipConfig.IsControlled) { + return 0.0; + } + for (int InletNode = 1; InletNode <= zoneEquipConfig.NumInletNodes; ++InletNode) { + int idx = zoneEquipConfig.AirDistUnitCool(InletNode).TermUnitSizingIndex; + if (idx == 0) { + continue; + } + termUnitSizingIndexOut = idx; + return 1.0 / (1.0 + state.dataSize->TermUnitSizing(idx).InducRat); + } + return 0.0; // no terminal unit found +} + +static Real64 getInducRatTempFrac(EnergyPlusData &state, int CtrlZoneNum) +{ + int unused = 0; + return getInducRatTempFrac(state, CtrlZoneNum, unused); +} + +void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIndicator) +{ + + // SUBROUTINE INFORMATION: + // AUTHOR Fred Buhl + // DATE WRITTEN February 2001 + + // PURPOSE OF THIS SUBROUTINE: + // Update the result variables of the zone sizing calculation + + // METHODOLOGY EMPLOYED: + // CallIndicator = 1 (BeginDay) zero the result arrays + // CallIndicator = 2 (DuringDay) fill arrays, averaging over 1 zone time step + // CallIndicator = 3 (EndDay) calculate daily maxima + // CallIndicator = 5 (EndSysSizingCalc) write out results + + // Using/Aliasing + using EMSManager::ManageEMS; + using General::FindNumberInList; + using Psychrometrics::PsyCpAirFnW; + using Psychrometrics::PsyHFnTdbW; + using Psychrometrics::PsyRhoAirFnPbTdbW; + using namespace OutputReportPredefined; + using namespace DataSizing; + + // Locals + int numOfTimeStepInDay; // number of zone time steps in a day + + // SUBROUTINE LOCAL VARIABLE DECLARATIONS: + int AirLoopNum; // primary air system index + Real64 SysCoolRetTemp; // system cooling return temperature for a time step [C] + Real64 SysHeatRetTemp; // system heating return temperature for a time step [C] + Real64 RhoAir; // density of air kg/m3 + Real64 OutAirFrac; // outside air fraction + Real64 SysCoolMixTemp; // system cooling mixed air temperature [C] + Real64 SysHeatMixTemp; // system heating mixed air temperature [C] + Real64 SysSensCoolCap; // system sensible cooling capacity [W] + Real64 SysTotCoolCap; // system total cooling capacity [W] + Real64 SysCoolZoneAvgTemp; // system cooling zone average temperature [C] + Real64 SysHeatZoneAvgTemp; // system heating zone average temperature [C] + Real64 SysHeatCap; // system heating capacity [W] + Real64 OutAirTemp; // outside air temperature + Real64 OutAirHumRat; // outside air humifity ratio + Real64 SysCoolMixHumRat; // system cooling mixed air humidity ratio [kg water/kg dry air] + Real64 SysCoolRetHumRat; // system coolingreturn air humifity ratio [kg water/kg dry air] + Real64 SysHeatMixHumRat; // system heating mixed air humidity ratio [kg water/kg dry air] + Real64 SysHeatRetHumRat; // system heatingreturn air humifity ratio [kg water/kg dry air] + Real64 SysCoolOutTemp; // system cooling outside air temperature [C] + Real64 SysCoolOutHumRat; // system cooling outside air humidity ratio [kg water/kg dry air] + Real64 SysHeatOutTemp; // system heating outside air temperature [C] + Real64 SysHeatOutHumRat; // system heating outside air humidity ratio [kg water/kg dry air] + Real64 SysDOASHeatAdd; // system DOAS heat addition rate [W] + Real64 SysDOASLatAdd; // system DOAS latent heat addition rate [W] + Real64 SysCoolSizingRat; // ratio of user input design flow for cooling divided by calculated design cooling flow + Real64 SysHeatSizingRat; // ratio of user input design flow for heating divided by calculated design heating flow + Real64 RetTempRise; // difference between zone return temperature and zone temperature [delta K] + Real64 SysCoolingEv; // System level ventilation effectiveness for cooling mode + Real64 SysHeatingEv; // System level ventilation effectiveness for heating mode + Real64 SysHtgPeakAirflow; // Peak heating airflow + numOfTimeStepInDay = state.dataGlobal->TimeStepsInHour * Constant::iHoursInDay; + + // allocate scratch arrays + if (!allocated(state.dataSize->SensCoolCapTemp)) { + state.dataSize->SensCoolCapTemp.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); + state.dataSize->TotCoolCapTemp.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); + } + + // allocate arrays used to store values for standard 62.1 tabular report + if (!allocated(state.dataSize->FaByZoneCool)) { + state.dataSize->FaByZoneCool.dimension(state.dataSize->NumAirTerminalUnits, 0.0); + state.dataSize->FaByZoneHeat.dimension(state.dataSize->NumAirTerminalUnits, 0.0); + state.dataSize->FbByZoneCool.dimension(state.dataSize->NumAirTerminalUnits, 0.0); + state.dataSize->FbByZoneHeat.dimension(state.dataSize->NumAirTerminalUnits, 0.0); + state.dataSize->FcByZoneCool.dimension(state.dataSize->NumAirTerminalUnits, 0.0); + state.dataSize->FcByZoneHeat.dimension(state.dataSize->NumAirTerminalUnits, 0.0); + state.dataSimAirServingZones->EvBySysCool.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); + state.dataSimAirServingZones->EvBySysHeat.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); + state.dataSize->XsBySysCool.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); + state.dataSize->XsBySysHeat.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); + state.dataSize->EvzByZoneCool.dimension(state.dataSize->NumAirTerminalUnits, 1.0); + state.dataSize->EvzByZoneCoolPrev.dimension(state.dataSize->NumAirTerminalUnits, 1.0); + state.dataSize->EvzByZoneHeat.dimension(state.dataSize->NumAirTerminalUnits, 1.0); + state.dataSize->EvzByZoneHeatPrev.dimension(state.dataSize->NumAirTerminalUnits, 1.0); + state.dataSize->EvzMinBySysCool.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); + state.dataSize->EvzMinBySysHeat.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 1.0); + state.dataSize->VotClgBySys.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); + state.dataSize->VotHtgBySys.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); + state.dataSize->VozSumClgBySys.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); + state.dataSize->VozSumHtgBySys.dimension(state.dataHVACGlobal->NumPrimaryAirSys, 0.0); + } + + switch (CallIndicator) { + case Constant::CallIndicator::BeginDay: { + // Correct the zone return temperature in ZoneSizing for the case of induction units. The calc in + // ZoneEquipmentManager assumes all the air entering the zone goes into the return node. + for (int CtrlZoneNum = 1; CtrlZoneNum <= state.dataGlobal->NumOfZones; ++CtrlZoneNum) { + Real64 inducFrac = getInducRatTempFrac(state, CtrlZoneNum); + if (inducFrac == 0.0) { + continue; + } + auto &zoneSizing = state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum); + RetTempRise = zoneSizing.ZoneRetTempAtCoolPeak - zoneSizing.ZoneTempAtCoolPeak; + if (RetTempRise > 0.01) { + zoneSizing.ZoneRetTempAtCoolPeak = zoneSizing.ZoneTempAtCoolPeak + RetTempRise * inducFrac; + } + RetTempRise = zoneSizing.ZoneRetTempAtHeatPeak - zoneSizing.ZoneTempAtHeatPeak; + if (RetTempRise > 0.01) { + zoneSizing.ZoneRetTempAtHeatPeak = zoneSizing.ZoneTempAtHeatPeak + RetTempRise * inducFrac; + } + } + + for (AirLoopNum = 1; AirLoopNum <= state.dataHVACGlobal->NumPrimaryAirSys; ++AirLoopNum) { // start of begin day loop over primary air systems + auto &airToZoneNodeInfo = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum); + int NumZonesCooled = airToZoneNodeInfo.NumZonesCooled; + int NumZonesHeated = airToZoneNodeInfo.NumZonesHeated; + state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum).CoolDesDay = state.dataEnvrn->EnvironmentName; + state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum).HeatDesDay = state.dataEnvrn->EnvironmentName; + state.dataSize->SensCoolCapTemp(AirLoopNum) = 0.0; + state.dataSize->TotCoolCapTemp(AirLoopNum) = 0.0; + + for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { // loop over cooled zones + int CtrlZoneNum = airToZoneNodeInfo.CoolCtrlZoneNums(ZonesCooledNum); + int TermUnitSizingIndex = airToZoneNodeInfo.TermUnitCoolSizingIndex(ZonesCooledNum); + Real64 adjCoolMassFlow = + state.dataSize->TermUnitSizing(TermUnitSizingIndex) + .applyTermUnitSizingCoolFlow(state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum).DesCoolMassFlow, + state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum).DesCoolMassFlowNoOA); + state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum).NonCoinCoolMassFlow += + adjCoolMassFlow / (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); + if (state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum).loadSizingType == DataSizing::LoadSizing::Latent && + !state.dataSize->FinalZoneSizing.empty()) { + if (!state.dataSize->FinalZoneSizing(CtrlZoneNum).zoneLatentSizing && state.dataSize->CurOverallSimDay == 1) { + ShowWarningError( + state, + EnergyPlus::format("Latent Sizing for AirLoop = {} requires latent sizing in Sizing:Zone object for Zone = {}", + airToZoneNodeInfo.AirLoopName, + state.dataSize->FinalZoneSizing(CtrlZoneNum).ZoneName)); + } + } else if (!state.dataSize->FinalZoneSizing.empty()) { // not latent sizing for air loop + if (state.dataSize->FinalZoneSizing(CtrlZoneNum).zoneLatentSizing && state.dataSize->CurOverallSimDay == 1 && + state.dataSize->FinalZoneSizing(CtrlZoneNum).heatCoilSizingMethod == DataSizing::HeatCoilSizMethod::None) { + ShowWarningError(state, + EnergyPlus::format("Sizing for AirLoop = {} includes latent sizing in Sizing:Zone object for Zone = {}", + airToZoneNodeInfo.AirLoopName, + state.dataSize->FinalZoneSizing(CtrlZoneNum).ZoneName)); + } + } + } // end of loop over cooled zones + + if (NumZonesHeated > 0) { // if there are zones supplied with central hot air + accumulateBeginDayNonCoinHeatMassFlow(state, + state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum), + NumZonesHeated, + airToZoneNodeInfo.HeatCtrlZoneNums, + airToZoneNodeInfo.TermUnitHeatSizingIndex); + } else { // otherwise use cool supply zones + accumulateBeginDayNonCoinHeatMassFlow(state, + state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum), + NumZonesCooled, + airToZoneNodeInfo.CoolCtrlZoneNums, + airToZoneNodeInfo.TermUnitCoolSizingIndex); + } + + } // End of begin day loop over primary air systems + } break; + case Constant::CallIndicator::DuringDay: { + int TimeStepInDay; // zone time step in day + TimeStepInDay = (state.dataGlobal->HourOfDay - 1) * state.dataGlobal->TimeStepsInHour + + state.dataGlobal->TimeStep; // calculate current zone time step index + + // Correct the zone return temperature in ZoneSizing for the case of induction units. The calc in + // ZoneEquipmentManager assumes all the air entering the zone goes into the return node. + for (int CtrlZoneNum = 1; CtrlZoneNum <= state.dataGlobal->NumOfZones; ++CtrlZoneNum) { + Real64 inducFrac = getInducRatTempFrac(state, CtrlZoneNum); + if (inducFrac == 0.0) { + continue; + } + auto &zoneSizing = state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum); + RetTempRise = zoneSizing.CoolZoneRetTempSeq(TimeStepInDay) - zoneSizing.CoolZoneTempSeq(TimeStepInDay); + if (RetTempRise > 0.01) { + zoneSizing.CoolZoneRetTempSeq(TimeStepInDay) = zoneSizing.CoolZoneTempSeq(TimeStepInDay) + RetTempRise * inducFrac; + } + RetTempRise = zoneSizing.HeatZoneRetTempSeq(TimeStepInDay) - zoneSizing.HeatZoneTempSeq(TimeStepInDay); + if (RetTempRise > 0.01) { + zoneSizing.HeatZoneRetTempSeq(TimeStepInDay) = zoneSizing.HeatZoneTempSeq(TimeStepInDay) + RetTempRise * inducFrac; + } + } + // start of zone time step loop over primary air systems + for (AirLoopNum = 1; AirLoopNum <= state.dataHVACGlobal->NumPrimaryAirSys; ++AirLoopNum) { + + int NumZonesCooled = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled; + int NumZonesHeated = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated; + + SysCoolRetTemp = 0.0; + OutAirFrac = 0.0; + SysCoolMixTemp = 0.0; + SysSensCoolCap = 0.0; + SysCoolRetHumRat = 0.0; + SysCoolMixHumRat = 0.0; + SysCoolZoneAvgTemp = 0.0; + SysHeatZoneAvgTemp = 0.0; + SysTotCoolCap = 0.0; + SysDOASHeatAdd = 0.0; + SysDOASLatAdd = 0.0; Real64 SysLatCoolHumRat = 0.0; for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { // loop over zones cooled by central system @@ -5411,15 +6264,15 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn state.dataSize->SysSizPeakDDNum(AirLoopNum).TimeStepAtSensCoolPk(state.dataSize->CurOverallSimDay) = TimeStepInDay; state.dataSize->SensCoolCapTemp(AirLoopNum) = SysSensCoolCap; if (sysSizing.coolingPeakLoad == DataSizing::PeakLoad::SensibleCooling) { - sysSizing.SensCoolCap = SysSensCoolCap; - sysSizing.TotCoolCap = SysTotCoolCap; - sysSizing.MixTempAtCoolPeak = SysCoolMixTemp; - sysSizing.MixHumRatAtCoolPeak = SysCoolMixHumRat; - sysSizing.RetTempAtCoolPeak = SysCoolRetTemp; - sysSizing.RetHumRatAtCoolPeak = SysCoolRetHumRat; - sysSizing.OutTempAtCoolPeak = state.dataEnvrn->OutDryBulbTemp; - sysSizing.OutHumRatAtCoolPeak = state.dataEnvrn->OutHumRat; - sysSizing.MassFlowAtCoolPeak = sysSizing.CoolFlowSeq(TimeStepInDay); + saveDuringDayCoolPeak(state, + sysSizing, + SysSensCoolCap, + SysTotCoolCap, + SysCoolMixTemp, + SysCoolMixHumRat, + SysCoolRetTemp, + SysCoolRetHumRat, + TimeStepInDay); } } // get the maximum system total cooling capacity @@ -5427,15 +6280,15 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn state.dataSize->SysSizPeakDDNum(AirLoopNum).TimeStepAtTotCoolPk(state.dataSize->CurOverallSimDay) = TimeStepInDay; state.dataSize->TotCoolCapTemp(AirLoopNum) = SysTotCoolCap; if (sysSizing.coolingPeakLoad == DataSizing::PeakLoad::TotalCooling) { - sysSizing.SensCoolCap = SysSensCoolCap; - sysSizing.TotCoolCap = SysTotCoolCap; - sysSizing.MixTempAtCoolPeak = SysCoolMixTemp; - sysSizing.MixHumRatAtCoolPeak = SysCoolMixHumRat; - sysSizing.RetTempAtCoolPeak = SysCoolRetTemp; - sysSizing.RetHumRatAtCoolPeak = SysCoolRetHumRat; - sysSizing.OutTempAtCoolPeak = state.dataEnvrn->OutDryBulbTemp; - sysSizing.OutHumRatAtCoolPeak = state.dataEnvrn->OutHumRat; - sysSizing.MassFlowAtCoolPeak = sysSizing.CoolFlowSeq(TimeStepInDay); + saveDuringDayCoolPeak(state, + sysSizing, + SysSensCoolCap, + SysTotCoolCap, + SysCoolMixTemp, + SysCoolMixHumRat, + SysCoolRetTemp, + SysCoolRetHumRat, + TimeStepInDay); } sysSizing.SysCoolCoinSpaceSens = 0.0; for (int zonesCoolLoop = 1; zonesCoolLoop <= state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled; ++zonesCoolLoop) { @@ -5443,682 +6296,204 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn sysSizing.SysCoolCoinSpaceSens += state.dataSize->CalcZoneSizing(state.dataSize->CurOverallSimDay, zoneNum).CoolLoadSeq(TimeStepInDay); } - } - // get the maximum cooling mass flow rate - if (sysSizing.CoolFlowSeq(TimeStepInDay) > sysSizing.CoinCoolMassFlow) { - sysSizing.CoinCoolMassFlow = sysSizing.CoolFlowSeq(TimeStepInDay); - state.dataSize->SysSizPeakDDNum(AirLoopNum).TimeStepAtCoolFlowPk(state.dataSize->CurOverallSimDay) = TimeStepInDay; - } - SysHeatRetTemp = 0.0; - OutAirFrac = 0.0; - SysHeatMixTemp = 0.0; - SysHeatCap = 0.0; - SysHeatRetHumRat = 0.0; - SysHeatMixHumRat = 0.0; - - if (NumZonesHeated > 0) { // IF there are centrally heated zones - - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesHeated; ++ZonesHeatedNum) { // loop over the heated zones - int CtrlZoneNum = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).HeatCtrlZoneNums(ZonesHeatedNum); - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex(ZonesHeatedNum); - auto &termUnitSizing = state.dataSize->TermUnitSizing(TermUnitSizingIndex); - auto &zoneSizing = state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum); - // sum up the heating mass flow rate for this time step - Real64 adjHeatFlowSeq = - termUnitSizing.applyTermUnitSizingHeatFlow(zoneSizing.HeatFlowSeq(TimeStepInDay), zoneSizing.HeatFlowSeqNoOA(TimeStepInDay)); - Real64 adjustedFlow = adjHeatFlowSeq / (1.0 + termUnitSizing.InducRat); - sysSizing.HeatFlowSeq(TimeStepInDay) += adjustedFlow; - // sum up the zone heating load to be met by this system for this time step - sysSizing.SumZoneHeatLoadSeq(TimeStepInDay) += - termUnitSizing.applyTermUnitSizingHeatLoad(zoneSizing.HeatLoadSeq(TimeStepInDay) / (1.0 + termUnitSizing.InducRat)); - // calculate the return air temperature for this time step - SysHeatRetTemp += zoneSizing.HeatZoneRetTempSeq(TimeStepInDay) * adjustedFlow; - SysHeatRetHumRat += zoneSizing.HeatZoneHumRatSeq(TimeStepInDay) * adjustedFlow; - SysHeatZoneAvgTemp += zoneSizing.HeatZoneTempSeq(TimeStepInDay) * adjustedFlow; - } // end heated zones loop - // Get peak system heating load with coincident - if (std::abs(sysSizing.SysDesHeatLoad) > std::abs(sysSizing.SumZoneHeatLoadSeq(TimeStepInDay))) { - sysSizing.SysDesHeatLoad = sysSizing.SumZoneHeatLoadSeq(TimeStepInDay); - sysSizing.SysHeatLoadTimeStepPk = TimeStepInDay; - } - // check that the system flow rate is nonzero - if (sysSizing.HeatFlowSeq(TimeStepInDay) > 0.0) { - // complete return air temp calc - SysHeatRetTemp /= sysSizing.HeatFlowSeq(TimeStepInDay); - SysHeatRetHumRat /= sysSizing.HeatFlowSeq(TimeStepInDay); - SysHeatZoneAvgTemp /= sysSizing.HeatFlowSeq(TimeStepInDay); - sysSizing.SysHeatRetTempSeq(TimeStepInDay) = SysHeatRetTemp; - sysSizing.SysHeatRetHumRatSeq(TimeStepInDay) = SysHeatRetHumRat; - sysSizing.HeatZoneAvgTempSeq(TimeStepInDay) = SysHeatZoneAvgTemp; - // calculate the outside air fraction for this time step - RhoAir = state.dataEnvrn->StdRhoAir; - if (sysSizing.HeatOAOption == DataSizing::OAControl::MinOA) { - OutAirFrac = RhoAir * sysSizing.DesOutAirVolFlow / sysSizing.HeatFlowSeq(TimeStepInDay); - OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - } else { - OutAirFrac = 1.0; - } - // calculate the mixed air temperature - SysHeatMixTemp = state.dataEnvrn->OutDryBulbTemp * OutAirFrac + SysHeatRetTemp * (1.0 - OutAirFrac); - SysHeatMixHumRat = state.dataEnvrn->OutHumRat * OutAirFrac + SysHeatRetHumRat * (1.0 - OutAirFrac); - sysSizing.SysHeatOutTempSeq(TimeStepInDay) = state.dataEnvrn->OutDryBulbTemp; - sysSizing.SysHeatOutHumRatSeq(TimeStepInDay) = state.dataEnvrn->OutHumRat; - // From the mixed air temp, heating supply air temp, and mass flow rate calculate the system heating capacity - SysHeatCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * sysSizing.HeatFlowSeq(TimeStepInDay) * - (sysSizing.HeatSupTemp - SysHeatMixTemp); - SysHeatCap = max(0.0, SysHeatCap); - // save the system heating capacity for the time step - sysSizing.HeatCapSeq(TimeStepInDay) = SysHeatCap; - } // end system flow rate IF - - // Get the maximum system heating capacity - if (SysHeatCap > sysSizing.HeatCap) { - state.dataSize->SysSizPeakDDNum(AirLoopNum).TimeStepAtHeatPk(state.dataSize->CurOverallSimDay) = TimeStepInDay; - sysSizing.HeatCap = SysHeatCap; - sysSizing.HeatMixTemp = SysHeatMixTemp; - sysSizing.HeatMixHumRat = SysHeatMixHumRat; - sysSizing.HeatRetTemp = SysHeatRetTemp; - sysSizing.HeatRetHumRat = SysHeatRetHumRat; - sysSizing.HeatOutTemp = state.dataEnvrn->OutDryBulbTemp; - sysSizing.HeatOutHumRat = state.dataEnvrn->OutHumRat; - // save time of system coincident heating coil peak - sysSizing.SysHeatCoilTimeStepPk = TimeStepInDay; - sysSizing.SysHeatCoinSpaceSens = 0.0; - if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated > 0) { - for (int zonesHeatLoop = 1; zonesHeatLoop <= state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated; - ++zonesHeatLoop) { - int zoneNum = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).HeatCtrlZoneNums(zonesHeatLoop); - sysSizing.SysHeatCoinSpaceSens += - state.dataSize->CalcZoneSizing(state.dataSize->CurOverallSimDay, zoneNum).HeatLoadSeq(TimeStepInDay); - } - } - } - //! save time of system coincident heating airflow peak - if (sysSizing.HeatFlowSeq(TimeStepInDay) > sysSizing.CoinHeatMassFlow) { - sysSizing.SysHeatAirTimeStepPk = TimeStepInDay; - } - - // Get the maximum system heating flow rate - sysSizing.CoinHeatMassFlow = max(sysSizing.CoinHeatMassFlow, sysSizing.HeatFlowSeq(TimeStepInDay)); - - } else { // No centrally heated zones: use cooled zones - - for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { // loop over the cooled zones - int CtrlZoneNum = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).CoolCtrlZoneNums(ZonesCooledNum); - auto &termUnitSizing = - state.dataSize->TermUnitSizing(state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum)); - auto &zoneSizing = state.dataSize->ZoneSizing(state.dataSize->CurOverallSimDay, CtrlZoneNum); - // sum up the heating mass flow rate for this time step - Real64 adjHeatFlowSeq = - termUnitSizing.applyTermUnitSizingHeatFlow(zoneSizing.HeatFlowSeq(TimeStepInDay), zoneSizing.HeatFlowSeqNoOA(TimeStepInDay)); - Real64 adjustedFlow = adjHeatFlowSeq / (1.0 + termUnitSizing.InducRat); - sysSizing.HeatFlowSeq(TimeStepInDay) += adjustedFlow; - // sum up the zone heating load to be met by this system for this time step - sysSizing.SumZoneHeatLoadSeq(TimeStepInDay) += - termUnitSizing.applyTermUnitSizingHeatLoad(zoneSizing.HeatLoadSeq(TimeStepInDay) / (1.0 + termUnitSizing.InducRat)); - // calculate the return air temperature for this time step - SysHeatRetTemp += zoneSizing.HeatZoneRetTempSeq(TimeStepInDay) * adjustedFlow; - SysHeatRetHumRat += zoneSizing.HeatZoneHumRatSeq(TimeStepInDay) * adjustedFlow; - SysHeatZoneAvgTemp += zoneSizing.HeatZoneTempSeq(TimeStepInDay) * adjustedFlow; - } // end of cooled zones loop - // Get peak system heating load with coincident - if (fabs(sysSizing.SysDesHeatLoad) < fabs(sysSizing.SumZoneHeatLoadSeq(TimeStepInDay))) { - sysSizing.SysDesHeatLoad = sysSizing.SumZoneHeatLoadSeq(TimeStepInDay); - sysSizing.SysHeatLoadTimeStepPk = TimeStepInDay; - } - - if (sysSizing.HeatFlowSeq(TimeStepInDay) > 0.0) { - // complete return air temp calc - SysHeatRetTemp /= sysSizing.HeatFlowSeq(TimeStepInDay); - SysHeatRetHumRat /= sysSizing.HeatFlowSeq(TimeStepInDay); - SysHeatZoneAvgTemp /= sysSizing.HeatFlowSeq(TimeStepInDay); - sysSizing.SysHeatRetTempSeq(TimeStepInDay) = SysHeatRetTemp; - sysSizing.SysHeatRetHumRatSeq(TimeStepInDay) = SysHeatRetHumRat; - sysSizing.HeatZoneAvgTempSeq(TimeStepInDay) = SysHeatZoneAvgTemp; - // calculate the outside air fraction for this time step - RhoAir = state.dataEnvrn->StdRhoAir; - if (sysSizing.HeatOAOption == DataSizing::OAControl::MinOA) { - OutAirFrac = RhoAir * sysSizing.DesOutAirVolFlow / sysSizing.HeatFlowSeq(TimeStepInDay); - OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - } else { - OutAirFrac = 1.0; - } - // calculate the mixed air temperature - SysHeatMixTemp = state.dataEnvrn->OutDryBulbTemp * OutAirFrac + SysHeatRetTemp * (1.0 - OutAirFrac); - SysHeatMixHumRat = state.dataEnvrn->OutHumRat * OutAirFrac + SysHeatRetHumRat * (1.0 - OutAirFrac); - sysSizing.SysHeatOutTempSeq(TimeStepInDay) = state.dataEnvrn->OutDryBulbTemp; - sysSizing.SysHeatOutHumRatSeq(TimeStepInDay) = state.dataEnvrn->OutHumRat; - // From the mixed air temp, heating supply air temp, and mass flow rate calculate the system heating capacity - SysHeatCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * sysSizing.HeatFlowSeq(TimeStepInDay) * - (sysSizing.HeatSupTemp - SysHeatMixTemp); - SysHeatCap = max(0.0, SysHeatCap); - // save the system heating capacity for the time step - sysSizing.HeatCapSeq(TimeStepInDay) = SysHeatCap; - } // end system flow rate IF - - // Get the maximum system heating capacity - if (SysHeatCap > sysSizing.HeatCap) { - state.dataSize->SysSizPeakDDNum(AirLoopNum).TimeStepAtHeatPk(state.dataSize->CurOverallSimDay) = TimeStepInDay; - sysSizing.HeatCap = SysHeatCap; - sysSizing.HeatMixTemp = SysHeatMixTemp; - sysSizing.HeatMixHumRat = SysHeatMixHumRat; - sysSizing.HeatRetTemp = SysHeatRetTemp; - sysSizing.HeatRetHumRat = SysHeatRetHumRat; - sysSizing.HeatOutTemp = state.dataEnvrn->OutDryBulbTemp; - sysSizing.HeatOutHumRat = state.dataEnvrn->OutHumRat; - // save time of system coincident heating coil peak - sysSizing.SysHeatCoilTimeStepPk = TimeStepInDay; - - sysSizing.SysHeatCoinSpaceSens = 0.0; - for (int zonesCoolLoop = 1; zonesCoolLoop <= state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled; ++zonesCoolLoop) { - int zoneNum = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).CoolCtrlZoneNums(zonesCoolLoop); - sysSizing.SysHeatCoinSpaceSens += - state.dataSize->CalcZoneSizing(state.dataSize->CurOverallSimDay, zoneNum).HeatLoadSeq(TimeStepInDay); - } - } // Get the maximum system heating flow rate - // save time of system coincident heating airflow peak - if (sysSizing.HeatFlowSeq(TimeStepInDay) > sysSizing.CoinHeatMassFlow) { - sysSizing.SysHeatAirTimeStepPk = TimeStepInDay; - } - - sysSizing.CoinHeatMassFlow = max(sysSizing.CoinHeatMassFlow, sysSizing.HeatFlowSeq(TimeStepInDay)); - } - - } // end of loop over primary air systems - } break; - case Constant::CallIndicator::EndDay: { - // the entire set of std. 62.1 code here seems misplaced, should have been placed in EndSysSizCalc block - // Get design flows - SysCoolingEv = 1.0; - SysHeatingEv = 1.0; - for (AirLoopNum = 1; AirLoopNum <= state.dataHVACGlobal->NumPrimaryAirSys; ++AirLoopNum) { - int MatchingCooledZoneNum; // temporary variable - auto &finalSysSizing = state.dataSize->FinalSysSizing(AirLoopNum); - int NumZonesCooled = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled; - int NumZonesHeated = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated; - auto &sysSizing = state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum); - - switch (sysSizing.SizingOption) { - case DataSizing::SizingConcurrence::Coincident: { - if (finalSysSizing.SystemOAMethod == SysOAMethod::ZoneSum) { - sysSizing.DesCoolVolFlow = sysSizing.CoinCoolMassFlow / state.dataEnvrn->StdRhoAir; - sysSizing.DesHeatVolFlow = sysSizing.CoinHeatMassFlow / state.dataEnvrn->StdRhoAir; - state.dataSize->VotClgBySys(AirLoopNum) = finalSysSizing.SysUncOA; - state.dataSize->VotHtgBySys(AirLoopNum) = finalSysSizing.SysUncOA; - for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffCooling < - state.dataSize->EvzMinBySysCool(AirLoopNum)) { - state.dataSize->EvzMinBySysCool(AirLoopNum) = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffCooling; - } - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffHeating < - state.dataSize->EvzMinBySysHeat(AirLoopNum)) { - state.dataSize->EvzMinBySysHeat(AirLoopNum) = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffHeating; - } - } - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesHeated; ++ZonesHeatedNum) { - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex(ZonesHeatedNum); - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffCooling < - state.dataSize->EvzMinBySysCool(AirLoopNum)) { - state.dataSize->EvzMinBySysCool(AirLoopNum) = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffCooling; - } - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffHeating < - state.dataSize->EvzMinBySysHeat(AirLoopNum)) { - state.dataSize->EvzMinBySysHeat(AirLoopNum) = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffHeating; - } - } - if (sysSizing.DesCoolVolFlow > 0) { - state.dataSize->XsBySysCool(AirLoopNum) = min(1.0, finalSysSizing.SysUncOA / sysSizing.DesCoolVolFlow); - } else { - state.dataSize->XsBySysCool(AirLoopNum) = 0.0; - } - if (sysSizing.DesHeatVolFlow > 0) { - state.dataSize->XsBySysHeat(AirLoopNum) = min(1.0, finalSysSizing.SysUncOA / sysSizing.DesHeatVolFlow); - } else { - state.dataSize->XsBySysHeat(AirLoopNum) = 0.0; - } - } else if (finalSysSizing.SystemOAMethod == SysOAMethod::VRP || - finalSysSizing.SystemOAMethod == SysOAMethod::SP) { // Ventilation Rate and Simplified Procedure - // cooling - sysSizing.DesCoolVolFlow = sysSizing.CoinCoolMassFlow / state.dataEnvrn->StdRhoAir; - if (sysSizing.DesCoolVolFlow > 0) { - OutAirFrac = sysSizing.DesOutAirVolFlow / sysSizing.DesCoolVolFlow; - } else { - OutAirFrac = 0.0; - } - OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - if (sysSizing.DesCoolVolFlow > 0) { - state.dataSimAirServingZones->Xs = min(1.0, finalSysSizing.SysUncOA / sysSizing.DesCoolVolFlow); - } else { - state.dataSimAirServingZones->Xs = 0.0; - } - if (finalSysSizing.OAAutoSized && sysSizing.DesCoolVolFlow > 0) { - int numZonesCooled = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled; - state.dataSimAirServingZones->MinCoolingEvz = 1.0; - state.dataSize->VozSumClgBySys(AirLoopNum) = 0.0; - for (int ZonesCooledNum = 1; ZonesCooledNum <= numZonesCooled; ++ZonesCooledNum) { - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); - - // Zone air secondary recirculation fraction - state.dataSimAirServingZones->Er = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneSecondaryRecirculation; - state.dataSimAirServingZones->Ep = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZonePrimaryAirFraction; - state.dataSimAirServingZones->ZoneOAFrac = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZpzClgByZone; - state.dataSimAirServingZones->ZoneEz = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffCooling; - VozClg = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).VozClgByZone; - if (finalSysSizing.SystemOAMethod == SysOAMethod::SP) { // 62.1 simplified procedure - if (state.dataSize->DBySys(AirLoopNum) < 0.60) { - state.dataSize->EvzByZoneCool(TermUnitSizingIndex) = 0.88 * state.dataSize->DBySys(AirLoopNum) + 0.22; - } else { - state.dataSize->EvzByZoneCool(TermUnitSizingIndex) = 0.75; - } - state.dataSimAirServingZones->MinCoolingEvz = state.dataSize->EvzByZoneCool(TermUnitSizingIndex); - } else { - if (state.dataSimAirServingZones->Er > 0.0) { - // multi-path ventilation system using VRP - state.dataSimAirServingZones->Fa = state.dataSimAirServingZones->Ep + - (1.0 - state.dataSimAirServingZones->Ep) * state.dataSimAirServingZones->Er; - state.dataSimAirServingZones->Fb = state.dataSimAirServingZones->Ep; - state.dataSimAirServingZones->Fc = 1.0 - (1.0 - state.dataSimAirServingZones->ZoneEz) * - (1.0 - state.dataSimAirServingZones->Er) * - (1.0 - state.dataSimAirServingZones->Ep); - // save Fa Fb and Fc for standard 62.1 report - state.dataSize->FaByZoneCool(TermUnitSizingIndex) = state.dataSimAirServingZones->Fa; - state.dataSize->FbByZoneCool(TermUnitSizingIndex) = state.dataSimAirServingZones->Fb; - state.dataSize->FcByZoneCool(TermUnitSizingIndex) = state.dataSimAirServingZones->Fc; - - // Calc zone ventilation efficiency - if (state.dataSimAirServingZones->Fa > 0.0) { - SysCoolingEv = - 1.0 + - state.dataSimAirServingZones->Xs * state.dataSimAirServingZones->Fb / state.dataSimAirServingZones->Fa - - state.dataSimAirServingZones->ZoneOAFrac * state.dataSimAirServingZones->Ep * - state.dataSimAirServingZones->Fc / state.dataSimAirServingZones->Fa; - } else { - SysCoolingEv = 1.0; - } - - } else { - // single-path ventilation system - SysCoolingEv = 1.0 + state.dataSimAirServingZones->Xs - state.dataSimAirServingZones->ZoneOAFrac; - // Apply ventilation efficiency limit; reset SysCoolingEv if necessary - LimitZoneVentEff(state, state.dataSimAirServingZones->Xs, VozClg, TermUnitSizingIndex, SysCoolingEv); - } - if (SysCoolingEv < state.dataSimAirServingZones->MinCoolingEvz) { - state.dataSimAirServingZones->MinCoolingEvz = SysCoolingEv; - } - state.dataSize->EvzByZoneCoolPrev(TermUnitSizingIndex) = - state.dataSize->EvzByZoneCool(TermUnitSizingIndex); // Save previous EvzByZoneCool - state.dataSize->EvzByZoneCool(TermUnitSizingIndex) = SysCoolingEv; - } - state.dataSize->VozSumClgBySys(AirLoopNum) += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).VozClgByZone; - } - - if (state.dataSimAirServingZones->MinCoolingEvz > 0) { - // (However, I don't think people diversity can be done correctly in E+ Sizing so assuming D=1 in this - // equation - // Vou = Diversity*(Rp*Pz) + Ra*Az - state.dataSimAirServingZones->Vou = finalSysSizing.SysUncOA; - state.dataSimAirServingZones->Vot = state.dataSimAirServingZones->Vou / state.dataSimAirServingZones->MinCoolingEvz; - if (state.dataSimAirServingZones->Vot > state.dataSize->VotClgBySys(AirLoopNum)) { - // This might be the cooling design day so only update if Vot is larger than the previous - state.dataSize->VotClgBySys(AirLoopNum) = state.dataSimAirServingZones->Vot; - state.dataSize->XsBySysCool(AirLoopNum) = state.dataSimAirServingZones->Xs; - state.dataSize->EvzMinBySysCool(AirLoopNum) = state.dataSimAirServingZones->MinCoolingEvz; - } else { - // Restore EvzByZoneCool() since it was reset by the current (but not highest Vot) design day - for (int ZonesCooledNum = 1; ZonesCooledNum <= numZonesCooled; ++ZonesCooledNum) { - int TermUnitSizingIndex = - state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); - state.dataSize->EvzByZoneCool(TermUnitSizingIndex) = state.dataSize->EvzByZoneCoolPrev(TermUnitSizingIndex); - } - } - } - } - - // heating - sysSizing.DesHeatVolFlow = sysSizing.CoinHeatMassFlow / state.dataEnvrn->StdRhoAir; - if (sysSizing.DesHeatVolFlow > 0) { - OutAirFrac = sysSizing.DesOutAirVolFlow / sysSizing.DesHeatVolFlow; - } else { - OutAirFrac = 0.0; - } - OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - - // This is a bit of a cludge. If the design zone heating airflows were increased due to - // the MaxZoneOaFraction, then the SysSizing(AirLoopNum,state.dataSize->CurOverallSimDay)%DesHeatVolFlow - // variable will be out of sync with the - if (finalSysSizing.MaxZoneOAFraction > 0 && finalSysSizing.HeatAirDesMethod == AirflowSizingMethod::FromDDCalc) { - SysHtgPeakAirflow = 0.0; - if (NumZonesHeated > 0) { - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesHeated; ++ZonesHeatedNum) { - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex(ZonesHeatedNum); - SysHtgPeakAirflow += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatVolFlow; - } - } else { - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesCooled; ++ZonesHeatedNum) { - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesHeatedNum); - SysHtgPeakAirflow += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatVolFlow; - } - } - } else { - SysHtgPeakAirflow = sysSizing.DesHeatVolFlow; - } - - if (sysSizing.DesHeatVolFlow > 0) { - // SysSizing(AirLoopNum,state.dataSize->CurOverallSimDay)%DesHeatVolFlow may be out of sync with - // FinalZoneSizing(CtrlZoneNum)%DesHeatVolFlow - state.dataSimAirServingZones->Xs = min(1.0, finalSysSizing.SysUncOA / max(sysSizing.DesHeatVolFlow, SysHtgPeakAirflow)); - } else { - state.dataSimAirServingZones->Xs = 0.0; - } - - if (finalSysSizing.OAAutoSized && sysSizing.DesHeatVolFlow > 0) { - int numZonesHeated = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated; - state.dataSimAirServingZones->MinHeatingEvz = 1.0; - state.dataSize->VozSumHtgBySys(AirLoopNum) = 0.0; - if (numZonesHeated > 0) { - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= numZonesHeated; ++ZonesHeatedNum) { - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex(ZonesHeatedNum); - MatchingCooledZoneNum = FindNumberInList( - TermUnitSizingIndex, state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex, NumZonesCooled); - if (MatchingCooledZoneNum == 0) { - // Zone air secondary recirculation fraction - state.dataSimAirServingZones->Er = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneSecondaryRecirculation; - state.dataSimAirServingZones->Ep = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZonePrimaryAirFractionHtg; - state.dataSimAirServingZones->ZoneOAFrac = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZpzHtgByZone; - state.dataSimAirServingZones->ZoneEz = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffHeating; - if (finalSysSizing.SystemOAMethod == SysOAMethod::SP) { // 62.1 simplified procedure - if (state.dataSize->DBySys(AirLoopNum) < 0.60) { - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = 0.88 * state.dataSize->DBySys(AirLoopNum) + 0.22; - } else { - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = 0.75; - } - state.dataSimAirServingZones->MinHeatingEvz = state.dataSize->EvzByZoneHeat(TermUnitSizingIndex); - } else { - if (state.dataSimAirServingZones->Er > 0.0) { - // multi-path ventilation system using VRP - state.dataSimAirServingZones->Fa = - state.dataSimAirServingZones->Ep + - (1.0 - state.dataSimAirServingZones->Ep) * state.dataSimAirServingZones->Er; - state.dataSimAirServingZones->Fb = state.dataSimAirServingZones->Ep; - state.dataSimAirServingZones->Fc = 1.0 - (1.0 - state.dataSimAirServingZones->ZoneEz) * - (1.0 - state.dataSimAirServingZones->Er) * - (1.0 - state.dataSimAirServingZones->Ep); - // save Fa Fb and Fc for standard 62.1 report - state.dataSize->FaByZoneHeat(TermUnitSizingIndex) = state.dataSimAirServingZones->Fa; - state.dataSize->FbByZoneHeat(TermUnitSizingIndex) = state.dataSimAirServingZones->Fb; - state.dataSize->FcByZoneHeat(TermUnitSizingIndex) = state.dataSimAirServingZones->Fc; - - // Calc zone ventilation efficiency - if (state.dataSimAirServingZones->Fa > 0.0) { - SysHeatingEv = 1.0 + - state.dataSimAirServingZones->Xs * state.dataSimAirServingZones->Fb / - state.dataSimAirServingZones->Fa - - state.dataSimAirServingZones->ZoneOAFrac * state.dataSimAirServingZones->Ep * - state.dataSimAirServingZones->Fc / state.dataSimAirServingZones->Fa; - } else { - SysHeatingEv = 1.0; - } - } else { - // single-path ventilation system - SysHeatingEv = 1.0 + state.dataSimAirServingZones->Xs - state.dataSimAirServingZones->ZoneOAFrac; - } - if (SysHeatingEv < state.dataSimAirServingZones->MinHeatingEvz) { - state.dataSimAirServingZones->MinHeatingEvz = SysHeatingEv; - } - state.dataSize->EvzByZoneHeatPrev(TermUnitSizingIndex) = - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex); // Save previous EvzByZoneHeat - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = SysHeatingEv; - } - state.dataSize->VozSumHtgBySys(AirLoopNum) += - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).VozHtgByZone; - } - } - } else { - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesCooled; ++ZonesHeatedNum) { - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesHeatedNum); - // Zone air secondary recirculation fraction - state.dataSimAirServingZones->Er = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneSecondaryRecirculation; - state.dataSimAirServingZones->Ep = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZonePrimaryAirFractionHtg; - state.dataSimAirServingZones->ZoneOAFrac = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZpzHtgByZone; - state.dataSimAirServingZones->ZoneEz = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffHeating; - if (finalSysSizing.SystemOAMethod == SysOAMethod::SP) { // 62.1 simplified procedure - if (state.dataSize->DBySys(AirLoopNum) < 0.60) { - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = 0.88 * state.dataSize->DBySys(AirLoopNum) + 0.22; - } else { - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = 0.75; - } - state.dataSimAirServingZones->MinHeatingEvz = state.dataSize->EvzByZoneHeat(TermUnitSizingIndex); - } else { - if (state.dataSimAirServingZones->Er > 0.0) { - // multi-path ventilation system using VRP - state.dataSimAirServingZones->Fa = - state.dataSimAirServingZones->Ep + - (1.0 - state.dataSimAirServingZones->Ep) * state.dataSimAirServingZones->Er; - state.dataSimAirServingZones->Fb = state.dataSimAirServingZones->Ep; - state.dataSimAirServingZones->Fc = 1.0 - (1.0 - state.dataSimAirServingZones->ZoneEz) * - (1.0 - state.dataSimAirServingZones->Er) * - (1.0 - state.dataSimAirServingZones->Ep); - // save Fa Fb and Fc for standard 62.1 report - state.dataSize->FaByZoneHeat(TermUnitSizingIndex) = state.dataSimAirServingZones->Fa; - state.dataSize->FbByZoneHeat(TermUnitSizingIndex) = state.dataSimAirServingZones->Fb; - state.dataSize->FcByZoneHeat(TermUnitSizingIndex) = state.dataSimAirServingZones->Fc; - - // Calc zone ventilation efficiency - if (state.dataSimAirServingZones->Fa > 0.0) { - SysHeatingEv = 1.0 + - state.dataSimAirServingZones->Xs * state.dataSimAirServingZones->Fb / - state.dataSimAirServingZones->Fa - - state.dataSimAirServingZones->ZoneOAFrac * state.dataSimAirServingZones->Ep * - state.dataSimAirServingZones->Fc / state.dataSimAirServingZones->Fa; - } else { - SysHeatingEv = 1.0; - } - } else { - // single-path ventilation system - SysHeatingEv = 1.0 + state.dataSimAirServingZones->Xs - state.dataSimAirServingZones->ZoneOAFrac; - } - if (SysHeatingEv < state.dataSimAirServingZones->MinHeatingEvz) { - state.dataSimAirServingZones->MinHeatingEvz = SysHeatingEv; - } - state.dataSize->EvzByZoneHeatPrev(TermUnitSizingIndex) = - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex); // Save previous EvzByZoneHeat - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = SysHeatingEv; - state.dataSize->VozSumHtgBySys(AirLoopNum) += - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).VozHtgByZone; - } - } - } + } + // get the maximum cooling mass flow rate + if (sysSizing.CoolFlowSeq(TimeStepInDay) > sysSizing.CoinCoolMassFlow) { + sysSizing.CoinCoolMassFlow = sysSizing.CoolFlowSeq(TimeStepInDay); + state.dataSize->SysSizPeakDDNum(AirLoopNum).TimeStepAtCoolFlowPk(state.dataSize->CurOverallSimDay) = TimeStepInDay; + } + SysHeatRetTemp = 0.0; + OutAirFrac = 0.0; + SysHeatMixTemp = 0.0; + SysHeatCap = 0.0; + SysHeatRetHumRat = 0.0; + SysHeatMixHumRat = 0.0; - if (state.dataSimAirServingZones->MinHeatingEvz > 0) { - // Std 62.1-2010, section 6.2.5.4: Eq. 6.6 - // (However, I don't think people diversity can be done correctly in E+ Sizing so assuming D=1 in this - // equation - // Vou = Diversity*(Rp*Pz) + Ra*Az - state.dataSimAirServingZones->Vou = finalSysSizing.SysUncOA; - state.dataSimAirServingZones->Vot = state.dataSimAirServingZones->Vou / state.dataSimAirServingZones->MinHeatingEvz; - if (state.dataSimAirServingZones->Vot > state.dataSize->VotHtgBySys(AirLoopNum)) { - // This might be the cooling design day so only update if Vot is larger than the previous - state.dataSize->VotHtgBySys(AirLoopNum) = state.dataSimAirServingZones->Vot; - state.dataSize->XsBySysHeat(AirLoopNum) = state.dataSimAirServingZones->Xs; - state.dataSize->EvzMinBySysHeat(AirLoopNum) = state.dataSimAirServingZones->MinHeatingEvz; - } else { - // Restore EvzByZoneHeat() since it was reset by the current (but not highest Vot) design day - // This kludge is probably because inside EndDay block and code gets called for each design day. - if (numZonesHeated > 0) { - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= numZonesHeated; ++ZonesHeatedNum) { - int TermUnitSizingIndex = - state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex(ZonesHeatedNum); - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = state.dataSize->EvzByZoneHeatPrev(TermUnitSizingIndex); - } - } else { - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesCooled; ++ZonesHeatedNum) { - int TermUnitSizingIndex = - state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesHeatedNum); - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = state.dataSize->EvzByZoneHeatPrev(TermUnitSizingIndex); - } - } - } - } - } - } else { // error + if (NumZonesHeated > 0) { // IF there are centrally heated zones + + accumulateHeatZoneFlowsDuringDay(state, + sysSizing, + NumZonesHeated, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).HeatCtrlZoneNums, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex, + TimeStepInDay, + SysHeatRetTemp, + SysHeatRetHumRat, + SysHeatZoneAvgTemp); + // Get peak system heating load with coincident + if (std::abs(sysSizing.SysDesHeatLoad) > std::abs(sysSizing.SumZoneHeatLoadSeq(TimeStepInDay))) { + sysSizing.SysDesHeatLoad = sysSizing.SumZoneHeatLoadSeq(TimeStepInDay); + sysSizing.SysHeatLoadTimeStepPk = TimeStepInDay; } - sysSizing.DesMainVolFlow = max(sysSizing.DesCoolVolFlow, sysSizing.DesHeatVolFlow); - // this should also be as least as big as is needed for Vot - } break; - case DataSizing::SizingConcurrence::NonCoincident: { + computeHeatRetMixCap(state, + sysSizing, + TimeStepInDay, + SysHeatRetTemp, + SysHeatRetHumRat, + SysHeatZoneAvgTemp, + SysHeatMixTemp, + SysHeatMixHumRat, + SysHeatCap); + + saveDuringDayHeatPeak(state, + sysSizing, + AirLoopNum, + TimeStepInDay, + SysHeatCap, + SysHeatMixTemp, + SysHeatMixHumRat, + SysHeatRetTemp, + SysHeatRetHumRat, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).HeatCtrlZoneNums); + + } else { // No centrally heated zones: use cooled zones + + accumulateHeatZoneFlowsDuringDay(state, + sysSizing, + NumZonesCooled, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).CoolCtrlZoneNums, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex, + TimeStepInDay, + SysHeatRetTemp, + SysHeatRetHumRat, + SysHeatZoneAvgTemp); + // Get peak system heating load with coincident + if (fabs(sysSizing.SysDesHeatLoad) < fabs(sysSizing.SumZoneHeatLoadSeq(TimeStepInDay))) { + sysSizing.SysDesHeatLoad = sysSizing.SumZoneHeatLoadSeq(TimeStepInDay); + sysSizing.SysHeatLoadTimeStepPk = TimeStepInDay; + } + + computeHeatRetMixCap(state, + sysSizing, + TimeStepInDay, + SysHeatRetTemp, + SysHeatRetHumRat, + SysHeatZoneAvgTemp, + SysHeatMixTemp, + SysHeatMixHumRat, + SysHeatCap); + + saveDuringDayHeatPeak(state, + sysSizing, + AirLoopNum, + TimeStepInDay, + SysHeatCap, + SysHeatMixTemp, + SysHeatMixHumRat, + SysHeatRetTemp, + SysHeatRetHumRat, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).CoolCtrlZoneNums); + } + + } // end of loop over primary air systems + } break; + case Constant::CallIndicator::EndDay: { + // the entire set of std. 62.1 code here seems misplaced, should have been placed in EndSysSizCalc block + // Get design flows + SysCoolingEv = 1.0; + SysHeatingEv = 1.0; + for (AirLoopNum = 1; AirLoopNum <= state.dataHVACGlobal->NumPrimaryAirSys; ++AirLoopNum) { + int MatchingCooledZoneNum; // temporary variable + auto &finalSysSizing = state.dataSize->FinalSysSizing(AirLoopNum); + int NumZonesCooled = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled; + int NumZonesHeated = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated; + auto &sysSizing = state.dataSize->SysSizing(state.dataSize->CurOverallSimDay, AirLoopNum); + + switch (sysSizing.SizingOption) { + case DataSizing::SizingConcurrence::Coincident: { if (finalSysSizing.SystemOAMethod == SysOAMethod::ZoneSum) { - sysSizing.DesCoolVolFlow = sysSizing.NonCoinCoolMassFlow / state.dataEnvrn->StdRhoAir; - sysSizing.DesHeatVolFlow = sysSizing.NonCoinHeatMassFlow / state.dataEnvrn->StdRhoAir; - state.dataSize->VotClgBySys(AirLoopNum) = finalSysSizing.SysUncOA; - state.dataSize->VotHtgBySys(AirLoopNum) = finalSysSizing.SysUncOA; - for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffCooling < - state.dataSize->EvzMinBySysCool(AirLoopNum)) { - state.dataSize->EvzMinBySysCool(AirLoopNum) = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffCooling; - } - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffHeating < - state.dataSize->EvzMinBySysHeat(AirLoopNum)) { - state.dataSize->EvzMinBySysHeat(AirLoopNum) = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffHeating; - } - } - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesHeated; ++ZonesHeatedNum) { - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex(ZonesHeatedNum); - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffCooling < - state.dataSize->EvzMinBySysCool(AirLoopNum)) { - state.dataSize->EvzMinBySysCool(AirLoopNum) = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffCooling; - } - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffHeating < - state.dataSize->EvzMinBySysHeat(AirLoopNum)) { - state.dataSize->EvzMinBySysHeat(AirLoopNum) = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffHeating; - } - } - if (sysSizing.DesCoolVolFlow > 0) { - state.dataSize->XsBySysCool(AirLoopNum) = min(1.0, finalSysSizing.SysUncOA / sysSizing.DesCoolVolFlow); - } else { - state.dataSize->XsBySysCool(AirLoopNum) = 0.0; - } - if (sysSizing.DesHeatVolFlow > 0) { - state.dataSize->XsBySysHeat(AirLoopNum) = min(1.0, finalSysSizing.SysUncOA / sysSizing.DesHeatVolFlow); - } else { - state.dataSize->XsBySysHeat(AirLoopNum) = 0.0; - } + updateZoneSumVolFlows(state, + sysSizing, + finalSysSizing, + AirLoopNum, + NumZonesCooled, + NumZonesHeated, + sysSizing.CoinCoolMassFlow, + sysSizing.CoinHeatMassFlow); } else if (finalSysSizing.SystemOAMethod == SysOAMethod::VRP || finalSysSizing.SystemOAMethod == SysOAMethod::SP) { // Ventilation Rate and Simplified Procedure // cooling - sysSizing.DesCoolVolFlow = sysSizing.NonCoinCoolMassFlow / state.dataEnvrn->StdRhoAir; - if (sysSizing.DesCoolVolFlow > 0) { - OutAirFrac = sysSizing.DesOutAirVolFlow / sysSizing.DesCoolVolFlow; + sysSizing.DesCoolVolFlow = sysSizing.CoinCoolMassFlow / state.dataEnvrn->StdRhoAir; + updateCoolVRPEvzVot(state, sysSizing, finalSysSizing, AirLoopNum); + + // heating + sysSizing.DesHeatVolFlow = sysSizing.CoinHeatMassFlow / state.dataEnvrn->StdRhoAir; + if (sysSizing.DesHeatVolFlow > 0) { + OutAirFrac = sysSizing.DesOutAirVolFlow / sysSizing.DesHeatVolFlow; } else { OutAirFrac = 0.0; } OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - if (sysSizing.DesCoolVolFlow > 0) { - state.dataSimAirServingZones->Xs = min(1.0, finalSysSizing.SysUncOA / sysSizing.DesCoolVolFlow); + // This is a bit of a cludge. If the design zone heating airflows were increased due to + // the MaxZoneOaFraction, then the SysSizing(AirLoopNum,state.dataSize->CurOverallSimDay)%DesHeatVolFlow + // variable will be out of sync with the + if (finalSysSizing.MaxZoneOAFraction > 0 && finalSysSizing.HeatAirDesMethod == AirflowSizingMethod::FromDDCalc) { + if (NumZonesHeated > 0) { + SysHtgPeakAirflow = + sumDesHeatVolFlow(state, NumZonesHeated, state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex); + } else { + SysHtgPeakAirflow = + sumDesHeatVolFlow(state, NumZonesCooled, state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex); + } + } else { + SysHtgPeakAirflow = sysSizing.DesHeatVolFlow; + } + + if (sysSizing.DesHeatVolFlow > 0) { + // SysSizing(AirLoopNum,state.dataSize->CurOverallSimDay)%DesHeatVolFlow may be out of sync with + // FinalZoneSizing(CtrlZoneNum)%DesHeatVolFlow + state.dataSimAirServingZones->Xs = min(1.0, finalSysSizing.SysUncOA / max(sysSizing.DesHeatVolFlow, SysHtgPeakAirflow)); } else { state.dataSimAirServingZones->Xs = 0.0; } - if (finalSysSizing.OAAutoSized && sysSizing.DesCoolVolFlow > 0) { - int numZonesCooled = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled; - state.dataSimAirServingZones->MinCoolingEvz = 1.0; - state.dataSize->VozSumClgBySys(AirLoopNum) = 0.0; - for (int ZonesCooledNum = 1; ZonesCooledNum <= numZonesCooled; ++ZonesCooledNum) { - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); - - // Zone air secondary recirculation fraction - state.dataSimAirServingZones->Er = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneSecondaryRecirculation; - state.dataSimAirServingZones->Ep = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZonePrimaryAirFraction; - state.dataSimAirServingZones->ZoneOAFrac = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZpzClgByZone; - state.dataSimAirServingZones->ZoneEz = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneADEffCooling; - VozClg = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).VozClgByZone; - if (finalSysSizing.SystemOAMethod == SysOAMethod::SP) { // 62.1 simplified procedure - if (state.dataSize->DBySys(AirLoopNum) < 0.60) { - state.dataSize->EvzByZoneCool(TermUnitSizingIndex) = 0.88 * state.dataSize->DBySys(AirLoopNum) + 0.22; - } else { - state.dataSize->EvzByZoneCool(TermUnitSizingIndex) = 0.75; - } - state.dataSimAirServingZones->MinCoolingEvz = state.dataSize->EvzByZoneCool(TermUnitSizingIndex); - } else { - if (state.dataSimAirServingZones->Er > 0.0) { - // multi-path ventilation system using VRP - state.dataSimAirServingZones->Fa = state.dataSimAirServingZones->Ep + - (1.0 - state.dataSimAirServingZones->Ep) * state.dataSimAirServingZones->Er; - state.dataSimAirServingZones->Fb = state.dataSimAirServingZones->Ep; - state.dataSimAirServingZones->Fc = 1.0 - (1.0 - state.dataSimAirServingZones->ZoneEz) * - (1.0 - state.dataSimAirServingZones->Er) * - (1.0 - state.dataSimAirServingZones->Ep); - // save Fa Fb and Fc for standard 62.1 report - state.dataSize->FaByZoneCool(TermUnitSizingIndex) = state.dataSimAirServingZones->Fa; - state.dataSize->FbByZoneCool(TermUnitSizingIndex) = state.dataSimAirServingZones->Fb; - state.dataSize->FcByZoneCool(TermUnitSizingIndex) = state.dataSimAirServingZones->Fc; - - // Calc zone ventilation efficiency - if (state.dataSimAirServingZones->Fa > 0.0) { - SysCoolingEv = - 1.0 + - state.dataSimAirServingZones->Xs * state.dataSimAirServingZones->Fb / state.dataSimAirServingZones->Fa - - state.dataSimAirServingZones->ZoneOAFrac * state.dataSimAirServingZones->Ep * - state.dataSimAirServingZones->Fc / state.dataSimAirServingZones->Fa; - } else { - SysCoolingEv = 1.0; - } - } else { - // single-path ventilation system - SysCoolingEv = 1.0 + state.dataSimAirServingZones->Xs - state.dataSimAirServingZones->ZoneOAFrac; - // Apply ventilation efficiency limit; reset SysCoolingEv if necessary - LimitZoneVentEff(state, state.dataSimAirServingZones->Xs, VozClg, TermUnitSizingIndex, SysCoolingEv); - } - if (SysCoolingEv < state.dataSimAirServingZones->MinCoolingEvz) { - state.dataSimAirServingZones->MinCoolingEvz = SysCoolingEv; - } - state.dataSize->EvzByZoneCoolPrev(TermUnitSizingIndex) = state.dataSize->EvzByZoneCool(TermUnitSizingIndex); - state.dataSize->EvzByZoneCool(TermUnitSizingIndex) = SysCoolingEv; - state.dataSize->VozSumClgBySys(AirLoopNum) += - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).VozClgByZone; - } - state.dataSize->VozSumClgBySys(AirLoopNum) += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).VozClgByZone; - } - if (state.dataSimAirServingZones->MinCoolingEvz > 0) { - // Std 62.1-2010, section 6.2.5.4: Eq. 6.6 - // (However, I don't think people diversity can be done correctly in E+ Sizing so assuming D=1 in this - // equation - // Vou = Diversity*(Rp*Pz) + Ra*Az - state.dataSimAirServingZones->Vou = finalSysSizing.SysUncOA; - state.dataSimAirServingZones->Vot = state.dataSimAirServingZones->Vou / state.dataSimAirServingZones->MinCoolingEvz; - if (state.dataSimAirServingZones->Vot > state.dataSize->VotClgBySys(AirLoopNum)) { - // This might be the cooling design day so only update if Vot is larger than the previous - state.dataSize->VotClgBySys(AirLoopNum) = state.dataSimAirServingZones->Vot; - state.dataSize->XsBySysCool(AirLoopNum) = state.dataSimAirServingZones->Xs; - state.dataSize->EvzMinBySysCool(AirLoopNum) = state.dataSimAirServingZones->MinCoolingEvz; - } else { - // Restore EvzByZoneCool() since it was reset by the current (but not highest Vot) design day - for (int ZonesCooledNum = 1; ZonesCooledNum <= numZonesCooled; ++ZonesCooledNum) { - int TermUnitSizingIndex = - state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); - state.dataSize->EvzByZoneCool(TermUnitSizingIndex) = state.dataSize->EvzByZoneCoolPrev(TermUnitSizingIndex); - } - } + if (finalSysSizing.OAAutoSized && sysSizing.DesHeatVolFlow > 0) { + int numZonesHeated = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated; + state.dataSimAirServingZones->MinHeatingEvz = 1.0; + state.dataSize->VozSumHtgBySys(AirLoopNum) = 0.0; + if (numZonesHeated > 0) { + computeHeatVentEffAndVozSum(state, + finalSysSizing, + AirLoopNum, + numZonesHeated, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex, + NumZonesCooled, + &state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex); + } else { + computeHeatVentEffAndVozSum(state, + finalSysSizing, + AirLoopNum, + NumZonesCooled, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex, + NumZonesCooled, + nullptr); } + + updateHeatVRPVot(state, finalSysSizing, AirLoopNum, numZonesHeated, NumZonesCooled); } + } else { // error + } + sysSizing.DesMainVolFlow = max(sysSizing.DesCoolVolFlow, sysSizing.DesHeatVolFlow); + // this should also be as least as big as is needed for Vot + } break; + case DataSizing::SizingConcurrence::NonCoincident: { + if (finalSysSizing.SystemOAMethod == SysOAMethod::ZoneSum) { + updateZoneSumVolFlows(state, + sysSizing, + finalSysSizing, + AirLoopNum, + NumZonesCooled, + NumZonesHeated, + sysSizing.NonCoinCoolMassFlow, + sysSizing.NonCoinHeatMassFlow); + } else if (finalSysSizing.SystemOAMethod == SysOAMethod::VRP || + finalSysSizing.SystemOAMethod == SysOAMethod::SP) { // Ventilation Rate and Simplified Procedure + // cooling + sysSizing.DesCoolVolFlow = sysSizing.NonCoinCoolMassFlow / state.dataEnvrn->StdRhoAir; + updateCoolVRPEvzVot(state, sysSizing, finalSysSizing, AirLoopNum); // heating sysSizing.DesHeatVolFlow = sysSizing.NonCoinHeatMassFlow / state.dataEnvrn->StdRhoAir; @@ -6256,36 +6631,7 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn } } - if (state.dataSimAirServingZones->MinHeatingEvz > 0) { - // Std 62.1-2010, section 6.2.5.4: Eq. 6.6 - // (However, I don't think people diversity can be done correctly in E+ Sizing so assuming D=1 in this - // equation - // Vou = Diversity*(Rp*Pz) + Ra*Az - state.dataSimAirServingZones->Vou = finalSysSizing.SysUncOA; - state.dataSimAirServingZones->Vot = state.dataSimAirServingZones->Vou / state.dataSimAirServingZones->MinHeatingEvz; - if (state.dataSimAirServingZones->Vot > state.dataSize->VotHtgBySys(AirLoopNum)) { - // This might be the cooling design day so only update if Vot is larger than the previous - state.dataSize->VotHtgBySys(AirLoopNum) = state.dataSimAirServingZones->Vot; - state.dataSize->XsBySysHeat(AirLoopNum) = state.dataSimAirServingZones->Xs; - state.dataSize->EvzMinBySysHeat(AirLoopNum) = state.dataSimAirServingZones->MinHeatingEvz; - } else { - // Restore EvzByZoneHeat() since it was just reset by the current (but not highest Vot) design day - // This kludge is probably because inside EndDay block and code gets called for each design day. - if (numZonesHeated > 0) { - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= numZonesHeated; ++ZonesHeatedNum) { - int TermUnitSizingIndex = - state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex(ZonesHeatedNum); - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = state.dataSize->EvzByZoneHeatPrev(TermUnitSizingIndex); - } - } else { - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesCooled; ++ZonesHeatedNum) { - int TermUnitSizingIndex = - state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesHeatedNum); - state.dataSize->EvzByZoneHeat(TermUnitSizingIndex) = state.dataSize->EvzByZoneHeatPrev(TermUnitSizingIndex); - } - } - } - } + updateHeatVRPVot(state, finalSysSizing, AirLoopNum, numZonesHeated, NumZonesCooled); } } else { // error } @@ -6329,68 +6675,28 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn // ZoneEquipmentManager assumes all the air entering the zone goes into the return node. int TimeStepIndex; // zone time step index for (int CtrlZoneNum = 1; CtrlZoneNum <= state.dataGlobal->NumOfZones; ++CtrlZoneNum) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).IsControlled) { - continue; - } - // Use first non-zero airdistunit for now, if there is one - termunitsizingtempfrac = 1.0; int TermUnitSizingIndex = 0; - for (int InletNode = 1; InletNode <= state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).NumInletNodes; ++InletNode) { - TermUnitSizingIndex = state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).AirDistUnitCool(InletNode).TermUnitSizingIndex; - if (TermUnitSizingIndex == 0) { - continue; - } - termunitsizingtemp = (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); - termunitsizingtempfrac = (1.0 / termunitsizingtemp); - if (TermUnitSizingIndex > 0) { - break; - } - } - if (TermUnitSizingIndex == 0) { - continue; // Skip this if there are no terminal units + Real64 inducFrac = getInducRatTempFrac(state, CtrlZoneNum, TermUnitSizingIndex); + if (inducFrac == 0.0) { + continue; } - RetTempRise = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneRetTempAtCoolPeak - - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneTempAtCoolPeak; + auto &tzFinal = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex); + RetTempRise = tzFinal.ZoneRetTempAtCoolPeak - tzFinal.ZoneTempAtCoolPeak; if (RetTempRise > 0.01) { - // avoid possible compiler bug - // FinalZoneSizing(CtrlZoneNum)%ZoneRetTempAtCoolPeak = & - // FinalZoneSizing(CtrlZoneNum)%ZoneTempAtCoolPeak + RetTempRise * & - // (1.0d0/(1.0d0+TermUnitSizing(CtrlZoneNum)%InducRat)) - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneRetTempAtCoolPeak = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneTempAtCoolPeak + RetTempRise * termunitsizingtempfrac; - } - RetTempRise = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneRetTempAtHeatPeak - - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneTempAtHeatPeak; + tzFinal.ZoneRetTempAtCoolPeak = tzFinal.ZoneTempAtCoolPeak + RetTempRise * inducFrac; + } + RetTempRise = tzFinal.ZoneRetTempAtHeatPeak - tzFinal.ZoneTempAtHeatPeak; if (RetTempRise > 0.01) { - // avoid possible compiler bug - // FinalZoneSizing(CtrlZoneNum)%ZoneRetTempAtHeatPeak = & - // FinalZoneSizing(CtrlZoneNum)%ZoneTempAtHeatPeak + RetTempRise * & - // (1.0d0/(1.0d0+TermUnitSizing(CtrlZoneNum)%InducRat)) - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneRetTempAtHeatPeak = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneTempAtHeatPeak + RetTempRise * termunitsizingtempfrac; + tzFinal.ZoneRetTempAtHeatPeak = tzFinal.ZoneTempAtHeatPeak + RetTempRise * inducFrac; } for (TimeStepIndex = 1; TimeStepIndex <= numOfTimeStepInDay; ++TimeStepIndex) { - RetTempRise = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).CoolZoneRetTempSeq(TimeStepIndex) - - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).CoolZoneTempSeq(TimeStepIndex); + RetTempRise = tzFinal.CoolZoneRetTempSeq(TimeStepIndex) - tzFinal.CoolZoneTempSeq(TimeStepIndex); if (RetTempRise > 0.01) { - // avoid possible compiler bug - // FinalZoneSizing(CtrlZoneNum)%CoolZoneRetTempSeq(TimeStepIndex) = & - // FinalZoneSizing(CtrlZoneNum)%CoolZoneTempSeq(TimeStepIndex) + RetTempRise * & - // (1.0d0/(1.0d0+TermUnitSizing(CtrlZoneNum)%InducRat)) - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).CoolZoneRetTempSeq(TimeStepIndex) = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).CoolZoneTempSeq(TimeStepIndex) + - RetTempRise * termunitsizingtempfrac; + tzFinal.CoolZoneRetTempSeq(TimeStepIndex) = tzFinal.CoolZoneTempSeq(TimeStepIndex) + RetTempRise * inducFrac; } - RetTempRise = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).HeatZoneRetTempSeq(TimeStepIndex) - - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).HeatZoneTempSeq(TimeStepIndex); + RetTempRise = tzFinal.HeatZoneRetTempSeq(TimeStepIndex) - tzFinal.HeatZoneTempSeq(TimeStepIndex); if (RetTempRise > 0.01) { - // avoid possible compiler bug - // FinalZoneSizing(CtrlZoneNum)%HeatZoneRetTempSeq(TimeStepIndex) = & - // FinalZoneSizing(CtrlZoneNum)%HeatZoneTempSeq(TimeStepIndex) + RetTempRise * & - // (1.0d0/(1.0d0+TermUnitSizing(CtrlZoneNum)%InducRat)) - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).HeatZoneRetTempSeq(TimeStepIndex) = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).HeatZoneTempSeq(TimeStepIndex) + - RetTempRise * termunitsizingtempfrac; + tzFinal.HeatZoneRetTempSeq(TimeStepIndex) = tzFinal.HeatZoneTempSeq(TimeStepIndex) + RetTempRise * inducFrac; } } } @@ -6409,32 +6715,8 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn state.dataSize->SysSizPeakDDNum(AirLoopNum).cSensCoolPeakDDDate = state.dataSize->DesDayWeath(DDNum).DateString; state.dataSize->SensCoolCapTemp(AirLoopNum) = sysSizing.SensCoolCap; if (sysSizing.coolingPeakLoad == DataSizing::PeakLoad::SensibleCooling) { - state.dataSize->CalcSysSizing(AirLoopNum).DesCoolVolFlow = sysSizing.DesCoolVolFlow; - state.dataSize->CalcSysSizing(AirLoopNum).CoolDesDay = sysSizing.CoolDesDay; - // state.dataSize->CalcSysSizing( AirLoopNum ).CoinCoolMassFlow = SysSizing( DDNum, AirLoopNum ).CoinCoolMassFlow; - state.dataSize->CalcSysSizing(AirLoopNum).MassFlowAtCoolPeak = sysSizing.MassFlowAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).SensCoolCap = sysSizing.SensCoolCap; - state.dataSize->CalcSysSizing(AirLoopNum).TotCoolCap = sysSizing.TotCoolCap; - state.dataSize->CalcSysSizing(AirLoopNum).CoolFlowSeq = sysSizing.CoolFlowSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SumZoneCoolLoadSeq = sysSizing.SumZoneCoolLoadSeq; - state.dataSize->CalcSysSizing(AirLoopNum).CoolZoneAvgTempSeq = sysSizing.CoolZoneAvgTempSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SensCoolCapSeq = sysSizing.SensCoolCapSeq; - state.dataSize->CalcSysSizing(AirLoopNum).TotCoolCapSeq = sysSizing.TotCoolCapSeq; - state.dataSize->CalcSysSizing(AirLoopNum).MixTempAtCoolPeak = sysSizing.MixTempAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).RetTempAtCoolPeak = sysSizing.RetTempAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).MixHumRatAtCoolPeak = sysSizing.MixHumRatAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).RetHumRatAtCoolPeak = sysSizing.RetHumRatAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).OutTempAtCoolPeak = sysSizing.OutTempAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).OutHumRatAtCoolPeak = sysSizing.OutHumRatAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).SysCoolRetTempSeq = sysSizing.SysCoolRetTempSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysCoolRetHumRatSeq = sysSizing.SysCoolRetHumRatSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysCoolOutTempSeq = sysSizing.SysCoolOutTempSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysCoolOutHumRatSeq = sysSizing.SysCoolOutHumRatSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysDOASHeatAddSeq = sysSizing.SysDOASHeatAddSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysDOASLatAddSeq = sysSizing.SysDOASLatAddSeq; + copyCoolPeakToCalcSysSizing(state.dataSize->CalcSysSizing(AirLoopNum), sysSizing); state.dataSize->CalcSysSizing(AirLoopNum).SysCoolCoinSpaceSens = sysSizing.SysCoolCoinSpaceSens; - state.dataSize->CalcSysSizing(AirLoopNum).SysDesCoolLoad = sysSizing.SysDesCoolLoad; - state.dataSize->CalcSysSizing(AirLoopNum).SysCoolLoadTimeStepPk = sysSizing.SysCoolLoadTimeStepPk; } } @@ -6443,31 +6725,7 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn state.dataSize->SysSizPeakDDNum(AirLoopNum).cTotCoolPeakDDDate = state.dataSize->DesDayWeath(DDNum).DateString; state.dataSize->TotCoolCapTemp(AirLoopNum) = sysSizing.TotCoolCap; if (sysSizing.coolingPeakLoad == DataSizing::PeakLoad::TotalCooling) { - state.dataSize->CalcSysSizing(AirLoopNum).DesCoolVolFlow = sysSizing.DesCoolVolFlow; - state.dataSize->CalcSysSizing(AirLoopNum).CoolDesDay = sysSizing.CoolDesDay; - // state.dataSize->CalcSysSizing( AirLoopNum ).CoinCoolMassFlow = SysSizing( DDNum, AirLoopNum ).CoinCoolMassFlow; - state.dataSize->CalcSysSizing(AirLoopNum).MassFlowAtCoolPeak = sysSizing.MassFlowAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).SensCoolCap = sysSizing.SensCoolCap; - state.dataSize->CalcSysSizing(AirLoopNum).TotCoolCap = sysSizing.TotCoolCap; - state.dataSize->CalcSysSizing(AirLoopNum).CoolFlowSeq = sysSizing.CoolFlowSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SumZoneCoolLoadSeq = sysSizing.SumZoneCoolLoadSeq; - state.dataSize->CalcSysSizing(AirLoopNum).CoolZoneAvgTempSeq = sysSizing.CoolZoneAvgTempSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SensCoolCapSeq = sysSizing.SensCoolCapSeq; - state.dataSize->CalcSysSizing(AirLoopNum).TotCoolCapSeq = sysSizing.TotCoolCapSeq; - state.dataSize->CalcSysSizing(AirLoopNum).MixTempAtCoolPeak = sysSizing.MixTempAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).RetTempAtCoolPeak = sysSizing.RetTempAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).MixHumRatAtCoolPeak = sysSizing.MixHumRatAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).RetHumRatAtCoolPeak = sysSizing.RetHumRatAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).OutTempAtCoolPeak = sysSizing.OutTempAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).OutHumRatAtCoolPeak = sysSizing.OutHumRatAtCoolPeak; - state.dataSize->CalcSysSizing(AirLoopNum).SysCoolRetTempSeq = sysSizing.SysCoolRetTempSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysCoolRetHumRatSeq = sysSizing.SysCoolRetHumRatSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysCoolOutTempSeq = sysSizing.SysCoolOutTempSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysCoolOutHumRatSeq = sysSizing.SysCoolOutHumRatSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysDOASHeatAddSeq = sysSizing.SysDOASHeatAddSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysDOASLatAddSeq = sysSizing.SysDOASLatAddSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysDesCoolLoad = sysSizing.SysDesCoolLoad; - state.dataSize->CalcSysSizing(AirLoopNum).SysCoolLoadTimeStepPk = sysSizing.SysCoolLoadTimeStepPk; + copyCoolPeakToCalcSysSizing(state.dataSize->CalcSysSizing(AirLoopNum), sysSizing); } state.dataSize->CalcSysSizing(AirLoopNum).SysCoolCoinSpaceSens = sysSizing.SysCoolCoinSpaceSens; } @@ -6481,34 +6739,7 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn if (sysSizing.HeatCap > state.dataSize->CalcSysSizing(AirLoopNum).HeatCap) { state.dataSize->SysSizPeakDDNum(AirLoopNum).HeatPeakDD = DDNum; state.dataSize->SysSizPeakDDNum(AirLoopNum).cHeatPeakDDDate = state.dataSize->DesDayWeath(DDNum).DateString; - state.dataSize->CalcSysSizing(AirLoopNum).DesHeatVolFlow = sysSizing.DesHeatVolFlow; - state.dataSize->CalcSysSizing(AirLoopNum).HeatDesDay = sysSizing.HeatDesDay; - state.dataSize->CalcSysSizing(AirLoopNum).CoinHeatMassFlow = sysSizing.CoinHeatMassFlow; - state.dataSize->CalcSysSizing(AirLoopNum).HeatCap = sysSizing.HeatCap; - state.dataSize->CalcSysSizing(AirLoopNum).PreheatCap = sysSizing.PreheatCap; - state.dataSize->CalcSysSizing(AirLoopNum).HeatFlowSeq = sysSizing.HeatFlowSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SumZoneHeatLoadSeq = sysSizing.SumZoneHeatLoadSeq; - state.dataSize->CalcSysSizing(AirLoopNum).HeatCapSeq = sysSizing.HeatCapSeq; - state.dataSize->CalcSysSizing(AirLoopNum).HeatZoneAvgTempSeq = sysSizing.HeatZoneAvgTempSeq; - state.dataSize->CalcSysSizing(AirLoopNum).PreheatCapSeq = sysSizing.PreheatCapSeq; - state.dataSize->CalcSysSizing(AirLoopNum).HeatMixTemp = sysSizing.HeatMixTemp; - state.dataSize->CalcSysSizing(AirLoopNum).HeatRetTemp = sysSizing.HeatRetTemp; - state.dataSize->CalcSysSizing(AirLoopNum).HeatMixHumRat = sysSizing.HeatMixHumRat; - state.dataSize->CalcSysSizing(AirLoopNum).HeatRetHumRat = sysSizing.HeatRetHumRat; - state.dataSize->CalcSysSizing(AirLoopNum).HeatOutTemp = sysSizing.HeatOutTemp; - state.dataSize->CalcSysSizing(AirLoopNum).HeatOutHumRat = sysSizing.HeatOutHumRat; - state.dataSize->CalcSysSizing(AirLoopNum).SysHeatRetTempSeq = sysSizing.SysHeatRetTempSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysHeatRetHumRatSeq = sysSizing.SysHeatRetHumRatSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysHeatOutTempSeq = sysSizing.SysHeatOutTempSeq; - state.dataSize->CalcSysSizing(AirLoopNum).SysHeatOutHumRatSeq = sysSizing.SysHeatOutHumRatSeq; - - state.dataSize->CalcSysSizing(AirLoopNum).SysHeatCoilTimeStepPk = sysSizing.SysHeatCoilTimeStepPk; - - state.dataSize->CalcSysSizing(AirLoopNum).SysHeatAirTimeStepPk = sysSizing.SysHeatAirTimeStepPk; - state.dataSize->CalcSysSizing(AirLoopNum).HeatDDNum = DDNum; - state.dataSize->CalcSysSizing(AirLoopNum).SysHeatCoinSpaceSens = sysSizing.SysHeatCoinSpaceSens; - state.dataSize->CalcSysSizing(AirLoopNum).SysDesHeatLoad = sysSizing.SysDesHeatLoad; - state.dataSize->CalcSysSizing(AirLoopNum).SysHeatLoadTimeStepPk = sysSizing.SysHeatLoadTimeStepPk; + copyHeatPeakToCalcSysSizing(state.dataSize->CalcSysSizing(AirLoopNum), sysSizing, DDNum); } } @@ -6521,77 +6752,26 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn int NumZonesCooled = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled; int NumZonesHeated = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated; SysCoolRetTemp = 0.0; - OutAirFrac = 0.0; SysCoolMixTemp = 0.0; SysSensCoolCap = 0.0; SysTotCoolCap = 0.0; - OutAirTemp = 0.0; - OutAirHumRat = 0.0; SysCoolMixHumRat = 0.0; SysCoolRetHumRat = 0.0; SysCoolOutTemp = 0.0; SysCoolOutHumRat = 0.0; - for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { // loop over cooled zones - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); - auto const &termUnitSizing = state.dataSize->TermUnitSizing(TermUnitSizingIndex); - // save the system cooling supply air temp - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesCoolCoilInTempTU = - state.dataSize->CalcSysSizing(AirLoopNum).CoolSupTemp; - // save the system cooling supply air hum rat - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesCoolCoilInHumRatTU = - state.dataSize->CalcSysSizing(AirLoopNum).CoolSupHumRat; - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesCoolMassFlow <= 0.0) { - continue; - } - Real64 coolMassFlow = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex) - .DesCoolMassFlow; // already scaled for term unit sizing in Updatestate.dataSize->TermUnitFinalZoneSizing - state.dataSize->CalcSysSizing(AirLoopNum).NonCoinCoolMassFlow += coolMassFlow / (1.0 + termUnitSizing.InducRat); - SysCoolRetTemp += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneRetTempAtCoolPeak * coolMassFlow / - (1.0 + termUnitSizing.InducRat); - SysCoolRetHumRat += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneHumRatAtCoolPeak * coolMassFlow / - (1.0 + termUnitSizing.InducRat); - int CoolDDNum = 0; // design day index of a peak cooling day - int CoolTimeStepNum = 0; // time step index (in day) of a cooling peak - CoolDDNum = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).CoolDDNum; - CoolTimeStepNum = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).TimeStepNumAtCoolMax; - if (CoolDDNum == 0) { - auto const &zoneCFS = state.dataSize->CalcFinalZoneSizing(state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneNum); - OutAirTemp += zoneCFS.CoolOutTemp * coolMassFlow / (1.0 + termUnitSizing.InducRat); - OutAirHumRat += zoneCFS.CoolOutHumRat * coolMassFlow / (1.0 + termUnitSizing.InducRat); - } else { - OutAirTemp += state.dataSize->DesDayWeath(CoolDDNum).Temp(CoolTimeStepNum) * coolMassFlow / (1.0 + termUnitSizing.InducRat); - OutAirHumRat += state.dataSize->DesDayWeath(CoolDDNum).HumRat(CoolTimeStepNum) * coolMassFlow / (1.0 + termUnitSizing.InducRat); - } - } - if (state.dataSize->CalcSysSizing(AirLoopNum).NonCoinCoolMassFlow > 0.0) { - SysCoolRetTemp /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinCoolMassFlow; - SysCoolRetHumRat /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinCoolMassFlow; - OutAirTemp /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinCoolMassFlow; - OutAirHumRat /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinCoolMassFlow; - SysCoolOutTemp = OutAirTemp; - SysCoolOutHumRat = OutAirHumRat; - RhoAir = state.dataEnvrn->StdRhoAir; - if (state.dataSize->CalcSysSizing(AirLoopNum).CoolOAOption == OAControl::MinOA) { - OutAirFrac = RhoAir * state.dataSize->CalcSysSizing(AirLoopNum).DesOutAirVolFlow / - state.dataSize->CalcSysSizing(AirLoopNum).NonCoinCoolMassFlow; - OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - } else { - OutAirFrac = 1.0; - } - SysCoolMixTemp = OutAirTemp * OutAirFrac + SysCoolRetTemp * (1.0 - OutAirFrac); - SysCoolMixHumRat = OutAirHumRat * OutAirFrac + SysCoolRetHumRat * (1.0 - OutAirFrac); - SysSensCoolCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * state.dataSize->CalcSysSizing(AirLoopNum).NonCoinCoolMassFlow * - (SysCoolMixTemp - state.dataSize->CalcSysSizing(AirLoopNum).CoolSupTemp); - SysSensCoolCap = max(0.0, SysSensCoolCap); - SysTotCoolCap = state.dataSize->CalcSysSizing(AirLoopNum).NonCoinCoolMassFlow * - (PsyHFnTdbW(SysCoolMixTemp, SysCoolMixHumRat) - PsyHFnTdbW(state.dataSize->CalcSysSizing(AirLoopNum).CoolSupTemp, - state.dataSize->CalcSysSizing(AirLoopNum).CoolSupHumRat)); - SysTotCoolCap = max(0.0, SysTotCoolCap); - } + accumulateNonCoinCoolZoneData(state, + AirLoopNum, + NumZonesCooled, + SysCoolRetTemp, + SysCoolRetHumRat, + SysCoolOutTemp, + SysCoolOutHumRat, + SysCoolMixTemp, + SysCoolMixHumRat, + SysSensCoolCap, + SysTotCoolCap); - int HeatDDNum = 0; // design day index of a peak cooling day - int HeatTimeStepNum = 0; // time step index (in day) of a cooling peak SysHeatRetTemp = 0.0; OutAirFrac = 0.0; SysHeatMixTemp = 0.0; @@ -6604,118 +6784,33 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn SysHeatOutHumRat = 0.0; if (NumZonesHeated > 0) { // IF there are centrally heated zones - - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesHeated; ++ZonesHeatedNum) { // loop over the heated zones - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex(ZonesHeatedNum); - auto const &termUnitSizing = state.dataSize->TermUnitSizing(TermUnitSizingIndex); - // save the system heating supply air temp - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatCoilInTempTU = - state.dataSize->CalcSysSizing(AirLoopNum).HeatSupTemp; - // save the system heating supply air hum rat - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatCoilInHumRatTU = - state.dataSize->CalcSysSizing(AirLoopNum).HeatSupHumRat; - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatMassFlow <= 0.0) { - continue; - } - Real64 heatMassFlow = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex) - .DesHeatMassFlow; // already scaled for term unit sizing in Updatestate.dataSize->TermUnitFinalZoneSizing - state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow += heatMassFlow / (1.0 + termUnitSizing.InducRat); - SysHeatRetTemp += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneRetTempAtHeatPeak * heatMassFlow / - (1.0 + termUnitSizing.InducRat); - SysHeatRetHumRat += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneHumRatAtHeatPeak * heatMassFlow / - (1.0 + termUnitSizing.InducRat); - HeatDDNum = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).HeatDDNum; - HeatTimeStepNum = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).TimeStepNumAtHeatMax; - if (HeatDDNum == 0) { - auto const &zoneCFS = - state.dataSize->CalcFinalZoneSizing(state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneNum); - OutAirTemp += zoneCFS.HeatOutTemp * heatMassFlow / (1.0 + termUnitSizing.InducRat); - OutAirHumRat += zoneCFS.HeatOutHumRat * heatMassFlow / (1.0 + termUnitSizing.InducRat); - } else { - OutAirTemp += state.dataSize->DesDayWeath(HeatDDNum).Temp(HeatTimeStepNum) * heatMassFlow / (1.0 + termUnitSizing.InducRat); - OutAirHumRat += - state.dataSize->DesDayWeath(HeatDDNum).HumRat(HeatTimeStepNum) * heatMassFlow / (1.0 + termUnitSizing.InducRat); - } - } - if (state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow > 0.0) { - SysHeatRetTemp /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow; - SysHeatRetHumRat /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow; - OutAirTemp /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow; - OutAirHumRat /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow; - SysHeatOutTemp = OutAirTemp; - SysHeatOutHumRat = OutAirHumRat; - RhoAir = state.dataEnvrn->StdRhoAir; - if (state.dataSize->CalcSysSizing(AirLoopNum).HeatOAOption == DataSizing::OAControl::MinOA) { - OutAirFrac = RhoAir * state.dataSize->CalcSysSizing(AirLoopNum).DesOutAirVolFlow / - state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow; - OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - } else { - OutAirFrac = 1.0; - } - SysHeatMixTemp = OutAirTemp * OutAirFrac + SysHeatRetTemp * (1.0 - OutAirFrac); - SysHeatMixHumRat = OutAirHumRat * OutAirFrac + SysHeatRetHumRat * (1.0 - OutAirFrac); - SysHeatCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow * - (state.dataSize->CalcSysSizing(AirLoopNum).HeatSupTemp - SysHeatMixTemp); - SysHeatCap = max(0.0, SysHeatCap); - } - + accumulateNonCoinHeatZoneData(state, + AirLoopNum, + NumZonesHeated, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex, + SysHeatRetTemp, + SysHeatRetHumRat, + OutAirTemp, + OutAirHumRat, + SysHeatOutTemp, + SysHeatOutHumRat, + SysHeatMixTemp, + SysHeatMixHumRat, + SysHeatCap); } else { // No centrally heated zones: use cooled zones - - for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { // loop over the cooled zones - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); - auto const &termUnitSizing = state.dataSize->TermUnitSizing(TermUnitSizingIndex); - // save the system heating supply air temp - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatCoilInTempTU = - state.dataSize->CalcSysSizing(AirLoopNum).HeatSupTemp; - // save the system heating supply air hum rat - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatCoilInHumRatTU = - state.dataSize->CalcSysSizing(AirLoopNum).HeatSupHumRat; - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesHeatMassFlow <= 0.0) { - continue; - } - Real64 heatMassFlow = - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex) - .DesHeatMassFlow; // already scaled for term unit sizing in Updatestate.dataSize->TermUnitFinalZoneSizing - state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow += heatMassFlow / (1.0 + termUnitSizing.InducRat); - SysHeatRetTemp += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneRetTempAtHeatPeak * heatMassFlow / - (1.0 + termUnitSizing.InducRat); - SysHeatRetHumRat += state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneHumRatAtHeatPeak * heatMassFlow / - (1.0 + termUnitSizing.InducRat); - HeatDDNum = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).HeatDDNum; - HeatTimeStepNum = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).TimeStepNumAtHeatMax; - if (HeatDDNum == 0) { - auto const &zoneCFS = - state.dataSize->CalcFinalZoneSizing(state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).ZoneNum); - OutAirTemp += zoneCFS.HeatOutTemp * heatMassFlow / (1.0 + termUnitSizing.InducRat); - OutAirHumRat += zoneCFS.HeatOutHumRat * heatMassFlow / (1.0 + termUnitSizing.InducRat); - } else { - OutAirTemp += state.dataSize->DesDayWeath(HeatDDNum).Temp(HeatTimeStepNum) * heatMassFlow / (1.0 + termUnitSizing.InducRat); - OutAirHumRat += - state.dataSize->DesDayWeath(HeatDDNum).HumRat(HeatTimeStepNum) * heatMassFlow / (1.0 + termUnitSizing.InducRat); - } - } - if (state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow > 0.0) { - SysHeatRetTemp /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow; - SysHeatRetHumRat /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow; - OutAirTemp /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow; - OutAirHumRat /= state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow; - SysHeatOutTemp = OutAirTemp; - SysHeatOutHumRat = OutAirHumRat; - RhoAir = state.dataEnvrn->StdRhoAir; - if (state.dataSize->CalcSysSizing(AirLoopNum).HeatOAOption == DataSizing::OAControl::MinOA) { - OutAirFrac = RhoAir * state.dataSize->CalcSysSizing(AirLoopNum).DesOutAirVolFlow / - state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow; - OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - } else { - OutAirFrac = 1.0; - } - SysHeatMixTemp = OutAirTemp * OutAirFrac + SysHeatRetTemp * (1.0 - OutAirFrac); - SysHeatMixHumRat = OutAirHumRat * OutAirFrac + SysHeatRetHumRat * (1.0 - OutAirFrac); - SysHeatCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * state.dataSize->CalcSysSizing(AirLoopNum).NonCoinHeatMassFlow * - (state.dataSize->CalcSysSizing(AirLoopNum).HeatSupTemp - SysHeatMixTemp); - SysHeatCap = max(0.0, SysHeatCap); - } + accumulateNonCoinHeatZoneData(state, + AirLoopNum, + NumZonesCooled, + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex, + SysHeatRetTemp, + SysHeatRetHumRat, + OutAirTemp, + OutAirHumRat, + SysHeatOutTemp, + SysHeatOutHumRat, + SysHeatMixTemp, + SysHeatMixHumRat, + SysHeatCap); } // move the noncoincident results into the system sizing array @@ -6755,70 +6850,7 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn // Move final system design data (calculated from zone data) to user design array for (std::size_t i = 0; i < state.dataSize->FinalSysSizing.size(); ++i) { - auto &z = state.dataSize->FinalSysSizing[i]; - auto &c = state.dataSize->CalcSysSizing[i]; - z.CoolDesDay = c.CoolDesDay; - z.HeatDesDay = c.HeatDesDay; - z.CoinCoolMassFlow = c.CoinCoolMassFlow; - z.CoinHeatMassFlow = c.CoinHeatMassFlow; - z.NonCoinCoolMassFlow = c.NonCoinCoolMassFlow; - z.NonCoinHeatMassFlow = c.NonCoinHeatMassFlow; - z.DesMainVolFlow = c.DesMainVolFlow; - z.DesHeatVolFlow = c.DesHeatVolFlow; - z.DesCoolVolFlow = c.DesCoolVolFlow; - z.MassFlowAtCoolPeak = c.MassFlowAtCoolPeak; - z.SensCoolCap = c.SensCoolCap; - z.TotCoolCap = c.TotCoolCap; - z.HeatCap = c.HeatCap; - z.PreheatCap = c.PreheatCap; - z.MixTempAtCoolPeak = c.MixTempAtCoolPeak; - z.MixHumRatAtCoolPeak = c.MixHumRatAtCoolPeak; - z.RetTempAtCoolPeak = c.RetTempAtCoolPeak; - z.RetHumRatAtCoolPeak = c.RetHumRatAtCoolPeak; - z.OutTempAtCoolPeak = c.OutTempAtCoolPeak; - z.OutHumRatAtCoolPeak = c.OutHumRatAtCoolPeak; - z.HeatMixTemp = c.HeatMixTemp; - z.HeatMixHumRat = c.HeatMixHumRat; - z.HeatRetTemp = c.HeatRetTemp; - z.HeatRetHumRat = c.HeatRetHumRat; - z.HeatOutTemp = c.HeatOutTemp; - z.HeatOutHumRat = c.HeatOutHumRat; - z.SysHeatCoilTimeStepPk = c.SysHeatCoilTimeStepPk; - z.SysHeatAirTimeStepPk = c.SysHeatAirTimeStepPk; - z.HeatDDNum = c.HeatDDNum; - z.SysCoolCoinSpaceSens = c.SysCoolCoinSpaceSens; - z.SysHeatCoinSpaceSens = c.SysHeatCoinSpaceSens; - z.SysDesCoolLoad = c.SysDesCoolLoad; - z.SysCoolLoadTimeStepPk = c.SysCoolLoadTimeStepPk; - z.SysDesHeatLoad = c.SysDesHeatLoad; - z.SysHeatLoadTimeStepPk = c.SysHeatLoadTimeStepPk; - } - - for (AirLoopNum = 1; AirLoopNum <= state.dataHVACGlobal->NumPrimaryAirSys; ++AirLoopNum) { - auto &finalSysSizing = state.dataSize->FinalSysSizing(AirLoopNum); - auto &calcSysSizing = state.dataSize->CalcSysSizing(AirLoopNum); - for (TimeStepIndex = 1; TimeStepIndex <= numOfTimeStepInDay; ++TimeStepIndex) { - finalSysSizing.HeatFlowSeq(TimeStepIndex) = calcSysSizing.HeatFlowSeq(TimeStepIndex); - finalSysSizing.CoolFlowSeq(TimeStepIndex) = calcSysSizing.CoolFlowSeq(TimeStepIndex); - finalSysSizing.SumZoneCoolLoadSeq(TimeStepIndex) = calcSysSizing.SumZoneCoolLoadSeq(TimeStepIndex); - finalSysSizing.SumZoneHeatLoadSeq(TimeStepIndex) = calcSysSizing.SumZoneHeatLoadSeq(TimeStepIndex); - finalSysSizing.CoolZoneAvgTempSeq(TimeStepIndex) = calcSysSizing.CoolZoneAvgTempSeq(TimeStepIndex); - finalSysSizing.HeatZoneAvgTempSeq(TimeStepIndex) = calcSysSizing.HeatZoneAvgTempSeq(TimeStepIndex); - finalSysSizing.SensCoolCapSeq(TimeStepIndex) = calcSysSizing.SensCoolCapSeq(TimeStepIndex); - finalSysSizing.TotCoolCapSeq(TimeStepIndex) = calcSysSizing.TotCoolCapSeq(TimeStepIndex); - finalSysSizing.HeatCapSeq(TimeStepIndex) = calcSysSizing.HeatCapSeq(TimeStepIndex); - finalSysSizing.PreheatCapSeq(TimeStepIndex) = calcSysSizing.PreheatCapSeq(TimeStepIndex); - finalSysSizing.SysCoolRetTempSeq(TimeStepIndex) = calcSysSizing.SysCoolRetTempSeq(TimeStepIndex); - finalSysSizing.SysCoolRetHumRatSeq(TimeStepIndex) = calcSysSizing.SysCoolRetHumRatSeq(TimeStepIndex); - finalSysSizing.SysHeatRetTempSeq(TimeStepIndex) = calcSysSizing.SysHeatRetTempSeq(TimeStepIndex); - finalSysSizing.SysHeatRetHumRatSeq(TimeStepIndex) = calcSysSizing.SysHeatRetHumRatSeq(TimeStepIndex); - finalSysSizing.SysCoolOutTempSeq(TimeStepIndex) = calcSysSizing.SysCoolOutTempSeq(TimeStepIndex); - finalSysSizing.SysCoolOutHumRatSeq(TimeStepIndex) = calcSysSizing.SysCoolOutHumRatSeq(TimeStepIndex); - finalSysSizing.SysHeatOutTempSeq(TimeStepIndex) = calcSysSizing.SysHeatOutTempSeq(TimeStepIndex); - finalSysSizing.SysHeatOutHumRatSeq(TimeStepIndex) = calcSysSizing.SysHeatOutHumRatSeq(TimeStepIndex); - finalSysSizing.SysDOASHeatAddSeq(TimeStepIndex) = calcSysSizing.SysDOASHeatAddSeq(TimeStepIndex); - finalSysSizing.SysDOASLatAddSeq(TimeStepIndex) = calcSysSizing.SysDOASLatAddSeq(TimeStepIndex); - } + copyCalcToFinalSysSizing(state.dataSize->FinalSysSizing[i], state.dataSize->CalcSysSizing[i]); } // Check for user input design system flow rates. Set the sizing ratios. @@ -6871,167 +6903,12 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn // Calculate the new user modified system design quantities if (std::abs(SysCoolSizingRat - 1.0) > 0.00001) { - - finalSysSizing.CoinCoolMassFlow = SysCoolSizingRat * calcSysSizing.CoinCoolMassFlow; - finalSysSizing.NonCoinCoolMassFlow = SysCoolSizingRat * calcSysSizing.NonCoinCoolMassFlow; - finalSysSizing.DesCoolVolFlow = SysCoolSizingRat * calcSysSizing.DesCoolVolFlow; - finalSysSizing.MassFlowAtCoolPeak = SysCoolSizingRat * calcSysSizing.MassFlowAtCoolPeak; - - if (finalSysSizing.DesCoolVolFlow > 0.0) { - - for (TimeStepIndex = 1; TimeStepIndex <= numOfTimeStepInDay; ++TimeStepIndex) { - - if (calcSysSizing.CoolFlowSeq(TimeStepIndex) > 0.0) { - - finalSysSizing.CoolFlowSeq(TimeStepIndex) = SysCoolSizingRat * calcSysSizing.CoolFlowSeq(TimeStepIndex); - if (finalSysSizing.CoolOAOption == OAControl::MinOA) { - OutAirFrac = RhoAir * finalSysSizing.DesOutAirVolFlow / finalSysSizing.CoolFlowSeq(TimeStepIndex); - OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - } else { - OutAirFrac = 1.0; - } - SysCoolMixTemp = finalSysSizing.SysCoolOutTempSeq(TimeStepIndex) * OutAirFrac + - finalSysSizing.SysCoolRetTempSeq(TimeStepIndex) * (1.0 - OutAirFrac); - SysCoolMixHumRat = finalSysSizing.SysCoolOutHumRatSeq(TimeStepIndex) * OutAirFrac + - finalSysSizing.SysCoolRetHumRatSeq(TimeStepIndex) * (1.0 - OutAirFrac); - SysSensCoolCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * finalSysSizing.CoolFlowSeq(TimeStepIndex) * - (SysCoolMixTemp - finalSysSizing.CoolSupTemp); - SysSensCoolCap = max(0.0, SysSensCoolCap); - SysTotCoolCap = - finalSysSizing.CoolFlowSeq(TimeStepIndex) * - (PsyHFnTdbW(SysCoolMixTemp, SysCoolMixHumRat) - PsyHFnTdbW(finalSysSizing.CoolSupTemp, finalSysSizing.CoolSupHumRat)); - SysTotCoolCap = max(0.0, SysTotCoolCap); - finalSysSizing.SensCoolCapSeq(TimeStepIndex) = SysSensCoolCap; - finalSysSizing.TotCoolCapSeq(TimeStepIndex) = SysTotCoolCap; - } - } - - if (finalSysSizing.CoolOAOption == OAControl::MinOA) { - OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesCoolVolFlow; - OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - } else { - OutAirFrac = 1.0; - } - finalSysSizing.MixTempAtCoolPeak = - finalSysSizing.OutTempAtCoolPeak * OutAirFrac + finalSysSizing.RetTempAtCoolPeak * (1.0 - OutAirFrac); - finalSysSizing.MixHumRatAtCoolPeak = - finalSysSizing.OutHumRatAtCoolPeak * OutAirFrac + finalSysSizing.RetHumRatAtCoolPeak * (1.0 - OutAirFrac); - finalSysSizing.SensCoolCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * RhoAir * finalSysSizing.DesCoolVolFlow * - (finalSysSizing.MixTempAtCoolPeak - finalSysSizing.CoolSupTemp); - finalSysSizing.SensCoolCap = max(0.0, finalSysSizing.SensCoolCap); - finalSysSizing.TotCoolCap = RhoAir * finalSysSizing.DesCoolVolFlow * - (PsyHFnTdbW(finalSysSizing.MixTempAtCoolPeak, finalSysSizing.MixHumRatAtCoolPeak) - - PsyHFnTdbW(finalSysSizing.CoolSupTemp, finalSysSizing.CoolSupHumRat)); - finalSysSizing.TotCoolCap = max(0.0, finalSysSizing.TotCoolCap); - } - - // take account of the user input system flow rates and alter the zone flow rates to match - for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); - if ((SysCoolSizingRat != 1.0) && (finalSysSizing.loadSizingType == DataSizing::LoadSizing::Ventilation) && - (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).MinOA > 0.0)) { - // size on ventilation load - if (state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).MinOA > 0.0) { - ZoneOARatio = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).MinOA / - max(state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).DesCoolVolFlow, - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).MinOA); - ZoneOARatio *= (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); - } else { - ZoneOARatio = 0.0; - } - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).scaleZoneCooling(ZoneOARatio); - } else if ((SysCoolSizingRat > 1.0) || - (SysCoolSizingRat < 1.0 && finalSysSizing.SizingOption == DataSizing::SizingConcurrence::NonCoincident)) { - // size on user input system design flows - state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex).scaleZoneCooling(SysCoolSizingRat); - } - } + applyCoolSizingRat(state, finalSysSizing, calcSysSizing, AirLoopNum, NumZonesCooled, numOfTimeStepInDay, SysCoolSizingRat); } if (std::abs(SysHeatSizingRat - 1.0) > 0.00001) { - - finalSysSizing.CoinHeatMassFlow = SysHeatSizingRat * calcSysSizing.CoinHeatMassFlow; - finalSysSizing.NonCoinHeatMassFlow = SysHeatSizingRat * calcSysSizing.NonCoinHeatMassFlow; - finalSysSizing.DesHeatVolFlow = SysHeatSizingRat * calcSysSizing.DesHeatVolFlow; - - if (finalSysSizing.DesHeatVolFlow > 0.0) { - - for (TimeStepIndex = 1; TimeStepIndex <= numOfTimeStepInDay; ++TimeStepIndex) { - - if (calcSysSizing.HeatFlowSeq(TimeStepIndex) > 0.0) { - - finalSysSizing.HeatFlowSeq(TimeStepIndex) = SysHeatSizingRat * calcSysSizing.HeatFlowSeq(TimeStepIndex); - if (finalSysSizing.HeatOAOption == DataSizing::OAControl::MinOA) { - OutAirFrac = RhoAir * finalSysSizing.DesOutAirVolFlow / finalSysSizing.HeatFlowSeq(TimeStepIndex); - OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - } else { - OutAirFrac = 1.0; - } - SysHeatMixTemp = finalSysSizing.SysHeatOutTempSeq(TimeStepIndex) * OutAirFrac + - finalSysSizing.SysHeatRetTempSeq(TimeStepIndex) * (1.0 - OutAirFrac); - SysHeatMixHumRat = finalSysSizing.SysHeatOutHumRatSeq(TimeStepIndex) * OutAirFrac + - finalSysSizing.SysHeatRetHumRatSeq(TimeStepIndex) * (1.0 - OutAirFrac); - SysHeatCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * finalSysSizing.HeatFlowSeq(TimeStepIndex) * - (finalSysSizing.HeatSupTemp - SysHeatMixTemp); - SysHeatCap = max(0.0, SysHeatCap); - finalSysSizing.HeatCapSeq(TimeStepIndex) = SysHeatCap; - } - } - - if (finalSysSizing.HeatOAOption == DataSizing::OAControl::MinOA) { - OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesHeatVolFlow; - OutAirFrac = min(1.0, max(0.0, OutAirFrac)); - } else { - OutAirFrac = 1.0; - } - finalSysSizing.HeatMixTemp = finalSysSizing.HeatOutTemp * OutAirFrac + finalSysSizing.HeatRetTemp * (1.0 - OutAirFrac); - finalSysSizing.HeatMixHumRat = finalSysSizing.HeatOutHumRat * OutAirFrac + finalSysSizing.HeatRetHumRat * (1.0 - OutAirFrac); - finalSysSizing.HeatCap = PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * RhoAir * finalSysSizing.DesHeatVolFlow * - (finalSysSizing.HeatSupTemp - finalSysSizing.HeatMixTemp); - finalSysSizing.HeatCap = max(0.0, finalSysSizing.HeatCap); - } - // take account of the user input system flow rates and alter the zone flow rates to match (for terminal unit sizing) - if (NumZonesHeated > 0) { // IF there are centrally heated zones - for (int ZonesHeatedNum = 1; ZonesHeatedNum <= NumZonesHeated; ++ZonesHeatedNum) { // loop over the heated zones - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatSizingIndex(ZonesHeatedNum); - auto &termUnitFinalZoneSizing = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex); - if ((SysHeatSizingRat != 1.0) && (finalSysSizing.loadSizingType == DataSizing::LoadSizing::Ventilation) && - (termUnitFinalZoneSizing.MinOA > 0.0)) { - // size on ventilation load - ZoneOARatio = termUnitFinalZoneSizing.MinOA / max(termUnitFinalZoneSizing.DesHeatVolFlow, termUnitFinalZoneSizing.MinOA); - ZoneOARatio *= (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); - termUnitFinalZoneSizing.scaleZoneHeating(ZoneOARatio); - } else if ((SysHeatSizingRat > 1.0) || - (SysHeatSizingRat < 1.0 && finalSysSizing.SizingOption == DataSizing::SizingConcurrence::NonCoincident)) { - // size on user input system design flows - termUnitFinalZoneSizing.scaleZoneHeating(SysHeatSizingRat); - } - } - } else { // No centrally heated zones: use cooled zones - for (int ZonesCooledNum = 1; ZonesCooledNum <= NumZonesCooled; ++ZonesCooledNum) { // loop over the cooled zones - int TermUnitSizingIndex = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolSizingIndex(ZonesCooledNum); - auto &termUnitFinalZoneSizing = state.dataSize->TermUnitFinalZoneSizing(TermUnitSizingIndex); - if ((SysHeatSizingRat != 1.0) && (finalSysSizing.loadSizingType == DataSizing::LoadSizing::Ventilation) && - (termUnitFinalZoneSizing.MinOA <= 0.0)) { - ShowWarningError(state, - EnergyPlus::format("FinalSystemSizing: AirLoop=\"{}\", Requested sizing on Ventilation,", - state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).AirLoopName)); - ShowContinueError(state, - EnergyPlus::format("but Zone has no design OA Flow. Zone=\"{}\".", termUnitFinalZoneSizing.ZoneName)); - } - if ((SysHeatSizingRat != 1.0) && (finalSysSizing.loadSizingType == DataSizing::LoadSizing::Ventilation) && - (termUnitFinalZoneSizing.MinOA > 0.0)) { - // size on ventilation load - ZoneOARatio = termUnitFinalZoneSizing.MinOA / max(termUnitFinalZoneSizing.DesHeatVolFlow, termUnitFinalZoneSizing.MinOA); - ZoneOARatio *= (1.0 + state.dataSize->TermUnitSizing(TermUnitSizingIndex).InducRat); - termUnitFinalZoneSizing.scaleZoneHeating(ZoneOARatio); - } else if ((SysHeatSizingRat != 1.0) && (finalSysSizing.loadSizingType == DataSizing::LoadSizing::Ventilation) && - (termUnitFinalZoneSizing.MinOA > 0.0)) { - // size on user input system design flows - termUnitFinalZoneSizing.scaleZoneHeating(SysHeatSizingRat); - } - } - } + applyHeatSizingRat( + state, finalSysSizing, calcSysSizing, AirLoopNum, NumZonesCooled, NumZonesHeated, numOfTimeStepInDay, SysHeatSizingRat); } finalSysSizing.DesMainVolFlow = max(finalSysSizing.DesCoolVolFlow, finalSysSizing.DesHeatVolFlow); @@ -7106,111 +6983,7 @@ void UpdateSysSizing(EnergyPlusData &state, Constant::CallIndicator const CallIn } // write out the sys design calc results - - print(state.files.ssz, "Time"); - int I; // write statement index - int J; // write statement index - for (I = 1; I <= state.dataHVACGlobal->NumPrimaryAirSys; ++I) { - for (J = 1; J <= state.dataEnvrn->TotDesDays + state.dataEnvrn->TotRunDesPersDays; ++J) { - constexpr const char *SSizeFmt12("{}{}{}{:2}{}{}{}{}{:2}{}{}{}{}{:2}{}{}{}{}{:2}{}{}{}{}{:2}{}"); - print(state.files.ssz, - SSizeFmt12, - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).AirPriLoopName, - ":DesPer", - J, - ":Des Heat Mass Flow [kg/s]", - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).AirPriLoopName, - ":DesPer", - J, - ":Des Heat Cap [W]", - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).AirPriLoopName, - ":DesPer", - J, - ":Des Cool Mass Flow [kg/s]", - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).AirPriLoopName, - ":DesPer", - J, - ":Des Sens Cool Cap [W]", - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).AirPriLoopName, - ":DesPer", - J, - ":Des Tot Cool Cap [W]"); - } - } - print(state.files.ssz, "\n"); - // HourFrac = 0.0 - int Minutes = 0; // Current Minutes Counter - TimeStepIndex = 0; - for (int HourCounter = 1; HourCounter <= 24; ++HourCounter) { // Hour Counter - for (int TimeStepCounter = 1; TimeStepCounter <= state.dataGlobal->TimeStepsInHour; ++TimeStepCounter) { // Time Step Counter - ++TimeStepIndex; - Minutes += state.dataGlobal->MinutesInTimeStep; - int HourPrint; // Hour to print (timestamp) - if (Minutes == 60) { - Minutes = 0; - HourPrint = HourCounter; - } else { - HourPrint = HourCounter - 1; - } - constexpr const char *SSizeFmt20("{:02}:{:02}:00"); - print(state.files.ssz, SSizeFmt20, HourPrint, Minutes); - for (I = 1; I <= state.dataHVACGlobal->NumPrimaryAirSys; ++I) { - for (J = 1; J <= state.dataEnvrn->TotDesDays + state.dataEnvrn->TotRunDesPersDays; ++J) { - constexpr const char *SSizeFmt22("{}{:12.6E}{}{:12.6E}{}{:12.6E}{}{:12.6E}{}{:12.6E}"); - - print(state.files.ssz, - SSizeFmt22, - state.dataSize->SizingFileColSep, - state.dataSize->SysSizing(J, I).HeatFlowSeq(TimeStepIndex), - state.dataSize->SizingFileColSep, - state.dataSize->SysSizing(J, I).HeatCapSeq(TimeStepIndex), - state.dataSize->SizingFileColSep, - state.dataSize->SysSizing(J, I).CoolFlowSeq(TimeStepIndex), - state.dataSize->SizingFileColSep, - state.dataSize->SysSizing(J, I).SensCoolCapSeq(TimeStepIndex), - state.dataSize->SizingFileColSep, - state.dataSize->SysSizing(J, I).TotCoolCapSeq(TimeStepIndex)); - } - } - print(state.files.ssz, "\n"); - } - } - - constexpr const char *SSizeFmt31("{}{:12.6E}{}{:12.6E}{}{:12.6E}{}{:12.6E}"); - print(state.files.ssz, "Coinc Peak "); - for (I = 1; I <= state.dataHVACGlobal->NumPrimaryAirSys; ++I) { - print(state.files.ssz, - SSizeFmt31, - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).CoinHeatMassFlow, - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).CoinCoolMassFlow, - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).HeatCap, - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).SensCoolCap); - } - print(state.files.ssz, "\n"); - - print(state.files.ssz, "NonCoinc Peak"); - for (I = 1; I <= state.dataHVACGlobal->NumPrimaryAirSys; ++I) { - print(state.files.ssz, - SSizeFmt31, - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).NonCoinHeatMassFlow, - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).NonCoinCoolMassFlow, - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).HeatCap, - state.dataSize->SizingFileColSep, - state.dataSize->CalcSysSizing(I).SensCoolCap); - } - print(state.files.ssz, "\n"); + writeSysSizingResults(state); // have moved a big section to later in calling order, write predefined standard 62.1 report data } break; default: diff --git a/src/EnergyPlus/SingleDuct.cc b/src/EnergyPlus/SingleDuct.cc index 2d06eefd8d6..435b9630d2f 100644 --- a/src/EnergyPlus/SingleDuct.cc +++ b/src/EnergyPlus/SingleDuct.cc @@ -92,6 +92,127 @@ namespace EnergyPlus::SingleDuct { +// Helper: look up the Air Distribution Unit for an air terminal, connect it to +// the zone equipment config, and populate CtrlZoneNum / ZoneFloorArea. +// Extracted from GetSysInput where this block was repeated for every terminal type. +static void connectAirTermToZone(EnergyPlusData &state, + SingleDuctAirTerminal &airTerm, + std::string_view RoutineName, + int outletNode, // node used to match ADU and zone inlet + bool &ErrorsFound) +{ + // Find matching Air Distribution Unit + for (int ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) { + if (outletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) { + state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum; + airTerm.ADUNum = ADUNum; + break; + } + } + if (airTerm.ADUNum == 0) { + ShowSevereError( + state, EnergyPlus::format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName)); + ShowContinueError(state, EnergyPlus::format("...should have outlet node = {}", state.dataLoopNodes->NodeID(outletNode))); + ErrorsFound = true; + } else { + for (int CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { + if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) { + continue; + } + for (int SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) { + if (outletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) { + if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) { + ShowSevereError(state, "Error in connecting a terminal unit to a zone"); + ShowContinueError(state, EnergyPlus::format("{} already connects to another zone", state.dataLoopNodes->NodeID(outletNode))); + ShowContinueError(state, EnergyPlus::format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName)); + ShowContinueError(state, "Check terminal unit node names for errors"); + ErrorsFound = true; + } else { + state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum; + state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = outletNode; + state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum = + state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex; + state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone; + } + airTerm.CtrlZoneNum = CtrlZone; + airTerm.CtrlZoneInNodeIndex = SupAirIn; + airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier * + state.dataHeatBal->Zone(CtrlZone).ListMultiplier; + } + } + } + } +} + +// Helper: parse a reheat coil type string and set the HeatingCoilType enum +// and (if applicable) the plant equipment type on the air terminal. +static void parseReheatCoilType(EnergyPlusData &state, SingleDuctAirTerminal &airTerm, std::string_view cAlphaFieldName, bool &ErrorsFound) +{ + if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) { + airTerm.ReheatComp_Num = HeatingCoilType::Gas; + } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) { + airTerm.ReheatComp_Num = HeatingCoilType::Electric; + } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) { + airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating; + airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating; + } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) { + airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating; + airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating; + } else if (!airTerm.ReheatComp.empty()) { + ShowSevereError(state, EnergyPlus::format("Illegal {} = {}.", cAlphaFieldName, airTerm.ReheatComp)); + ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); + ErrorsFound = true; + } +} + +// Helper: look up the reheat coil index based on coil type. +static void lookupReheatCoilIndex(EnergyPlusData &state, + SingleDuctAirTerminal &airTerm, + ErrorObjectHeader const &eoh, + std::string_view cAlphaFieldName, + std::string_view alphaValue, + bool &ErrorsFound) +{ + if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) { + HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound); + if (airTerm.ReheatComp_Index == 0) { + ShowSevereItemNotFound(state, eoh, cAlphaFieldName, alphaValue); + ErrorsFound = true; + } + } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) { + airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound); + if (airTerm.ReheatComp_Index == 0) { + ShowSevereItemNotFound(state, eoh, cAlphaFieldName, alphaValue); + ErrorsFound = true; + } + } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) { + airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound); + if (airTerm.ReheatComp_Index == 0) { + ShowSevereItemNotFound(state, eoh, cAlphaFieldName, alphaValue); + ErrorsFound = true; + } + } +} + +// Helper: get the reheat coil control node (water or steam inlet) for +// hot-water and steam reheat coils. Does nothing for gas/electric coils. +static void lookupReheatControlNode(EnergyPlusData &state, SingleDuctAirTerminal &airTerm, bool &ErrorsFound) +{ + if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) { + return; + } + bool IsNotOK = false; + if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) { + airTerm.ReheatControlNode = SteamCoils::GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); + } else { + airTerm.ReheatControlNode = WaterCoils::GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); + } + if (IsNotOK) { + ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); + ErrorsFound = true; + } +} + // Module containing the Single Duct Systems as a single component/ or really a single driver // MODULE INFORMATION: @@ -240,9 +361,6 @@ void GetSysInput(EnergyPlusData &state) int IOStat; bool ErrorsFound(false); // If errors detected in input bool IsNotOK; // Flag to verify name - int CtrlZone; // controlled zone do loop index - int SupAirIn; // controlled zone supply air inlet index - int ADUNum; // air distribution unit index std::string CurrentModuleObject; // for ease in getting objects Array1D_string Alphas; // Alpha input items for object Array1D_string cAlphaFields; // Alpha field names @@ -277,55 +395,18 @@ void GetSysInput(EnergyPlusData &state) state.dataSingleDuct->SysUniqueNames.reserve(static_cast(state.dataSingleDuct->NumSDAirTerminal)); state.dataSingleDuct->CheckEquipName.dimension(state.dataSingleDuct->NumSDAirTerminal, true); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, - "AirTerminal:SingleDuct:VAV:Reheat", - state.dataSingleDuct->TotalArgsGSI, - state.dataSingleDuct->NumAlphasGSI, - state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, - "AirTerminal:SingleDuct:VAV:NoReheat", - state.dataSingleDuct->TotalArgsGSI, - state.dataSingleDuct->NumAlphasGSI, - state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, - "AirTerminal:SingleDuct:ConstantVolume:Reheat", - state.dataSingleDuct->TotalArgsGSI, - state.dataSingleDuct->NumAlphasGSI, - state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, - "AirTerminal:SingleDuct:ConstantVolume:NoReheat", - state.dataSingleDuct->TotalArgsGSI, - state.dataSingleDuct->NumAlphasGSI, - state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, - "AirTerminal:SingleDuct:VAV:Reheat:VariableSpeedFan", - state.dataSingleDuct->TotalArgsGSI, - state.dataSingleDuct->NumAlphasGSI, - state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, - "AirTerminal:SingleDuct:VAV:HeatAndCool:Reheat", - state.dataSingleDuct->TotalArgsGSI, - state.dataSingleDuct->NumAlphasGSI, - state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI); - state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, - "AirTerminal:SingleDuct:VAV:HeatAndCool:NoReheat", - state.dataSingleDuct->TotalArgsGSI, - state.dataSingleDuct->NumAlphasGSI, - state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI); - state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI); + for (auto const *objName : {"AirTerminal:SingleDuct:VAV:Reheat", + "AirTerminal:SingleDuct:VAV:NoReheat", + "AirTerminal:SingleDuct:ConstantVolume:Reheat", + "AirTerminal:SingleDuct:ConstantVolume:NoReheat", + "AirTerminal:SingleDuct:VAV:Reheat:VariableSpeedFan", + "AirTerminal:SingleDuct:VAV:HeatAndCool:Reheat", + "AirTerminal:SingleDuct:VAV:HeatAndCool:NoReheat"}) { + state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs( + state, objName, state.dataSingleDuct->TotalArgsGSI, state.dataSingleDuct->NumAlphasGSI, state.dataSingleDuct->NumNumsGSI); + state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI); + state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI); + } Alphas.allocate(state.dataSingleDuct->MaxAlphasGSI); cAlphaFields.allocate(state.dataSingleDuct->MaxAlphasGSI); @@ -366,42 +447,10 @@ void GetSysInput(EnergyPlusData &state) airTerm.SysType_Num = SysType::SingleDuctVAVReheat; airTerm.ReheatComp = Alphas(7); - if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) { - airTerm.ReheatComp_Num = HeatingCoilType::Gas; - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) { - airTerm.ReheatComp_Num = HeatingCoilType::Electric; - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) { - airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating; - airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating; - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) { - airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating; - airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating; - } else if (!airTerm.ReheatComp.empty()) { - ShowSevereError(state, EnergyPlus::format("Illegal {} = {}.", cAlphaFields(8), airTerm.ReheatComp)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } + parseReheatCoilType(state, airTerm, cAlphaFields(8), ErrorsFound); airTerm.ReheatName = Alphas(8); - if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) { - HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8)); - ErrorsFound = true; - } - } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) { - airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8)); - ErrorsFound = true; - } - } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) { - airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8)); - ErrorsFound = true; - } - } + lookupReheatCoilIndex(state, airTerm, eoh, cAlphaFields(8), Alphas(8), ErrorsFound); if (lAlphaBlanks(2)) { airTerm.availSched = Sched::GetScheduleAlwaysOn(state); @@ -490,23 +539,7 @@ void GetSysInput(EnergyPlusData &state) // The reheat coil control node is necessary for hot water and steam reheat, but not necessary for // electric or gas reheat. - if (airTerm.ReheatComp_Num != HeatingCoilType::Gas && airTerm.ReheatComp_Num != HeatingCoilType::Electric) { - if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) { - IsNotOK = false; - airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } - } else { - IsNotOK = false; - airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } - } - } + lookupReheatControlNode(state, airTerm, ErrorsFound); airTerm.ReheatAirOutletNode = GetOnlySingleNode(state, Alphas(9), ErrorsFound, @@ -549,53 +582,8 @@ void GetSysInput(EnergyPlusData &state) state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode), "Air Nodes"); - for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) { - if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) { - state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum; - airTerm.ADUNum = ADUNum; - break; - } - } - // one assumes if there isn't one assigned, it's an error? - if (airTerm.ADUNum == 0) { - ShowSevereError( - state, - EnergyPlus::format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, EnergyPlus::format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode))); - ErrorsFound = true; - } else { - - // Fill the Zone Equipment data with the inlet node number of this unit. - for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) { - continue; - } - for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) { - if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) { - if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) { - ShowSevereError(state, "Error in connecting a terminal unit to a zone"); - ShowContinueError( - state, - EnergyPlus::format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode))); - ShowContinueError(state, EnergyPlus::format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, "Check terminal unit node names for errors"); - ErrorsFound = true; - } else { - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum; - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum = - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone; - } + connectAirTermToZone(state, airTerm, RoutineName, airTerm.ReheatAirOutletNode, ErrorsFound); - airTerm.CtrlZoneNum = CtrlZone; - airTerm.CtrlZoneInNodeIndex = SupAirIn; - airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier * - state.dataHeatBal->Zone(CtrlZone).ListMultiplier; - } - } - } - } if (Numbers(7) == Constant::AutoCalculate) { airTerm.MaxAirVolFlowRateDuringReheat = Numbers(7); } else { @@ -701,41 +689,9 @@ void GetSysInput(EnergyPlusData &state) airTerm.sysType = CurrentModuleObject; airTerm.SysType_Num = SysType::SingleDuctCBVAVReheat; airTerm.ReheatComp = Alphas(5); - if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) { - airTerm.ReheatComp_Num = HeatingCoilType::Gas; - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) { - airTerm.ReheatComp_Num = HeatingCoilType::Electric; - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) { - airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating; - airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating; - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) { - airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating; - airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating; - } else if (!airTerm.ReheatComp.empty()) { - ShowSevereError(state, EnergyPlus::format("Illegal {} = {}.", cAlphaFields(5), airTerm.ReheatComp)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } + parseReheatCoilType(state, airTerm, cAlphaFields(5), ErrorsFound); airTerm.ReheatName = Alphas(6); - if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) { - HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6)); - ErrorsFound = true; - } - } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) { - airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6)); - ErrorsFound = true; - } - } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) { - airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6)); - ErrorsFound = true; - } - } + lookupReheatCoilIndex(state, airTerm, eoh, cAlphaFields(6), Alphas(6), ErrorsFound); if (lAlphaBlanks(2)) { airTerm.availSched = Sched::GetScheduleAlwaysOn(state); @@ -782,25 +738,7 @@ void GetSysInput(EnergyPlusData &state) } // The reheat coil control node is necessary for hot water and steam reheat, but not necessary for // electric or gas reheat. - if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) { - } else { - if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) { - IsNotOK = false; - airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } - } else { - IsNotOK = false; - airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } - } - // END IF - } + lookupReheatControlNode(state, airTerm, ErrorsFound); airTerm.ReheatAirOutletNode = GetOnlySingleNode(state, Alphas(7), ErrorsFound, @@ -834,52 +772,8 @@ void GetSysInput(EnergyPlusData &state) state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode), "Air Nodes"); - for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) { - if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) { - state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum; - airTerm.ADUNum = ADUNum; - break; - } - } - // one assumes if there isn't one assigned, it's an error? - if (airTerm.ADUNum == 0) { - ShowSevereError( - state, - EnergyPlus::format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, EnergyPlus::format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode))); - ErrorsFound = true; - } else { + connectAirTermToZone(state, airTerm, RoutineName, airTerm.ReheatAirOutletNode, ErrorsFound); - // Fill the Zone Equipment data with the inlet node number of this unit - for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) { - continue; - } - for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) { - if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) { - if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) { - ShowSevereError(state, "Error in connecting a terminal unit to a zone"); - ShowContinueError( - state, - EnergyPlus::format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode))); - ShowContinueError(state, EnergyPlus::format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, "Check terminal unit node names for errors"); - ErrorsFound = true; - } else { - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum; - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum = - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone; - } - airTerm.CtrlZoneNum = CtrlZone; - airTerm.CtrlZoneInNodeIndex = SupAirIn; - airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier * - state.dataHeatBal->Zone(CtrlZone).ListMultiplier; - } - } - } - } if (!lNumericBlanks(6)) { airTerm.MaxReheatTemp = Numbers(6); airTerm.MaxReheatTempSetByUser = true; @@ -947,41 +841,9 @@ void GetSysInput(EnergyPlusData &state) airTerm.sysType = CurrentModuleObject; airTerm.SysType_Num = SysType::SingleDuctConstVolReheat; airTerm.ReheatComp = Alphas(5); - if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) { - airTerm.ReheatComp_Num = HeatingCoilType::Gas; - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) { - airTerm.ReheatComp_Num = HeatingCoilType::Electric; - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) { - airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating; - airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating; - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) { - airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating; - airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating; - } else { - ShowSevereError(state, EnergyPlus::format("Illegal {} = {}.", cAlphaFields(5), airTerm.ReheatComp)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } + parseReheatCoilType(state, airTerm, cAlphaFields(5), ErrorsFound); airTerm.ReheatName = Alphas(6); - if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) { - HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6)); - ErrorsFound = true; - } - } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) { - airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6)); - ErrorsFound = true; - } - } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) { - airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6)); - ErrorsFound = true; - } - } + lookupReheatCoilIndex(state, airTerm, eoh, cAlphaFields(6), Alphas(6), ErrorsFound); if (lAlphaBlanks(2)) { airTerm.availSched = Sched::GetScheduleAlwaysOn(state); @@ -1012,24 +874,7 @@ void GetSysInput(EnergyPlusData &state) cAlphaFields(4)); // The reheat coil control node is necessary for hot water reheat, but not necessary for // electric or gas reheat. - if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) { - } else { - if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) { - IsNotOK = false; - airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } - } else { - IsNotOK = false; - airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } - } - } + lookupReheatControlNode(state, airTerm, ErrorsFound); airTerm.ReheatAirOutletNode = airTerm.OutletNodeNum; airTerm.MaxAirVolFlowRate = Numbers(1); airTerm.ZoneMinAirFracDes = 0.0; @@ -1065,51 +910,7 @@ void GetSysInput(EnergyPlusData &state) state.dataLoopNodes->NodeID(airTerm.OutletNodeNum), "Air Nodes"); - for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) { - if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) { - state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum; - airTerm.ADUNum = ADUNum; - break; - } - } - // one assumes if there isn't one assigned, it's an error? - if (airTerm.ADUNum == 0) { - ShowSevereError( - state, - EnergyPlus::format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, EnergyPlus::format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode))); - ErrorsFound = true; - } else { - - // Fill the Zone Equipment data with the inlet node number of this unit. - for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) { - continue; - } - for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) { - if (airTerm.OutletNodeNum == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) { - if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) { - ShowSevereError(state, "Error in connecting a terminal unit to a zone"); - ShowContinueError( - state, EnergyPlus::format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.OutletNodeNum))); - ShowContinueError(state, EnergyPlus::format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, "Check terminal unit node names for errors"); - ErrorsFound = true; - } else { - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum; - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.OutletNodeNum; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum = - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone; - } - airTerm.CtrlZoneNum = CtrlZone; - airTerm.CtrlZoneInNodeIndex = SupAirIn; - airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier * - state.dataHeatBal->Zone(CtrlZone).ListMultiplier; - } - } - } - } + connectAirTermToZone(state, airTerm, RoutineName, airTerm.ReheatAirOutletNode, ErrorsFound); ValidateComponent(state, Alphas(5), Alphas(6), IsNotOK, airTerm.sysType); if (IsNotOK) { @@ -1207,51 +1008,7 @@ void GetSysInput(EnergyPlusData &state) state.dataLoopNodes->NodeID(airTerm.OutletNodeNum), "Air Nodes"); - for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) { - if (airTerm.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) { - state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum; - airTerm.ADUNum = ADUNum; - break; - } - } - // one assumes if there isn't one assigned, it's an error? - if (airTerm.ADUNum == 0) { - ShowSevereError( - state, - EnergyPlus::format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, EnergyPlus::format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.OutletNodeNum))); - ErrorsFound = true; - } else { - - // Fill the Zone Equipment data with the inlet node number of this unit. - for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) { - continue; - } - for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) { - if (airTerm.OutletNodeNum == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) { - if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) { - ShowSevereError(state, "Error in connecting a terminal unit to a zone"); - ShowContinueError( - state, EnergyPlus::format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.OutletNodeNum))); - ShowContinueError(state, EnergyPlus::format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, "Check terminal unit node names for errors"); - ErrorsFound = true; - } else { - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum; - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.OutletNodeNum; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum = - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone; - } - airTerm.CtrlZoneNum = CtrlZone; - airTerm.CtrlZoneInNodeIndex = SupAirIn; - airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier * - state.dataHeatBal->Zone(CtrlZone).ListMultiplier; - } - } - } - } + connectAirTermToZone(state, airTerm, RoutineName, airTerm.OutletNodeNum, ErrorsFound); if (lAlphaBlanks(5)) { airTerm.NoOAFlowInputFromUser = true; @@ -1433,53 +1190,8 @@ void GetSysInput(EnergyPlusData &state) state.dataLoopNodes->NodeID(airTerm.OutletNodeNum), "Air Nodes"); - for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) { - if (airTerm.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) { - state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum; - airTerm.ADUNum = ADUNum; - break; - } - } - // one assumes if there isn't one assigned, it's an error? - if (airTerm.ADUNum == 0) { - ShowSevereError( - state, - EnergyPlus::format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, EnergyPlus::format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode))); - ErrorsFound = true; - } else { - - // Fill the Zone Equipment data with the inlet node number of this unit. - for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) { - continue; - } - for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) { - if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) { - if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) { - ShowSevereError(state, "Error in connecting a terminal unit to a zone"); - ShowContinueError( - state, - EnergyPlus::format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode))); - ShowContinueError(state, EnergyPlus::format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, "Check terminal unit node names for errors"); - ErrorsFound = true; - } else { - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum; - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum = - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone; - } + connectAirTermToZone(state, airTerm, RoutineName, airTerm.ReheatAirOutletNode, ErrorsFound); - airTerm.CtrlZoneNum = CtrlZone; - airTerm.CtrlZoneInNodeIndex = SupAirIn; - airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier * - state.dataHeatBal->Zone(CtrlZone).ListMultiplier; - } - } - } - } if (!lAlphaBlanks(7)) { airTerm.OARequirementsPtr = Util::FindItemInList(Alphas(7), state.dataSize->OARequirements); if (airTerm.OARequirementsPtr == 0) { @@ -1608,52 +1320,7 @@ void GetSysInput(EnergyPlusData &state) state.dataLoopNodes->NodeID(airTerm.OutletNodeNum), "Air Nodes"); - for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) { - if (airTerm.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) { - state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum; - airTerm.ADUNum = ADUNum; - break; - } - } - // one assumes if there isn't one assigned, it's an error? - if (airTerm.ADUNum == 0) { - ShowSevereError( - state, - EnergyPlus::format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, EnergyPlus::format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode))); - ErrorsFound = true; - } else { - - // Fill the Zone Equipment data with the inlet node number of this unit. - for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) { - continue; - } - for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) { - if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) { - if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) { - ShowSevereError(state, "Error in connecting a terminal unit to a zone"); - ShowContinueError( - state, - EnergyPlus::format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode))); - ShowContinueError(state, EnergyPlus::format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, "Check terminal unit node names for errors"); - ErrorsFound = true; - } else { - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum; - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum = - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone; - } - airTerm.CtrlZoneNum = CtrlZone; - airTerm.CtrlZoneInNodeIndex = SupAirIn; - airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier * - state.dataHeatBal->Zone(CtrlZone).ListMultiplier; - } - } - } - } + connectAirTermToZone(state, airTerm, RoutineName, airTerm.ReheatAirOutletNode, ErrorsFound); if (lAlphaBlanks(5)) { airTerm.ZoneTurndownMinAirFrac = 1.0; @@ -1707,52 +1374,17 @@ void GetSysInput(EnergyPlusData &state) airTerm.SysType_Num = SysType::SingleDuctVAVReheatVSFan; airTerm.ReheatComp = Alphas(7); airTerm.ReheatName = Alphas(8); + parseReheatCoilType(state, airTerm, cAlphaFields(7), ErrorsFound); IsNotOK = false; - if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) { - airTerm.ReheatComp_Num = HeatingCoilType::Gas; - airTerm.ReheatAirOutletNode = GetHeatingCoilOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - airTerm.ReheatCoilMaxCapacity = GetHeatingCoilCapacity(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName)); - } - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) { - airTerm.ReheatComp_Num = HeatingCoilType::Electric; + if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) { airTerm.ReheatAirOutletNode = GetHeatingCoilOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); airTerm.ReheatCoilMaxCapacity = GetHeatingCoilCapacity(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); if (IsNotOK) { ShowContinueError(state, EnergyPlus::format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName)); } - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) { - airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating; - airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating; - } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) { - airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating; - airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating; - } else if (!airTerm.ReheatComp.empty()) { - ShowSevereError(state, EnergyPlus::format("Illegal {} = {}.", cAlphaFields(7), airTerm.ReheatComp)); - ShowContinueError(state, EnergyPlus::format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; } - if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) { - HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8)); - ErrorsFound = true; - } - } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) { - airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8)); - ErrorsFound = true; - } - } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) { - airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound); - if (airTerm.ReheatComp_Index == 0) { - ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8)); - ErrorsFound = true; - } - } + lookupReheatCoilIndex(state, airTerm, eoh, cAlphaFields(8), Alphas(8), ErrorsFound); airTerm.fanType = static_cast(getEnumValue(HVAC::fanTypeNamesUC, Alphas(5))); @@ -1798,58 +1430,19 @@ void GetSysInput(EnergyPlusData &state) airTerm.ZoneMinAirFracDes = Numbers(3); // The reheat coil control node is necessary for hot water reheat, but not necessary for // electric or gas reheat. - if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) { - // IF(.NOT. lAlphaBlanks(6)) THEN - // CALL ShowWarningError(state, 'In '//TRIM(sd_airterminal(SysNum)%SysType)//' = ' // TRIM(sd_airterminal(SysNum)%SysName) & - // // ' the '//TRIM(cAlphaFields(6))//' is not needed and will be ignored.') - // CALL ShowContinueError(state, ' It is used for hot water reheat coils only.') - // END IF - } else { - // IF(lAlphaBlanks(6)) THEN - // CALL ShowSevereError(state, 'In '//TRIM(sd_airterminal(SysNum)%SysType)//' = ' // TRIM(sd_airterminal(SysNum)%SysName) & - // // ' the '//TRIM(cAlphaFields(6))//' is undefined') - // ErrorsFound=.TRUE. - // END IF + lookupReheatControlNode(state, airTerm, ErrorsFound); + // For water/steam coils in VSFan terminals, also look up the air outlet node from the coil + // (only if the control node was found, i.e. ReheatControlNode != 0) + if (airTerm.ReheatComp_Num != HeatingCoilType::Gas && airTerm.ReheatComp_Num != HeatingCoilType::Electric && airTerm.ReheatControlNode != 0) { + IsNotOK = false; if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) { - IsNotOK = false; - airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } else { - // A4, \field Unit supply air outlet node - // \note same as heating coil air outlet node - // \note same as zone inlet node - // \type alpha - IsNotOK = false; - airTerm.ReheatAirOutletNode = GetCoilAirOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } - } - // GetOnlySingleNode(state, Alphas(6),ErrorsFound,sd_airterminal(SysNum)%SysType,Alphas(1), & - // Node::FluidType::Steam,Node::NodeConnectionType::Actuator,1,Node::ObjectIsParent) + airTerm.ReheatAirOutletNode = GetCoilAirOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); } else { - IsNotOK = false; - airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } else { - // A4, \field Unit supply air outlet node - // \note same as heating coil air outlet node - // \note same as zone inlet node - // \type alpha - IsNotOK = false; - airTerm.ReheatAirOutletNode = GetCoilOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); - if (IsNotOK) { - ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); - ErrorsFound = true; - } - } - // GetOnlySingleNode(state, Alphas(6),ErrorsFound,sd_airterminal(SysNum)%SysType,Alphas(1), & - // Node::FluidType::Water,Node::NodeConnectionType::Actuator,1,Node::ObjectIsParent) + airTerm.ReheatAirOutletNode = GetCoilOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK); + } + if (IsNotOK) { + ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); + ErrorsFound = true; } } // A4, \field Unit supply air outlet node @@ -1891,56 +1484,9 @@ void GetSysInput(EnergyPlusData &state) state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode), "Air Nodes"); - for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) { - if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) { - state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum; - airTerm.ADUNum = ADUNum; - break; - } - } - // one assumes if there isn't one assigned, it's an error? - if (airTerm.ADUNum == 0) { - ShowSevereError( - state, - EnergyPlus::format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, EnergyPlus::format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode))); - ErrorsFound = true; - } else { + connectAirTermToZone(state, airTerm, RoutineName, airTerm.ReheatAirOutletNode, ErrorsFound); - // Fill the Zone Equipment data with the inlet node number of this unit. - // what if not found? error? - IsNotOK = true; - for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) { - continue; - } - for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) { - if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) { - IsNotOK = false; - if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) { - ShowSevereError(state, "Error in connecting a terminal unit to a zone"); - ShowContinueError( - state, - EnergyPlus::format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode))); - ShowContinueError(state, EnergyPlus::format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName)); - ShowContinueError(state, "Check terminal unit node names for errors"); - ErrorsFound = true; - } else { - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum; - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum = - state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex; - state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone; - } - airTerm.CtrlZoneNum = CtrlZone; - airTerm.CtrlZoneInNodeIndex = SupAirIn; - airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier * - state.dataHeatBal->Zone(CtrlZone).ListMultiplier; - } - } - } - } - if (IsNotOK) { + if (airTerm.ADUNum != 0 && airTerm.CtrlZoneNum == 0) { ShowWarningError(state, "Did not Match Supply Air Outlet Node to any Zone Node"); ShowContinueError(state, EnergyPlus::format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName)); } diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index e24647b672c..de4d1da48d4 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -864,6 +864,207 @@ void checkScheduledSurfacePresent(EnergyPlusData &state) } } +// Helper: set up window glazing transmittance and profile angle output variables (used by both ExtSolar and non-ExtSolar paths) +static void setupWindowGlazingOutputVars(EnergyPlusData &state, int SurfLoop, std::string const &surfName) +{ + auto &s_surf = state.dataSurface; + SetupOutputVariable(state, + "Surface Window Solar Horizontal Profile Angle", + Constant::Units::deg, + s_surf->SurfWinProfileAngHor(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Solar Vertical Profile Angle", + Constant::Units::deg, + s_surf->SurfWinProfileAngVert(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Glazing Beam to Beam Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinGlTsolBmBm(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Glazing Beam to Diffuse Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinGlTsolBmDif(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Glazing Diffuse to Diffuse Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinGlTsolDifDif(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Model Solver Iteration Count", + Constant::Units::None, + s_surf->SurfWinWindowCalcIterationsRep(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); +} + +// Helper: set up frame and divider output variables for a window surface (used by both ExtSolar and non-ExtSolar paths) +static void setupFrameDividerOutputVars(EnergyPlusData &state, int SurfLoop, std::string const &surfName) +{ + auto &s_surf = state.dataSurface; + if (s_surf->SurfWinFrameArea(SurfLoop) > 0.0) { + SetupOutputVariable(state, + "Surface Window Frame Heat Gain Rate", + Constant::Units::W, + s_surf->SurfWinFrameHeatGain(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Frame Heat Loss Rate", + Constant::Units::W, + s_surf->SurfWinFrameHeatLoss(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Frame Inside Temperature", + Constant::Units::C, + s_surf->SurfWinFrameTempIn(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Frame Outside Temperature", + Constant::Units::C, + s_surf->SurfWinFrameTempSurfOut(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + } + if (s_surf->SurfWinDividerArea(SurfLoop) > 0.0) { + SetupOutputVariable(state, + "Surface Window Divider Heat Gain Rate", + Constant::Units::W, + s_surf->SurfWinDividerHeatGain(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Divider Heat Loss Rate", + Constant::Units::W, + s_surf->SurfWinDividerHeatLoss(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Divider Inside Temperature", + Constant::Units::C, + s_surf->SurfWinDividerTempIn(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Divider Outside Temperature", + Constant::Units::C, + s_surf->SurfWinDividerTempSurfOut(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + } +} + +// Helper: set up screen output variables for a window surface (used by both ExtSolar and non-ExtSolar paths) +static void setupScreenOutputVars(EnergyPlusData &state, int SurfLoop, std::string const &surfName) +{ + auto &s_surf = state.dataSurface; + if (s_surf->SurfaceWindow(SurfLoop).screenNum > 0) { + SetupOutputVariable(state, + "Surface Window Screen Beam to Beam Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinScTsolBmBm(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Screen Beam to Diffuse Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinScTsolBmDif(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Screen Diffuse to Diffuse Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinScTsolDifDif(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Screen and Glazing System Beam Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinScGlSysTsolBmBm(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Screen and Glazing System Diffuse Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinScGlSysTsolDifDif(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + } +} + +// Helper: set up blind output variables for a window surface (used by both ExtSolar and non-ExtSolar paths) +static void setupBlindOutputVars(EnergyPlusData &state, int SurfLoop, std::string const &surfName) +{ + auto &s_surf = state.dataSurface; + auto &surfShade = s_surf->surfShades(SurfLoop); + if (surfShade.blind.matNum > 0) { + SetupOutputVariable(state, + "Surface Window Blind Beam to Beam Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinBlTsolBmBm(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Blind Beam to Diffuse Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinBlTsolBmDif(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Blind Diffuse to Diffuse Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinBlTsolDifDif(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Blind and Glazing System Beam Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinBlGlSysTsolBmBm(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + SetupOutputVariable(state, + "Surface Window Blind and Glazing System Diffuse Solar Transmittance", + Constant::Units::None, + s_surf->SurfWinBlGlSysTsolDifDif(SurfLoop), + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + surfName); + } +} + void AllocateModuleArrays(EnergyPlusData &state) { @@ -1628,68 +1829,7 @@ void AllocateModuleArrays(EnergyPlusData &state) } } - if (s_surf->SurfWinFrameArea(SurfLoop) > 0.0) { - // CurrentModuleObject='Window Frames' - SetupOutputVariable(state, - "Surface Window Frame Heat Gain Rate", - Constant::Units::W, - s_surf->SurfWinFrameHeatGain(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Frame Heat Loss Rate", - Constant::Units::W, - s_surf->SurfWinFrameHeatLoss(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Frame Inside Temperature", - Constant::Units::C, - s_surf->SurfWinFrameTempIn(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Frame Outside Temperature", - Constant::Units::C, - s_surf->SurfWinFrameTempSurfOut(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - } - if (s_surf->SurfWinDividerArea(SurfLoop) > 0.0) { - // CurrentModuleObject='Window Dividers' - SetupOutputVariable(state, - "Surface Window Divider Heat Gain Rate", - Constant::Units::W, - s_surf->SurfWinDividerHeatGain(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Divider Heat Loss Rate", - Constant::Units::W, - s_surf->SurfWinDividerHeatLoss(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Divider Inside Temperature", - Constant::Units::C, - s_surf->SurfWinDividerTempIn(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Divider Outside Temperature", - Constant::Units::C, - s_surf->SurfWinDividerTempSurfOut(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - } + setupFrameDividerOutputVars(state, SurfLoop, surf.Name); // CurrentModuleObject='Windows' // Energy @@ -1886,130 +2026,11 @@ void AllocateModuleArrays(EnergyPlusData &state) surf.Name); } - // Output blind report variables only when blinds are used - auto &surfShade = s_surf->surfShades(SurfLoop); - if (surfShade.blind.matNum > 0) { - // CurrentModuleObject='Window Blinds' - SetupOutputVariable(state, - "Surface Window Blind Beam to Beam Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinBlTsolBmBm(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Blind Beam to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinBlTsolBmDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Blind Diffuse to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinBlTsolDifDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Blind and Glazing System Beam Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinBlGlSysTsolBmBm(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Blind and Glazing System Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinBlGlSysTsolDifDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - } + setupBlindOutputVars(state, SurfLoop, surf.Name); - // Output screen report variables only when screens are used - if (s_surf->SurfaceWindow(SurfLoop).screenNum > 0) { - // CurrentModuleObject='Window Screens' - SetupOutputVariable(state, - "Surface Window Screen Beam to Beam Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinScTsolBmBm(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Screen Beam to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinScTsolBmDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Screen Diffuse to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinScTsolDifDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Screen and Glazing System Beam Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinScGlSysTsolBmBm(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Screen and Glazing System Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinScGlSysTsolDifDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - } + setupScreenOutputVars(state, SurfLoop, surf.Name); - // CurrentModuleObject='Windows' - SetupOutputVariable(state, - "Surface Window Solar Horizontal Profile Angle", - Constant::Units::deg, - s_surf->SurfWinProfileAngHor(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Solar Vertical Profile Angle", - Constant::Units::deg, - s_surf->SurfWinProfileAngVert(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Glazing Beam to Beam Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinGlTsolBmBm(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Glazing Beam to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinGlTsolBmDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Glazing Diffuse to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinGlTsolDifDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Model Solver Iteration Count", - Constant::Units::None, - s_surf->SurfWinWindowCalcIterationsRep(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); + setupWindowGlazingOutputVars(state, SurfLoop, surf.Name); } else { // Not ExtSolar if (state.dataGlobal->DisplayAdvancedReportVariables) { // CurrentModuleObject='InteriorWindows(Advanced)' @@ -2098,66 +2119,7 @@ void AllocateModuleArrays(EnergyPlusData &state) OutputProcessor::TimeStepType::Zone, OutputProcessor::StoreType::Average, surf.Name); - if (s_surf->SurfWinFrameArea(SurfLoop) > 0.0) { - SetupOutputVariable(state, - "Surface Window Frame Heat Gain Rate", - Constant::Units::W, - s_surf->SurfWinFrameHeatGain(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Frame Heat Loss Rate", - Constant::Units::W, - s_surf->SurfWinFrameHeatLoss(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Frame Inside Temperature", - Constant::Units::C, - s_surf->SurfWinFrameTempIn(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Frame Outside Temperature", - Constant::Units::C, - s_surf->SurfWinFrameTempSurfOut(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - } - if (s_surf->SurfWinDividerArea(SurfLoop) > 0.0) { - SetupOutputVariable(state, - "Surface Window Divider Heat Gain Rate", - Constant::Units::W, - s_surf->SurfWinDividerHeatGain(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Divider Heat Loss Rate", - Constant::Units::W, - s_surf->SurfWinDividerHeatLoss(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Divider Inside Temperature", - Constant::Units::C, - s_surf->SurfWinDividerTempIn(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Divider Outside Temperature", - Constant::Units::C, - s_surf->SurfWinDividerTempSurfOut(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - } + setupFrameDividerOutputVars(state, SurfLoop, surf.Name); // Energy if (surf.OriginalClass != SurfaceClass::TDD_Diffuser) { @@ -2310,127 +2272,11 @@ void AllocateModuleArrays(EnergyPlusData &state) OutputProcessor::StoreType::Sum, surf.Name); - // Output blind report variables only when blinds are used - auto &surfShade = s_surf->surfShades(SurfLoop); - if (surfShade.blind.matNum > 0) { - SetupOutputVariable(state, - "Surface Window Blind Beam to Beam Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinBlTsolBmBm(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Blind Beam to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinBlTsolBmDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Blind Diffuse to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinBlTsolDifDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Blind and Glazing System Beam Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinBlGlSysTsolBmBm(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Blind and Glazing System Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinBlGlSysTsolDifDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - } + setupBlindOutputVars(state, SurfLoop, surf.Name); - // Output screen report variables only when screens are used - if (s_surf->SurfaceWindow(SurfLoop).screenNum > 0) { - SetupOutputVariable(state, - "Surface Window Screen Beam to Beam Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinScTsolBmBm(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Screen Beam to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinScTsolBmDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Screen Diffuse to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinScTsolDifDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Screen and Glazing System Beam Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinScGlSysTsolBmBm(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Screen and Glazing System Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinScGlSysTsolDifDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - } + setupScreenOutputVars(state, SurfLoop, surf.Name); - SetupOutputVariable(state, - "Surface Window Solar Horizontal Profile Angle", - Constant::Units::deg, - s_surf->SurfWinProfileAngHor(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Solar Vertical Profile Angle", - Constant::Units::deg, - s_surf->SurfWinProfileAngVert(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Glazing Beam to Beam Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinGlTsolBmBm(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Glazing Beam to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinGlTsolBmDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Glazing Diffuse to Diffuse Solar Transmittance", - Constant::Units::None, - s_surf->SurfWinGlTsolDifDif(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); - SetupOutputVariable(state, - "Surface Window Model Solver Iteration Count", - Constant::Units::None, - s_surf->SurfWinWindowCalcIterationsRep(SurfLoop), - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - surf.Name); + setupWindowGlazingOutputVars(state, SurfLoop, surf.Name); } } // end non extsolar reporting as advanced variables } // Window Reporting @@ -6515,6 +6361,45 @@ void CalcInteriorSolarOverlaps(EnergyPlusData &state, } // End of check that sunlit area > 0. } +// Compute screen beam transmittance/absorptance/reflectance for the given surface and screen. +// Encapsulates the phi/theta calculation from SOLCOS + surface orientation, and handles both +// the PRECALC_INTERP_SCREEN (BilinearInterp) and non-PRECALC (CalcScreenTransmittance) paths. +static Material::ScreenBmTransAbsRef +getScreenBtar(EnergyPlusData &state, Material::MaterialScreen const *screen, DataSurfaces::SurfaceData const &surf) +{ + Real64 solPhi = std::acos(state.dataEnvrn->SOLCOS.z); + Real64 solTheta = std::atan2(state.dataEnvrn->SOLCOS.x, state.dataEnvrn->SOLCOS.y); + Real64 winPhi = surf.Tilt * Constant::DegToRad; + Real64 winTheta = surf.Azimuth * Constant::DegToRad; + Real64 phi = std::abs(solPhi - winPhi); + Real64 theta = std::abs(solTheta - winTheta); + Material::NormalizePhiTheta(phi, theta); + + Material::ScreenBmTransAbsRef btar; +#ifdef PRECALC_INTERP_SCREEN + int ip1, ip2, it1, it2; + BilinearInterpCoeffs coeffs; + Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2); + GetBilinearInterpCoeffs(phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs); + auto const &b11 = screen->btars[ip1][it1]; + auto const &b12 = screen->btars[ip1][it2]; + auto const &b21 = screen->btars[ip2][it1]; + auto const &b22 = screen->btars[ip2][it2]; + + btar.BmTrans = BilinearInterp(b11.BmTrans, b12.BmTrans, b21.BmTrans, b22.BmTrans, coeffs); + btar.BmTransBack = BilinearInterp(b11.BmTransBack, b12.BmTransBack, b21.BmTransBack, b22.BmTransBack, coeffs); + btar.DfTrans = BilinearInterp(b11.DfTrans, b12.DfTrans, b21.DfTrans, b22.DfTrans, coeffs); + btar.DfTransBack = BilinearInterp(b11.DfTransBack, b12.DfTransBack, b21.DfTransBack, b22.DfTransBack, coeffs); + btar.RefSolFront = BilinearInterp(b11.RefSolFront, b12.RefSolFront, b21.RefSolFront, b22.RefSolFront, coeffs); + btar.RefSolBack = BilinearInterp(b11.RefSolBack, b12.RefSolBack, b21.RefSolBack, b22.RefSolBack, coeffs); + btar.AbsSolFront = BilinearInterp(b11.AbsSolFront, b12.AbsSolFront, b21.AbsSolFront, b22.AbsSolFront, coeffs); + btar.AbsSolBack = BilinearInterp(b11.AbsSolBack, b12.AbsSolBack, b21.AbsSolBack, b22.AbsSolBack, coeffs); +#else // !PRECALC_INTERP_SCREEN + Material::CalcScreenTransmittance(state, screen, phi, theta, btar); +#endif // PRECALC_INTERP_SCREEN + return btar; +} + void CalcInteriorSolarDistribution(EnergyPlusData &state) { @@ -6855,53 +6740,7 @@ void CalcInteriorSolarDistribution(EnergyPlusData &state) auto const *screen = dynamic_cast(s_mat->materials(ScNum)); assert(screen != nullptr); - Real64 solPhi = std::acos(state.dataEnvrn->SOLCOS.z); - Real64 solTheta = std::atan2(state.dataEnvrn->SOLCOS.x, state.dataEnvrn->SOLCOS.y); - Real64 winPhi = surf.Tilt * Constant::DegToRad; - Real64 winTheta = surf.Azimuth * Constant::DegToRad; - Real64 phi = std::abs(solPhi - winPhi); - Real64 theta = std::abs(solTheta - winTheta); - Material::NormalizePhiTheta(phi, theta); -#ifdef PRECALC_INTERP_SCREEN - int ip1, ip2, it1, it2; - BilinearInterpCoeffs coeffs; - Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2); - GetBilinearInterpCoeffs( - phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs); - auto const &b11 = screen->btars[ip1][it1]; - auto const &b12 = screen->btars[ip1][it2]; - auto const &b21 = screen->btars[ip2][it1]; - auto const &b22 = screen->btars[ip2][it2]; - - Real64 TScDifDif = screen->DfTrans; - Real64 TScBmDif = BilinearInterp(b11.DfTrans, b12.DfTrans, b21.DfTrans, b22.DfTrans, coeffs); - Real64 TScBmBm = BilinearInterp(b11.BmTrans, b12.BmTrans, b21.BmTrans, b22.BmTrans, coeffs); - Real64 RScBack = BilinearInterp(b11.RefSolFront, b12.RefSolFront, b21.RefSolFront, b22.RefSolFront, coeffs); - Real64 RScDifBack = screen->DfRef; - - Real64 RGlFront = - Window::POLYF(CosInc, thisConstruct.ReflSolBeamFrontCoef); // Glazing system solar front beam-beam reflectance - Real64 RGlDiffFront = thisConstruct.ReflectSolDiffFront; // Glazing system front diffuse solar reflectance - Real64 RGlDifFr = thisConstruct.ReflectSolDiffFront; // Diffuse front reflectance of glass - // Reduce the bare window absorbed beam by the screen beam transmittance and then account for - // interreflections - for (int Lay = 1; Lay <= NGlass; ++Lay) { - Real64 ADiffWin = thisConstruct.AbsDiff(Lay); // Diffuse solar absorptance of glass layer, bare window - AbWinSh(Lay) = TScBmBm * AbWin(Lay) + (TScBmBm * RGlFront * RScBack + TScBmDif) * thisConstruct.AbsDiff(Lay) / - (1.0 - RGlDiffFront * RScDifBack) * CosInc * FracSunLit; - ADiffWinSh(Lay) = ADiffWin * TScDifDif / (1.0 - RGlDifFr * RScDifBack); - } - // Exterior beam absorbed by EXTERIOR SCREEN - Real64 AbsScBeam = BilinearInterp(b11.AbsSolFront, b12.AbsSolFront, b21.AbsSolFront, b22.AbsSolFront, coeffs); - Real64 AbsScDiffBack = screen->DfAbs; - Real64 AbsScreen = AbsScBeam * (1.0 + TScBmBm * RGlFront) + - (AbsScDiffBack * TScBmBm * RGlFront * RGlDiffFront * RScBack / - (1.0 - RScDifBack * RGlDiffFront)); // Exterior screen beam solar absorptance - state.dataSolarShading->SurfWinExtBeamAbsByShadFac(SurfNum) = AbsScreen * CosInc * SunLitFract * InOutProjSLFracMult; -#else // !PRECALC_INTERP_SCREEN - Material::ScreenBmTransAbsRef btar; - CalcScreenTransmittance(state, screen, phi, theta, btar); - + auto const btar = getScreenBtar(state, screen, surf); Real64 TScDifDif = screen->DfTrans; Real64 TScBmDif = btar.DfTrans; Real64 TScBmBm = btar.BmTrans; @@ -6927,7 +6766,6 @@ void CalcInteriorSolarDistribution(EnergyPlusData &state) (AbsScDiffBack * TScBmBm * RGlFront * RGlDiffFront * RScBack / (1.0 - RScDifBack * RGlDiffFront)); // Exterior screen beam solar absorptance state.dataSolarShading->SurfWinExtBeamAbsByShadFac(SurfNum) = AbsScreen * CosInc * SunLitFract * InOutProjSLFracMult; -#endif // PRECALC_INTERP_SCREEN } else if (ShadeFlag == WinShadingType::BGBlind) { // Between-glass blind o // Isolated glass and blind properties at current incidence angle, profile angle and slat angle @@ -7294,52 +7132,13 @@ void CalcInteriorSolarDistribution(EnergyPlusData &state) auto const *screen = dynamic_cast(s_mat->materials(ScNum)); assert(screen != nullptr); - Real64 solPhi = std::acos(state.dataEnvrn->SOLCOS.z); - Real64 solTheta = std::atan2(state.dataEnvrn->SOLCOS.x, state.dataEnvrn->SOLCOS.y); - Real64 winPhi = surf.Tilt * Constant::DegToRad; - Real64 winTheta = surf.Azimuth * Constant::DegToRad; - Real64 phi = std::abs(solPhi - winPhi); - Real64 theta = std::abs(solTheta - winTheta); - Material::NormalizePhiTheta(phi, theta); -#ifdef PRECALC_INTERP_SCREEN - int ip1, ip2, it1, it2; - BilinearInterpCoeffs coeffs; - Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2); - GetBilinearInterpCoeffs( - phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs); - auto const &b11 = screen->btars[ip1][it1]; - auto const &b12 = screen->btars[ip1][it2]; - auto const &b21 = screen->btars[ip2][it1]; - auto const &b22 = screen->btars[ip2][it2]; - - Real64 RScBack = BilinearInterp(b11.RefSolFront, b12.RefSolFront, b21.RefSolFront, b22.RefSolFront, coeffs); - Real64 RScDifBack = screen->DfRef; - - Real64 RGlBmFr = Window::POLYF(CosInc, thisConstruct.ReflSolBeamFrontCoef); // Beam front reflectance of glass - Real64 RGlDifFr = thisConstruct.ReflectSolDiffFront; // Diffuse front reflectance of glass - // beam transmittance (written in subroutine CalcScreenTransmittance each time step) - TScBmBm = BilinearInterp(b11.BmTrans, b12.BmTrans, b21.BmTrans, b22.BmTrans, coeffs); - TBmBmSc = TBmBm * TScBmBm; - TScBmDif = BilinearInterp(b11.DfTrans, b12.DfTrans, b21.DfTrans, b22.DfTrans, coeffs); - // beam-beam and diffuse transmittance of exterior beam - TBmAllShBlSc = TScBmBm * (TBmBm + RGlBmFr * RScBack * TDifBare / (1 - RGlDifFr * RScDifBack)) + - TScBmDif * TDifBare / (1 - RGlDifFr * RScDifBack); - TBmBmShBlSc = TBmBmSc; - TBmDifShBlSc = TBmAllShBlSc - TBmBmShBlSc; - // Report variable for Beam-to-Diffuse transmittance (scattered transmittance) - s_surf->SurfWinScGlSysTsolBmBm(SurfNum) = TBmBmSc; - s_surf->SurfWinScTsolBmBm(SurfNum) = TScBmBm; - s_surf->SurfWinScTsolBmDif(SurfNum) = TScBmDif; -#else // !PRECALC_INTERP_SCREEN - Material::ScreenBmTransAbsRef btar; - CalcScreenTransmittance(state, screen, phi, theta, btar); - + auto const btar = getScreenBtar(state, screen, surf); Real64 RScBack = btar.RefSolFront; Real64 RScDifBack = screen->DfRef; Real64 RGlBmFr = Window::POLYF(CosInc, thisConstruct.ReflSolBeamFrontCoef); // Beam front reflectance of glass Real64 RGlDifFr = thisConstruct.ReflectSolDiffFront; // Diffuse front reflectance of glass - // beam transmittance (written in subroutine CalcScreenTransmittance each time step) + // beam transmittance TScBmBm = btar.BmTrans; TBmBmSc = TBmBm * TScBmBm; TScBmDif = btar.DfTrans; @@ -7352,7 +7151,6 @@ void CalcInteriorSolarDistribution(EnergyPlusData &state) s_surf->SurfWinScGlSysTsolBmBm(SurfNum) = TBmBmSc; s_surf->SurfWinScTsolBmBm(SurfNum) = TScBmBm; s_surf->SurfWinScTsolBmDif(SurfNum) = TScBmDif; -#endif // PRECALC_INTERP_SCREEN } else { TBlBmBm = surfShade.blind.bmBmTrans; TBlBmDif = FrontBeamDiffTrans; @@ -7945,60 +7743,7 @@ void CalcInteriorSolarDistribution(EnergyPlusData &state) auto const *screen = dynamic_cast(s_mat->materials(ScNum)); assert(screen != nullptr); - // auto &surf = s_surf->Surface(SurfNum); - Real64 solPhi = std::acos(state.dataEnvrn->SOLCOS.z); - Real64 solTheta = std::atan2(state.dataEnvrn->SOLCOS.x, state.dataEnvrn->SOLCOS.y); - Real64 winPhi = surf.Tilt * Constant::DegToRad; - Real64 winTheta = surf.Azimuth * Constant::DegToRad; - Real64 phi = std::abs(solPhi - winPhi); - Real64 theta = std::abs(solTheta - winTheta); - Material::NormalizePhiTheta(phi, theta); -#ifdef PRECALC_INTERP_SCREEN - int ip1, ip2, it1, it2; - BilinearInterpCoeffs coeffs; - Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2); - GetBilinearInterpCoeffs( - phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs); - auto const &b11 = screen->btars[ip1][it1]; - auto const &b12 = screen->btars[ip1][it2]; - auto const &b21 = screen->btars[ip2][it1]; - auto const &b22 = screen->btars[ip2][it2]; - - Real64 TScBmBmBack = BilinearInterp(b11.BmTransBack, b12.BmTransBack, b21.BmTransBack, b22.BmTransBack, coeffs); - Real64 TScBmDiffBack = BilinearInterp(b11.DfTransBack, b12.DfTransBack, b21.DfTransBack, b22.DfTransBack, coeffs); - Real64 RScBack = BilinearInterp(b11.RefSolFront, b12.RefSolFront, b21.RefSolFront, b22.RefSolFront, coeffs); - Real64 RScDifBack = screen->DfRef; - for (int Lay = 1; Lay <= NBackGlass; ++Lay) { - Real64 AbWinBack = Window::POLYF(CosIncBack, constrBack.AbsBeamBackCoef(Lay)); - Real64 AGlDiffFront = constrBack.AbsDiff(Lay); - state.dataSolarShading->SurfWinAbsBeam(Lay) = - AbWinBack + (TGlBmBack * AGlDiffFront * RScBack / (1.0 - RScDifBack * RGlDiffFront)); - } - - // Interior beam transmitted by exterior back window with EXTERIOR SCREEN - Real64 TScDifDif = screen->DfTrans; - Real64 RScBmDifBk = BilinearInterp(b11.RefSolBack, b12.RefSolBack, b21.RefSolBack, b22.RefSolBack, coeffs); - Real64 RGlDifFr = thisConstruct.ReflectSolDiffFront; - Real64 RScDifDifBk = screen->DfRef; - TransBeamWin = TGlBmBack * - (TScBmBmBack + TScBmDiffBack + TScDifDif * RScBmDifBk * RGlDifFr / (1.0 - RScDifDifBk * RGlDifFr)); - - // Interior beam absorbed by EXTERIOR SCREEN on exterior back window - Real64 AbsScBack = BilinearInterp(b11.AbsSolBack, b12.AbsSolBack, b21.AbsSolBack, b22.AbsSolBack, coeffs); - Real64 AbsScDiffBack = screen->DfAbs; - Real64 RScDiffBack = BilinearInterp(b11.RefSolFront, b12.RefSolFront, b21.RefSolFront, b22.RefSolFront, coeffs); - // Screen solar back absorptance for interior solar - Real64 AScBack = - TGlBmBack * (AbsScBack + RScBack * RGlDiffFront * AbsScDiffBack / (1.0 - RScDiffBack * RGlDiffFront)); - - BABSZone += BOverlap * AScBack; - backSurfBeamSolInTrans += BOverlap * AScBack; - state.dataSolarShading->SurfWinIntBeamAbsByShadFac(BackSurfNum) = - BOverlap * AScBack / (s_surf->Surface(BackSurfNum).Area + s_surf->SurfWinDividerArea(BackSurfNum)); -#else // !PRECALC_INTERP_SCREEN - Material::ScreenBmTransAbsRef btar; - Material::CalcScreenTransmittance(state, screen, phi, theta, btar); - + auto const btar = getScreenBtar(state, screen, surf); Real64 TScBmBmBack = btar.BmTransBack; Real64 TScBmDiffBack = btar.DfTransBack; Real64 RScBack = btar.RefSolFront; @@ -8027,9 +7772,9 @@ void CalcInteriorSolarDistribution(EnergyPlusData &state) TGlBmBack * (AbsScBack + RScBack * RGlDiffFront * AbsScDiffBack / (1.0 - RScDiffBack * RGlDiffFront)); BABSZone += BOverlap * AScBack; + backSurfBeamSolInTrans += BOverlap * AScBack; state.dataSolarShading->SurfWinIntBeamAbsByShadFac(BackSurfNum) = BOverlap * AScBack / (s_surf->Surface(BackSurfNum).Area + s_surf->SurfWinDividerArea(BackSurfNum)); -#endif // PRECALC_INTERP_SCREEN } // End of check if exterior screen on back window diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index 4e0f278592a..56a096e8887 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -928,1377 +928,1361 @@ namespace SurfaceGeometry { state.dataSurface->extMovInsuls.allocate(state.dataSurface->TotSurfaces); } - void GetSurfaceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input + // Match up interzone surfaces: reconcile ExtBoundCond, check construction layers, + // areas, tilts, azimuths, and exposures for each pair of interzone surfaces. + static void matchInterzoneSurfaces(EnergyPlusData &state, std::string_view RoutineName, int MovedSurfs, bool &SurfError) { + bool NonMatch = false; + bool izConstDiffMsg = false; - // SUBROUTINE INFORMATION: - // AUTHOR Richard Liesen - // DATE WRITTEN November 1997 - // MODIFIED April 1999, Linda Lawrie - // Dec. 2000, FW (add "one-wall zone" checks) - // RE-ENGINEERED May 2000, Linda Lawrie (breakout surface type gets) - - // PURPOSE OF THIS SUBROUTINE: - // The purpose of this subroutine is to read in the surface information - // from the input data file and interpret and put in the derived type - - // METHODOLOGY EMPLOYED: - // The order of surfaces does not matter and the surfaces are resorted into - // the hierarchical order: - // All Shading Surfaces - // Airwalls for space x1 - // Base Surfaces for space x1 - // Opaque Subsurfaces for space x1 - // Window Subsurfaces for space x1 - // TDD Dome Surfaces for space x1 - // Airwalls for space x2 - // Base Surfaces for space x2 - // etc - // Pointers are set in the spaces (AllSurfaceFirst/Last, HTSurfaceFirst/Last, OpaqOrIntMassSurfaceFirst/Last, WindowSurfaceFirst/Last, - // OpaqOrWinSurfaceFirst/Last, TDDDomeFirst/Last) - - // REFERENCES: - // This routine manages getting the input for the following Objects: - // SurfaceGeometry - // Surface:Shading:Detached - // Surface:HeatTransfer - // Surface:HeatTransfer:Sub - // Surface:Shading:Attached - // Surface:InternalMass - - // Vertex input: - // N3 , \field Number of Surface Vertices -- Number of (X,Y,Z) groups in this surface - // \note currently limited 3 or 4, later? - // \min 3 - // \max 4 - // \memo vertices are given in SurfaceGeometry coordinates -- if relative, all surface coordinates - // \memo are "relative" to the Zone Origin. if WCS, then building and zone origins are used - // \memo for some internal calculations, but all coordinates are given in an "absolute" system. - // N4, \field Vertex 1 X-coordinate - // \units m - // \type real - // N5 , \field Vertex 1 Y-coordinate - // \units m - // \type real - // N6 , \field Vertex 1 Z-coordinate - // \units m - // \type real - // N7, \field Vertex 2 X-coordinate - // \units m - // \type real - // N8, \field Vertex 2 Y-coordinate - // \units m - // \type real - // N9, \field Vertex 2 Z-coordinate - // \units m - // \type real - // N10, \field Vertex 3 X-coordinate - // \units m - // \type real - // N11, \field Vertex 3 Y-coordinate - // \units m - // \type real - // N12, \field Vertex 3 Z-coordinate - // \units m - // \type real - // N13, \field Vertex 4 X-coordinate - // \units m - // \type real - // N14, \field Vertex 4 Y-coordinate - // \type real - // \units m - // N15; \field Vertex 4 Z-coordinate - // \units m - // \type real - - // The vertices are stored in the surface derived type. - // +(1)-------------------------(4)+ - // | | - // | | - // | | - // +(2)-------------------------(3)+ - // The above diagram shows the actual coordinate points of a typical wall - // (you're on the outside looking toward the wall) as stored into - // Surface%Vertex(1:) - - static constexpr std::string_view RoutineName = "GetSurfaceData: "; - using namespace Vectors; - using namespace DataErrorTracking; - - bool NonMatch(false); // Error for non-matching interzone surfaces - int MovedSurfs; // Number of Moved Surfaces (when sorting into hierarchical structure) - bool SurfError(false); // General Surface Error, causes fatal error at end of routine - int TotLay; // Total layers in a construction - int TotLayFound; // Total layers in the construction of a matching interzone surface - // Simple Surfaces (Rectangular) - int LayNumOutside; // Outside material numbers for a shaded construction - // entries with two glazing systems - int NeedToAddSurfaces; // Surfaces that will be added due to "unentered" other zone surface - int NeedToAddSubSurfaces; // SubSurfaces that will be added due to "unentered" other zone surface - int CurNewSurf = 0; - Real64 SurfWorldAz; - Real64 SurfTilt; - - int MultFound; - int MultSurfNum; - bool SubSurfaceSevereDisplayed; - bool subSurfaceError(false); - bool errFlag; - - bool izConstDiff; // differences in construction for IZ surfaces - bool izConstDiffMsg; // display message about hb diffs only once. + for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { + if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) { + continue; + } + if (state.dataSurface->Surface(SurfNum).ExtBoundCond == unreconciledZoneSurface) { + if (not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) { + int Found = 0; + if (state.dataSurface->Surface(SurfNum).ExtBoundCondName == state.dataSurface->Surface(SurfNum).Name) { + Found = SurfNum; + } else { + Found = Util::FindItemInList(state.dataSurface->Surface(SurfNum).ExtBoundCondName, state.dataSurface->Surface, MovedSurfs); + } + if (Found != 0) { + state.dataSurface->Surface(SurfNum).ExtBoundCond = Found; + // Check that matching surface is also "OtherZoneSurface" + if (state.dataSurface->Surface(Found).ExtBoundCond <= 0 && + state.dataSurface->Surface(Found).ExtBoundCond != unreconciledZoneSurface) { + ShowSevereError(state, EnergyPlus::format("{}Potential \"OtherZoneSurface\" is not matched correctly:", RoutineName)); + ShowContinueError(state, + EnergyPlus::format("Surface={}, Zone={}", + state.dataSurface->Surface(SurfNum).Name, + state.dataSurface->Surface(SurfNum).ZoneName)); + ShowContinueError(state, + EnergyPlus::format("Nonmatched Other/InterZone Surface={}, Zone={}", + state.dataSurface->Surface(Found).Name, + state.dataSurface->Surface(Found).ZoneName)); + SurfError = true; + } + // Check that matching interzone surface has construction with reversed layers + if (Found != SurfNum) { // Interzone surface + // Make sure different zones too (CR 4110) + if (state.dataSurface->Surface(SurfNum).spaceNum == state.dataSurface->Surface(Found).spaceNum) { + ++state.dataSurfaceGeometry->ErrCount2; + if (state.dataSurfaceGeometry->ErrCount2 == 1 && !state.dataGlobal->DisplayExtraWarnings) { + ShowWarningError( + state, + EnergyPlus::format("{}CAUTION -- Interspace surfaces are occurring in the same space(s).", RoutineName)); + ShowContinueError( + state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual occurrences."); + } + if (state.dataGlobal->DisplayExtraWarnings) { + ShowWarningError( + state, EnergyPlus::format("{}CAUTION -- Interspace surfaces are usually in different spaces", RoutineName)); + ShowContinueError(state, + EnergyPlus::format("Surface={}, Space={}, Zone={}", + state.dataSurface->Surface(SurfNum).Name, + state.dataHeatBal->space(state.dataSurface->Surface(SurfNum).spaceNum).Name, + state.dataSurface->Surface(SurfNum).ZoneName)); + ShowContinueError(state, + EnergyPlus::format("Surface={}, Space={}, Zone={}", + state.dataSurface->Surface(Found).Name, + state.dataHeatBal->space(state.dataSurface->Surface(Found).spaceNum).Name, + state.dataSurface->Surface(Found).ZoneName)); + } + } + int ConstrNum = state.dataSurface->Surface(SurfNum).Construction; + int ConstrNumFound = state.dataSurface->Surface(Found).Construction; + if (ConstrNum <= 0 || ConstrNumFound <= 0) { + continue; + } + if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning && + state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning) { + continue; + } + if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning && + state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) { + continue; + } + int TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers; + int TotLayFound = state.dataConstruction->Construct(ConstrNumFound).TotLayers; + if (TotLay != TotLayFound) { // Different number of layers + // match on like Uvalues (nominal) + if (std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) { + ShowSevereError( + state, + EnergyPlus::format("{}Construction {} of interzone surface {} does not have the same number of layers as the " + "construction {} of adjacent surface {}", + RoutineName, + state.dataConstruction->Construct(ConstrNum).Name, + state.dataSurface->Surface(SurfNum).Name, + state.dataConstruction->Construct(ConstrNumFound).Name, + state.dataSurface->Surface(Found).Name)); + if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning || + !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning) { + ShowContinueError(state, "...this problem for this pair will not be reported again."); + state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning = true; + state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning = true; + } + SurfError = true; + } + } else { // Same number of layers; check for reverse layers + bool izConstDiff = false; + CheckForReversedLayers(state, izConstDiff, ConstrNum, ConstrNumFound, TotLay); + if (izConstDiff && + std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) { + ShowSevereError( + state, + EnergyPlus::format("{}Construction {} of interzone surface {} does not have the same materials in the " + "reverse order as the construction {} of adjacent surface {}", + RoutineName, + state.dataConstruction->Construct(ConstrNum).Name, + state.dataSurface->Surface(SurfNum).Name, + state.dataConstruction->Construct(ConstrNumFound).Name, + state.dataSurface->Surface(Found).Name)); + ShowContinueError(state, + "or the properties of the reversed layers are not correct due to differing layer front and " + "back side values"); + if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning || + !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) { + ShowContinueError(state, "...this problem for this pair will not be reported again."); + state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true; + state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true; + } + SurfError = true; + } else if (izConstDiff) { + ShowWarningError( + state, + EnergyPlus::format("{}Construction {} of interzone surface {} does not have the same materials in the " + "reverse order as the construction {} of adjacent surface {}", + RoutineName, + state.dataConstruction->Construct(ConstrNum).Name, + state.dataSurface->Surface(SurfNum).Name, + state.dataConstruction->Construct(ConstrNumFound).Name, + state.dataSurface->Surface(Found).Name)); + ShowContinueError(state, + "or the properties of the reversed layers are not correct due to differing layer front and " + "back side values"); + ShowContinueError( + state, + EnergyPlus::format( + "...but Nominal U values are similar, diff=[{:.4R}] ... simulation proceeds.", + std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)))); + if (!izConstDiffMsg) { + ShowContinueError(state, + "...if the two zones are expected to have significantly different temperatures, the proper " + "\"reverse\" construction should be created."); + izConstDiffMsg = true; + } + if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning || + !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) { + ShowContinueError(state, "...this problem for this pair will not be reported again."); + state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true; + state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true; + } + } + } - // Get the total number of surfaces to allocate derived type and for surface loops + // If significantly different areas + int MultFound = state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).Multiplier * + state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).ListMultiplier; + int MultSurfNum = state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).Multiplier * + state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).ListMultiplier; + if (state.dataSurface->Surface(Found).Area > 0.0) { + if (std::abs((state.dataSurface->Surface(Found).Area * MultFound - + state.dataSurface->Surface(SurfNum).Area * MultSurfNum) / + state.dataSurface->Surface(Found).Area * MultFound) > 0.02) { // 2% difference in areas + ++state.dataSurfaceGeometry->ErrCount4; + if (state.dataSurfaceGeometry->ErrCount4 == 1 && !state.dataGlobal->DisplayExtraWarnings) { + ShowWarningError( + state, + EnergyPlus::format( + "{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:", + RoutineName)); + ShowContinueError( + state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual mismatches."); + } + if (state.dataGlobal->DisplayExtraWarnings) { + ShowWarningError( + state, + EnergyPlus::format( + "{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:", + RoutineName)); - if (state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag) { - return; - } - state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag = true; + if (MultFound == 1 && MultSurfNum == 1) { + ShowContinueError(state, + EnergyPlus::format(" Area={:.1T} in Surface={}, Zone={}", + state.dataSurface->Surface(SurfNum).Area, + state.dataSurface->Surface(SurfNum).Name, + state.dataSurface->Surface(SurfNum).ZoneName)); + ShowContinueError(state, + EnergyPlus::format(" Area={:.1T} in Surface={}, Zone={}", + state.dataSurface->Surface(Found).Area, + state.dataSurface->Surface(Found).Name, + state.dataSurface->Surface(Found).ZoneName)); + } else { // Show multiplier info + ShowContinueError( + state, + EnergyPlus::format(" Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}", + state.dataSurface->Surface(SurfNum).Area, + MultSurfNum, + state.dataSurface->Surface(SurfNum).Area * MultSurfNum, + state.dataSurface->Surface(SurfNum).Name, + state.dataSurface->Surface(SurfNum).ZoneName)); - GetGeometryParameters(state, ErrorsFound); + ShowContinueError( + state, + EnergyPlus::format(" Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}", + state.dataSurface->Surface(Found).Area, + MultFound, + state.dataSurface->Surface(Found).Area * MultFound, + state.dataSurface->Surface(Found).Name, + state.dataSurface->Surface(Found).ZoneName)); + } + } + } + } + // Check opposites Azimuth and Tilt + if (std::abs(std::abs(state.dataSurface->Surface(Found).Tilt + state.dataSurface->Surface(SurfNum).Tilt) - 180.0) > 1.0) { + ShowWarningError(state, EnergyPlus::format("{}InterZone Surface Tilts do not match as expected.", RoutineName)); + ShowContinueError(state, + EnergyPlus::format(" Tilt={:.1T} in Surface={}, Zone={}", + state.dataSurface->Surface(SurfNum).Tilt, + state.dataSurface->Surface(SurfNum).Name, + state.dataSurface->Surface(SurfNum).ZoneName)); + ShowContinueError(state, + EnergyPlus::format(" Tilt={:.1T} in Surface={}, Zone={}", + state.dataSurface->Surface(Found).Tilt, + state.dataSurface->Surface(Found).Name, + state.dataSurface->Surface(Found).ZoneName)); + } + // check surface class match + bool classMismatch = (state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Wall && + state.dataSurface->Surface(Found).Class != SurfaceClass::Wall) || + (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall && + state.dataSurface->Surface(Found).Class == SurfaceClass::Wall) || + (state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Roof && + state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) || + (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof && + state.dataSurface->Surface(Found).Class == SurfaceClass::Floor); + if (classMismatch) { + ShowWarningError(state, EnergyPlus::format("{}InterZone Surface Classes do not match as expected.", RoutineName)); + ShowContinueError(state, + EnergyPlus::format("Surface=\"{}\", surface class={}", + state.dataSurface->Surface(SurfNum).Name, + cSurfaceClass(state.dataSurface->Surface(SurfNum).Class))); + ShowContinueError(state, + EnergyPlus::format("Adjacent Surface=\"{}\", surface class={}", + state.dataSurface->Surface(Found).Name, + cSurfaceClass(state.dataSurface->Surface(Found).Class))); + ShowContinueError(state, "Other errors/warnings may follow about these surfaces."); + } + if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof && + state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Floor) { + if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall) { + if (state.dataSurface->Surface(SurfNum).BaseSurf == 0) { + continue; + } + if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Roof || + state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Floor) { + continue; + } + } + if (std::abs(std::abs(state.dataSurface->Surface(SurfNum).Azimuth - state.dataSurface->Surface(Found).Azimuth) - + 180.0) > 1.0) { + if (std::abs(state.dataSurface->Surface(SurfNum).SinTilt) > 0.5 || state.dataGlobal->DisplayExtraWarnings) { + ShowWarningError(state, + EnergyPlus::format("{}InterZone Surface Azimuths do not match as expected.", RoutineName)); + ShowContinueError(state, + EnergyPlus::format(" Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}", + state.dataSurface->Surface(SurfNum).Azimuth, + state.dataSurface->Surface(SurfNum).Tilt, + state.dataSurface->Surface(SurfNum).Name, + state.dataSurface->Surface(SurfNum).ZoneName)); + ShowContinueError(state, + EnergyPlus::format(" Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}", + state.dataSurface->Surface(Found).Azimuth, + state.dataSurface->Surface(Found).Tilt, + state.dataSurface->Surface(Found).Name, + state.dataSurface->Surface(Found).ZoneName)); + ShowContinueError(state, + EnergyPlus::format("..surface class of first surface={}", + cSurfaceClass(state.dataSurface->Surface(SurfNum).Class))); + ShowContinueError(state, + EnergyPlus::format("..surface class of second surface={}", + cSurfaceClass(state.dataSurface->Surface(Found).Class))); + } + } + } - if (state.dataSurface->WorldCoordSystem) { - bool RelWarning = false; - if (state.dataHeatBal->BuildingAzimuth != 0.0) { - RelWarning = true; - } - for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) { - if (state.dataHeatBal->Zone(ZoneNum).RelNorth != 0.0) { - RelWarning = true; - } - } - if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) { - ShowWarningError( - state, - EnergyPlus::format( - "{}World Coordinate System selected. Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.", - RoutineName)); - ShowContinueError(state, - "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs."); - state.dataSurfaceGeometry->WarningDisplayed = true; - } - RelWarning = false; - for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) { - if (state.dataHeatBal->Zone(ZoneNum).OriginX != 0.0) { - RelWarning = true; - } - if (state.dataHeatBal->Zone(ZoneNum).OriginY != 0.0) { - RelWarning = true; - } - if (state.dataHeatBal->Zone(ZoneNum).OriginZ != 0.0) { - RelWarning = true; + // Make sure exposures (Sun, Wind) are the same and are "not" + auto warnAndClearExposure = [&](bool &flag1, bool &flag2, std::string_view exposureName) { + if (flag1 || flag2) { + ShowWarningError( + state, + EnergyPlus::format( + "{}Interzone surfaces cannot be \"{}\" -- removing {}", RoutineName, exposureName, exposureName)); + ShowContinueError(state, + EnergyPlus::format(" Surface={}, Zone={}", + state.dataSurface->Surface(SurfNum).Name, + state.dataSurface->Surface(SurfNum).ZoneName)); + ShowContinueError(state, + EnergyPlus::format(" Surface={}, Zone={}", + state.dataSurface->Surface(Found).Name, + state.dataSurface->Surface(Found).ZoneName)); + flag1 = false; + flag2 = false; + } + }; + warnAndClearExposure( + state.dataSurface->Surface(SurfNum).ExtSolar, state.dataSurface->Surface(Found).ExtSolar, "SunExposed"); + warnAndClearExposure( + state.dataSurface->Surface(SurfNum).ExtWind, state.dataSurface->Surface(Found).ExtWind, "WindExposed"); + } + // Set opposing surface back to this one (regardless of error) + state.dataSurface->Surface(Found).ExtBoundCond = SurfNum; + // Check subsurfaces... make sure base surface is also an interzone surface + if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface + if ((state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) && + not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) { + if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond == + state.dataSurface->Surface(SurfNum).BaseSurf) { + ShowSevereError(state, + EnergyPlus::format("{}SubSurface=\"{}\" is an interzone subsurface.", + RoutineName, + state.dataSurface->Surface(SurfNum).Name)); + ShowContinueError( + state, + EnergyPlus::format("..but the Base Surface is not an interzone surface, Surface=\"{}\".", + state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name)); + SurfError = true; + } + } + } + } else { + ShowSevereError(state, + EnergyPlus::format("{}Adjacent Surface not found: {} adjacent to surface {}", + RoutineName, + state.dataSurface->Surface(SurfNum).ExtBoundCondName, + state.dataSurface->Surface(SurfNum).Name)); + NonMatch = true; + SurfError = true; + } + } else if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface + if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0 && + state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond != + state.dataSurface->Surface(SurfNum).BaseSurf) { + ShowSevereError(state, EnergyPlus::format("{}SubSurface on Interzone Surface must be an Interzone SubSurface.", RoutineName)); + ShowContinueError( + state, EnergyPlus::format("...OutsideFaceEnvironment is blank, in Surface={}", state.dataSurface->Surface(SurfNum).Name)); + SurfError = true; + } else { + ++state.dataSurfaceGeometry->ErrCount3; + if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) { + ShowWarningError(state, EnergyPlus::format("{}Blank name for Outside Boundary Condition Objects.", RoutineName)); + ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces."); + } + if (state.dataGlobal->DisplayExtraWarnings) { + ShowWarningError(state, + EnergyPlus::format("{}Blank name for Outside Boundary Condition Object, in surface={}", + RoutineName, + state.dataSurface->Surface(SurfNum).Name)); + ShowContinueError(state, + EnergyPlus::format("Resetting this surface to be an internal zone surface, zone={}", + state.dataSurface->Surface(SurfNum).ZoneName)); + } + state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name; + state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum; + } + } else { + ++state.dataSurfaceGeometry->ErrCount3; + if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) { + ShowSevereError(state, EnergyPlus::format("{}Blank name for Outside Boundary Condition Objects.", RoutineName)); + ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces."); + } + if (state.dataGlobal->DisplayExtraWarnings) { + ShowWarningError(state, + EnergyPlus::format("{}Blank name for Outside Boundary Condition Object, in surface={}", + RoutineName, + state.dataSurface->Surface(SurfNum).Name)); + ShowContinueError(state, + EnergyPlus::format("Resetting this surface to be an internal zone (adiabatic) surface, zone={}", + state.dataSurface->Surface(SurfNum).ZoneName)); + } + state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name; + state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum; + SurfError = true; } } - if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) { - ShowWarningError( - state, - EnergyPlus::format( - "{}World Coordinate System selected. Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.", - RoutineName)); - ShowContinueError(state, - "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs."); - state.dataSurfaceGeometry->WarningDisplayed = true; - } - } - - int TotDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site:Detailed"); - int TotDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building:Detailed"); - int TotRectDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site"); - int TotRectDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building"); - int TotHTSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "BuildingSurface:Detailed"); - int TotDetailedWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Detailed"); - int TotDetailedRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RoofCeiling:Detailed"); - int TotDetailedFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Detailed"); - int TotHTSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "FenestrationSurface:Detailed"); - int TotShdSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Zone:Detailed"); - int TotOverhangs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang"); - int TotOverhangsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang:Projection"); - int TotFins = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin"); - int TotFinsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin:Projection"); - int TotRectWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window"); - int TotRectDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door"); - int TotRectGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor"); - int TotRectIZWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window:Interzone"); - int TotRectIZDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door:Interzone"); - int TotRectIZGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor:Interzone"); - int TotRectExtWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Exterior"); - int TotRectIntWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Adiabatic"); - int TotRectIZWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Interzone"); - int TotRectUGWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Underground"); - int TotRectRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Roof"); - int TotRectCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Adiabatic"); - int TotRectIZCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Interzone"); - int TotRectGCFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:GroundContact"); - int TotRectIntFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Adiabatic"); - int TotRectIZFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Interzone"); - - state.dataSurface->TotOSC = 0; - - int TotIntMassSurfaces = GetNumIntMassSurfaces(state); - - state.dataSurface->TotSurfaces = (TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg) * 2 + TotHTSurfs + - TotHTSubs + TotShdSubs * 2 + TotIntMassSurfaces + TotOverhangs * 2 + TotOverhangsProjection * 2 + - TotFins * 4 + TotFinsProjection * 4 + TotDetailedWalls + TotDetailedRoofs + TotDetailedFloors + - TotRectWindows + TotRectDoors + TotRectGlazedDoors + TotRectIZWindows + TotRectIZDoors + - TotRectIZGlazedDoors + TotRectExtWalls + TotRectIntWalls + TotRectIZWalls + TotRectUGWalls + TotRectRoofs + - TotRectCeilings + TotRectIZCeilings + TotRectGCFloors + TotRectIntFloors + TotRectIZFloors; - - state.dataSurfaceGeometry->SurfaceTmp.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately - state.dataSurfaceGeometry->UniqueSurfaceNames.reserve(state.dataSurface->TotSurfaces); - // SurfaceTmp structure is allocated via derived type initialization. - - int NumSurfs = 0; - int AddedSubSurfaces = 0; - state.dataErrTracking->AskForSurfacesReport = true; - - GetDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotDetachedFixed, TotDetachedBldg); - - GetRectDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotRectDetachedFixed, TotRectDetachedBldg); - - GetHTSurfaceData(state, - ErrorsFound, - NumSurfs, - TotHTSurfs, - TotDetailedWalls, - TotDetailedRoofs, - TotDetailedFloors, - state.dataSurfaceGeometry->BaseSurfCls, - state.dataSurfaceGeometry->BaseSurfIDs, - NeedToAddSurfaces); - - GetRectSurfaces(state, - ErrorsFound, - NumSurfs, - TotRectExtWalls, - TotRectIntWalls, - TotRectIZWalls, - TotRectUGWalls, - TotRectRoofs, - TotRectCeilings, - TotRectIZCeilings, - TotRectGCFloors, - TotRectIntFloors, - TotRectIZFloors, - state.dataSurfaceGeometry->BaseSurfIDs, - NeedToAddSurfaces); - - GetHTSubSurfaceData(state, - ErrorsFound, - NumSurfs, - TotHTSubs, - state.dataSurfaceGeometry->SubSurfCls, - state.dataSurfaceGeometry->SubSurfIDs, - AddedSubSurfaces, - NeedToAddSubSurfaces); - - GetRectSubSurfaces(state, - ErrorsFound, - NumSurfs, - TotRectWindows, - TotRectDoors, - TotRectGlazedDoors, - TotRectIZWindows, - TotRectIZDoors, - TotRectIZGlazedDoors, - state.dataSurfaceGeometry->SubSurfIDs, - AddedSubSurfaces, - NeedToAddSubSurfaces); - - GetAttShdSurfaceData(state, ErrorsFound, NumSurfs, TotShdSubs); - - GetSimpleShdSurfaceData(state, ErrorsFound, NumSurfs, TotOverhangs, TotOverhangsProjection, TotFins, TotFinsProjection); - - GetIntMassSurfaceData(state, ErrorsFound, NumSurfs); - - state.dataSurface->TotSurfaces = NumSurfs + AddedSubSurfaces + NeedToAddSurfaces + NeedToAddSubSurfaces; - - if (ErrorsFound) { - ShowFatalError(state, EnergyPlus::format("{}Errors discovered, program terminates.", RoutineName)); } - - state.dataSurface->Surface.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately - state.dataSurface->SurfaceWindow.allocate(state.dataSurface->TotSurfaces); - state.dataSurface->surfShades.allocate(state.dataSurface->TotSurfaces); - AllocateSurfaceArrays(state); - AllocateSurfaceWindows(state, state.dataSurface->TotSurfaces); - - // Have to make room for added surfaces, if needed - int FirstTotalSurfaces = NumSurfs + AddedSubSurfaces; - if (NeedToAddSurfaces + NeedToAddSubSurfaces > 0) { - state.dataSurfaceGeometry->SurfaceTmp.redimension(state.dataSurface->TotSurfaces); - CurNewSurf = FirstTotalSurfaces; + if (NonMatch) { + ShowSevereError(state, EnergyPlus::format("{}Non matching interzone surfaces found", RoutineName)); } + } - // add the "need to add" surfaces - // Debug write(outputfiledebug,*) ' need to add ',NeedtoAddSurfaces+NeedToAddSubSurfaces - for (int SurfNum = 1; SurfNum <= FirstTotalSurfaces; ++SurfNum) { - auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); - if ((surfTemp.ExtBoundCond != unenteredAdjacentZoneSurface) && (surfTemp.ExtBoundCond != unenteredAdjacentSpaceSurface)) { + // Check that subsurface exterior boundary conditions are consistent with + // their base surface (e.g. adiabatic sub in exterior base, interzone sub in adiabatic base, etc.) + static void checkSubSurfaceExtBoundConsistency(EnergyPlusData &state, std::string_view RoutineName, bool &SurfError) + { + bool SubSurfaceSevereDisplayed = false; + for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { + auto const &surf = state.dataSurface->Surface(SurfNum); + if (!surf.HeatTransSurf) { continue; } - // Need to add surface - ++CurNewSurf; - // Debug write(outputfiledebug,*) ' adding surface=',curnewsurf - auto &newSurf = state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf); - newSurf = surfTemp; - // Basic parameters are the same for both surfaces. - if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) { - int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones); - if (Found == 0) { - continue; - } - newSurf.Zone = Found; - auto &newZone = state.dataHeatBal->Zone(Found); - newSurf.ZoneName = newZone.Name; - assert(!newZone.spaceIndexes.empty()); - newSurf.spaceNum = 0; // clear this here and set later - } else if (surfTemp.ExtBoundCond == unenteredAdjacentSpaceSurface) { - int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->space, state.dataGlobal->numSpaces); - if (Found == 0) { - continue; - } - newSurf.spaceNum = Found; - int zoneNum = state.dataHeatBal->space(Found).zoneNum; - newSurf.Zone = zoneNum; - newSurf.ZoneName = state.dataHeatBal->Zone(zoneNum).Name; - } - // Reverse Construction - newSurf.Construction = DataHeatBalance::AssignReverseConstructionNumber(state, surfTemp.Construction, SurfError); - newSurf.ConstructionStoredInputValue = newSurf.Construction; - // Reverse Vertices - int NVert = surfTemp.Sides; - for (int Vert = 1; Vert <= surfTemp.Sides; ++Vert) { - newSurf.Vertex(Vert) = surfTemp.Vertex(NVert); - --NVert; + if (surf.BaseSurf == SurfNum) { + continue; // base surface } - if (newSurf.Sides > 2) { - Vectors::CreateNewellAreaVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellAreaVector); - newSurf.GrossArea = Vectors::VecLength(newSurf.NewellAreaVector); - newSurf.Area = newSurf.GrossArea; - newSurf.NetAreaShadowCalc = newSurf.Area; - Vectors::CreateNewellSurfaceNormalVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellSurfaceNormalVector); - Vectors::DetermineAzimuthAndTilt( - newSurf.Vertex, SurfWorldAz, SurfTilt, newSurf.lcsx, newSurf.lcsy, newSurf.lcsz, newSurf.NewellSurfaceNormalVector); - newSurf.Azimuth = SurfWorldAz; - newSurf.Tilt = SurfTilt; - newSurf.convOrientation = Convect::GetSurfConvOrientation(newSurf.Tilt); - - // Sine and cosine of azimuth and tilt - newSurf.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad); - newSurf.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad); - newSurf.SinTilt = std::sin(SurfTilt * Constant::DegToRad); - newSurf.CosTilt = std::cos(SurfTilt * Constant::DegToRad); - // Outward normal unit vector (pointing away from room) - newSurf.OutNormVec = newSurf.NewellSurfaceNormalVector; - for (int n = 1; n <= 3; ++n) { - if (std::abs(newSurf.OutNormVec(n) - 1.0) < 1.e-06) { - newSurf.OutNormVec(n) = +1.0; - } - if (std::abs(newSurf.OutNormVec(n) + 1.0) < 1.e-06) { - newSurf.OutNormVec(n) = -1.0; - } - if (std::abs(newSurf.OutNormVec(n)) < 1.e-06) { - newSurf.OutNormVec(n) = 0.0; + auto const &baseSurf = state.dataSurface->Surface(surf.BaseSurf); + // not base surface. Check it. + if (baseSurf.ExtBoundCond <= 0) { // exterior or other base surface + if (surf.ExtBoundCond != baseSurf.ExtBoundCond) { // should match base surface + std::string subCondStr; + if (surf.ExtBoundCond == SurfNum) { + subCondStr = "adiabatic surface"; + } else if (surf.ExtBoundCond > 0) { + subCondStr = "interzone surface"; + } else { + subCondStr = std::string(DataSurfaces::cExtBoundCondition(surf.ExtBoundCond)); } - } - - // Can perform tests on this surface here - newSurf.ViewFactorSky = 0.5 * (1.0 + newSurf.CosTilt); - newSurf.ViewFactorGround = 0.5 * (1.0 - newSurf.CosTilt); - - // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing - // surfaces - newSurf.ViewFactorSkyIR = newSurf.ViewFactorSky; - newSurf.ViewFactorGroundIR = 0.5 * (1.0 - newSurf.CosTilt); - } + std::string baseCondStr(DataSurfaces::cExtBoundCondition(baseSurf.ExtBoundCond)); - // Change Name - newSurf.Name = "iz-" + surfTemp.Name; - // Debug write(outputfiledebug,*) ' new surf name=',TRIM(SurfaceTmp(CurNewSurf)%Name) - // Debug write(outputfiledebug,*) ' new surf in zone=',TRIM(surfacetmp(curnewsurf)%zoneName) - newSurf.ExtBoundCond = unreconciledZoneSurface; - surfTemp.ExtBoundCond = unreconciledZoneSurface; - newSurf.ExtBoundCondName = surfTemp.Name; - surfTemp.ExtBoundCondName = newSurf.Name; - if (newSurf.Class == SurfaceClass::Roof || newSurf.Class == SurfaceClass::Wall || newSurf.Class == SurfaceClass::Floor) { - // base surface - if (surfTemp.Class == SurfaceClass::Roof) { - newSurf.Class = SurfaceClass::Floor; - // Debug write(outputfiledebug,*) ' new surfaces is a floor' - } else if (surfTemp.Class == SurfaceClass::Floor) { - newSurf.Class = SurfaceClass::Roof; - // Debug write(outputfiledebug,*) ' new surfaces is a roof' + if (baseSurf.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) { + ShowWarningError( + state, + EnergyPlus::format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]", + RoutineName, + surf.Name, + DataSurfaces::cExtBoundCondition(surf.ExtBoundCond), + baseSurf.Name, + baseCondStr)); + ShowContinueError(state, "...SubSurface will not use the exterior condition model of the base surface."); + } else { + ShowSevereError( + state, + EnergyPlus::format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]", + RoutineName, + surf.Name, + subCondStr, + baseSurf.Name, + baseCondStr)); + SurfError = true; + } + if (!SubSurfaceSevereDisplayed && SurfError) { + ShowContinueError(state, "...calculations for heat balance would be compromised."); + SubSurfaceSevereDisplayed = true; + } } - newSurf.BaseSurf = CurNewSurf; - newSurf.BaseSurfName = newSurf.Name; - // Debug write(outputfiledebug,*) ' basesurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName) - } else { - // subsurface - int Found = - Util::FindItemInList("iz-" + surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, FirstTotalSurfaces + CurNewSurf - 1); - if (Found > 0) { - newSurf.BaseSurfName = "iz-" + surfTemp.BaseSurfName; - newSurf.BaseSurf = Found; - auto &foundBaseSurf = state.dataSurfaceGeometry->SurfaceTmp(Found); - foundBaseSurf.Area -= newSurf.Area; - if (newSurf.Class == SurfaceClass::Window || newSurf.Class == SurfaceClass::GlassDoor) { - foundBaseSurf.NetAreaShadowCalc -= newSurf.Area / newSurf.Multiplier; - } else { // Door, TDD:Diffuser, TDD:DOME - foundBaseSurf.NetAreaShadowCalc -= newSurf.Area; + } else if (baseSurf.BaseSurf == baseSurf.ExtBoundCond) { + // adiabatic base surface. make sure subsurfaces match + if (surf.ExtBoundCond != SurfNum) { // not adiabatic surface + std::string subCondStr; + if (surf.ExtBoundCond > 0) { + subCondStr = "interzone surface"; + } else { + subCondStr = std::string(DataSurfaces::cExtBoundCondition(surf.ExtBoundCond)); } - newSurf.ExtBoundCond = foundBaseSurf.ExtBoundCond; - newSurf.ExtBoundCondName = surfTemp.Name; - newSurf.ExtSolar = foundBaseSurf.ExtSolar; - newSurf.ExtWind = foundBaseSurf.ExtWind; - newSurf.Zone = foundBaseSurf.Zone; - newSurf.ZoneName = foundBaseSurf.ZoneName; - newSurf.spaceNum = foundBaseSurf.spaceNum; - newSurf.OSCPtr = foundBaseSurf.OSCPtr; - // Debug write(outputfiledebug,*) ' subsurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName) - // Debug write(outputfiledebug,*) ' subsurf, basesurf=',TRIM('iz-'//SurfaceTmp(SurfNum)%BaseSurfName) - } else { ShowSevereError( state, - EnergyPlus::format("{}Adding unentered subsurface, could not find base surface=iz-{}", RoutineName, surfTemp.BaseSurfName)); + EnergyPlus::format( + "{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [adiabatic surface]", + RoutineName, + surf.Name, + subCondStr, + baseSurf.Name)); + if (!SubSurfaceSevereDisplayed) { + ShowContinueError(state, "...calculations for heat balance would be compromised."); + SubSurfaceSevereDisplayed = true; + } SurfError = true; } + } else if (baseSurf.ExtBoundCond > 0) { // interzone surface + if (surf.ExtBoundCond == SurfNum) { + ShowSevereError(state, + EnergyPlus::format("{}Subsurface=\"{}\" is an adiabatic surface in an Interzone base surface=\"{}\"", + RoutineName, + surf.Name, + baseSurf.Name)); + if (!SubSurfaceSevereDisplayed) { + ShowContinueError(state, "...calculations for heat balance would be compromised."); + SubSurfaceSevereDisplayed = true; + } + // SurfError=.TRUE. + } } } - //********************************************************************************** - // After all of the surfaces have been defined then the base surfaces for the - // sub-surfaces can be defined. Loop through surfaces and match with the sub-surface - // names. - for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { - auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); - if (!surfTemp.HeatTransSurf) { - continue; - } + } - int Found = 0; - // why are we doing this again? this should have already been done. - if (Util::SameString(surfTemp.BaseSurfName, surfTemp.Name)) { - Found = SurfNum; - } else { - Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces); + // Classify a heat-transfer surface into the appropriate SurfaceFilter lists + // (interior vs exterior, then by class: window/wall/floor/roof). + static void classifySurfaceFilter(EnergyPlusData &state, int SurfNum, DataSurfaces::SurfaceClass surfClass, bool isWindow, bool isInterior) + { + using DataSurfaces::SurfaceFilter; + auto &filterLists = state.dataSurface->SurfaceFilterLists; + + // Pick the correct set of filter enums based on interior vs exterior + SurfaceFilter const allSurfaces = isInterior ? SurfaceFilter::AllInteriorSurfaces : SurfaceFilter::AllExteriorSurfaces; + SurfaceFilter const allWindows = isInterior ? SurfaceFilter::AllInteriorWindows : SurfaceFilter::AllExteriorWindows; + SurfaceFilter const allWalls = isInterior ? SurfaceFilter::AllInteriorWalls : SurfaceFilter::AllExteriorWalls; + SurfaceFilter const allFloors = isInterior ? SurfaceFilter::AllInteriorFloors : SurfaceFilter::AllExteriorFloors; + SurfaceFilter const allRoofs = isInterior ? SurfaceFilter::AllInteriorRoofs : SurfaceFilter::AllExteriorRoofs; + + filterLists[static_cast(allSurfaces)].push_back(SurfNum); + if (isWindow) { + filterLists[static_cast(allWindows)].push_back(SurfNum); + } else if (surfClass == DataSurfaces::SurfaceClass::Wall) { + filterLists[static_cast(allWalls)].push_back(SurfNum); + } else if (surfClass == DataSurfaces::SurfaceClass::Floor) { + filterLists[static_cast(allFloors)].push_back(SurfNum); + } else if (surfClass == DataSurfaces::SurfaceClass::Roof) { + filterLists[static_cast(allRoofs)].push_back(SurfNum); + filterLists[static_cast(SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum); + } + } + + // Build the various heat-transfer, window, non-window, interzone, exterior-solar, + // obstruction, Kiva, and SurfaceFilter surface lists. Also set the IsShadowPossibleObstruction flag. + static void buildSurfaceLists(EnergyPlusData &state, bool ErrorsFound) + { + auto &s_surf = state.dataSurface; + + s_surf->AllHTSurfaceList.reserve(s_surf->TotSurfaces); + s_surf->AllExtSolarSurfaceList.reserve(s_surf->TotSurfaces); + s_surf->AllShadowPossObstrSurfaceList.reserve(s_surf->TotSurfaces); + s_surf->AllIZSurfaceList.reserve(s_surf->TotSurfaces); + s_surf->AllHTNonWindowSurfaceList.reserve(s_surf->TotSurfaces - s_surf->TotWindows); + s_surf->AllHTWindowSurfaceList.reserve(s_surf->TotWindows); + s_surf->AllExtSolWindowSurfaceList.reserve(s_surf->TotWindows); + s_surf->AllExtSolWinWithFrameSurfaceList.reserve(s_surf->TotWindows); + s_surf->AllHTKivaSurfaceList.reserve(s_surf->TotSurfaces); + + for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) { + auto &surf = s_surf->Surface(SurfNum); + surf.IsShadowPossibleObstruction = false; + if (surf.ExtSolar) { + s_surf->AllExtSolarSurfaceList.push_back(SurfNum); } - if (Found > 0) { - surfTemp.BaseSurf = Found; - if (SurfNum != Found) { // for subsurfaces - if (surfTemp.HeatTransSurf) { - ++state.dataSurfaceGeometry->SurfaceTmp(Found).NumSubSurfaces; - } - if (surfTemp.Class < SurfaceClass::Window || surfTemp.Class > SurfaceClass::TDD_Diffuser) { - if (surfTemp.Class == SurfaceClass::None) { - ShowSevereError(state, EnergyPlus::format("{}Invalid SubSurface detected, Surface={}", RoutineName, surfTemp.Name)); - } else { - ShowSevereError(state, - EnergyPlus::format("{}Invalid SubSurface detected, Surface={}, class={} invalid class for subsurface", - RoutineName, - surfTemp.Name, - state.dataSurfaceGeometry->BaseSurfCls(int(surfTemp.Class)))); - SurfError = true; + if (surf.HeatTransSurf) { + s_surf->AllHTSurfaceList.push_back(SurfNum); + int const zoneNum(surf.Zone); + auto &surfZone(state.dataHeatBal->Zone(zoneNum)); + surfZone.ZoneHTSurfaceList.push_back(SurfNum); + if (surf.Class == DataSurfaces::SurfaceClass::Window) { + s_surf->AllHTWindowSurfaceList.push_back(SurfNum); + surfZone.ZoneHTWindowSurfaceList.push_back(SurfNum); + if (surf.ExtSolar) { + s_surf->AllExtSolWindowSurfaceList.push_back(SurfNum); + if (surf.FrameDivider > 0) { + s_surf->AllExtSolWinWithFrameSurfaceList.push_back(SurfNum); } } + } else { + s_surf->AllHTNonWindowSurfaceList.push_back(SurfNum); + surfZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum); + } + int const surfExtBoundCond(surf.ExtBoundCond); + if ((surfExtBoundCond > 0) && (surfExtBoundCond != SurfNum)) { + s_surf->AllIZSurfaceList.push_back(SurfNum); + surfZone.ZoneIZSurfaceList.push_back(SurfNum); + auto &adjZone(state.dataHeatBal->Zone(s_surf->Surface(surfExtBoundCond).Zone)); + adjZone.ZoneHTSurfaceList.push_back(SurfNum); + adjZone.ZoneIZSurfaceList.push_back(SurfNum); + if (surf.Class == DataSurfaces::SurfaceClass::Window) { + adjZone.ZoneHTWindowSurfaceList.push_back(SurfNum); + } else { + adjZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum); + } } } - } // ...end of the Surface DO loop for finding BaseSurf - //********************************************************************************** - // The surfaces need to be hierarchical by space. Input is allowed to be in any order. In - // this section the surfaces are reordered into: - // All shadowing surfaces (if mirrored, Mir- surface follows immediately after original) - // Shading:Site - // Shading:Building - // Shading:space (and variants) - // For each space: - // Walls - // Floors - // Roofs/Ceilings - // Internal Mass - // Non-Window subsurfaces (including doors) - // Window subsurfaces (including TubularDaylightingDiffusers) - // TubularDaylightingDomes - // After reordering, MovedSurfs should equal TotSurfaces + // Exclude non-exterior heat transfer surfaces (but not OtherSideCondModeledExt = -4 CR7640) + if (surf.HeatTransSurf && surf.ExtBoundCond > 0) { + continue; + } + if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::Ground) { + continue; + } + if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::KivaFoundation) { + s_surf->AllHTKivaSurfaceList.push_back(SurfNum); + if (!ErrorsFound) { + state.dataSurfaceGeometry->kivaManager.foundationInputs[surf.OSCPtr].surfaces.push_back(SurfNum); + } + continue; + } + if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt) { + continue; + } + if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) { + continue; + } + if (surf.Class == SurfaceClass::Window || surf.Class == SurfaceClass::Door) { + continue; + } + if (surf.MirroredSurf) { + continue; + } + if (surf.IsAirBoundarySurf) { + continue; + } + + surf.IsShadowPossibleObstruction = true; + s_surf->AllShadowPossObstrSurfaceList.push_back(SurfNum); + } + + // Populate SurfaceFilter lists + for (int iSurfaceFilter = 1; iSurfaceFilter < static_cast(DataSurfaces::SurfaceFilter::Num); ++iSurfaceFilter) { + s_surf->SurfaceFilterLists[iSurfaceFilter].reserve(s_surf->TotSurfaces); + } + + for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) { + auto const &surf = s_surf->Surface(SurfNum); + if (!surf.HeatTransSurf) { + continue; + } + bool isWindow = state.dataConstruction->Construct(surf.Construction).TypeIsWindow; + bool isInterior = surf.ExtBoundCond > 0; + classifySurfaceFilter(state, SurfNum, surf.Class, isWindow, isInterior); + } + } + + void GetSurfaceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input + { + + // SUBROUTINE INFORMATION: + // AUTHOR Richard Liesen + // DATE WRITTEN November 1997 + // MODIFIED April 1999, Linda Lawrie + // Dec. 2000, FW (add "one-wall zone" checks) + // RE-ENGINEERED May 2000, Linda Lawrie (breakout surface type gets) + + // PURPOSE OF THIS SUBROUTINE: + // The purpose of this subroutine is to read in the surface information + // from the input data file and interpret and put in the derived type + + // METHODOLOGY EMPLOYED: + // The order of surfaces does not matter and the surfaces are resorted into + // the hierarchical order: + // All Shading Surfaces + // Airwalls for space x1 + // Base Surfaces for space x1 + // Opaque Subsurfaces for space x1 + // Window Subsurfaces for space x1 + // TDD Dome Surfaces for space x1 + // Airwalls for space x2 + // Base Surfaces for space x2 + // etc + // Pointers are set in the spaces (AllSurfaceFirst/Last, HTSurfaceFirst/Last, OpaqOrIntMassSurfaceFirst/Last, WindowSurfaceFirst/Last, + // OpaqOrWinSurfaceFirst/Last, TDDDomeFirst/Last) + + // REFERENCES: + // This routine manages getting the input for the following Objects: + // SurfaceGeometry + // Surface:Shading:Detached + // Surface:HeatTransfer + // Surface:HeatTransfer:Sub + // Surface:Shading:Attached + // Surface:InternalMass + + // Vertex input: + // N3 , \field Number of Surface Vertices -- Number of (X,Y,Z) groups in this surface + // \note currently limited 3 or 4, later? + // \min 3 + // \max 4 + // \memo vertices are given in SurfaceGeometry coordinates -- if relative, all surface coordinates + // \memo are "relative" to the Zone Origin. if WCS, then building and zone origins are used + // \memo for some internal calculations, but all coordinates are given in an "absolute" system. + // N4, \field Vertex 1 X-coordinate + // \units m + // \type real + // N5 , \field Vertex 1 Y-coordinate + // \units m + // \type real + // N6 , \field Vertex 1 Z-coordinate + // \units m + // \type real + // N7, \field Vertex 2 X-coordinate + // \units m + // \type real + // N8, \field Vertex 2 Y-coordinate + // \units m + // \type real + // N9, \field Vertex 2 Z-coordinate + // \units m + // \type real + // N10, \field Vertex 3 X-coordinate + // \units m + // \type real + // N11, \field Vertex 3 Y-coordinate + // \units m + // \type real + // N12, \field Vertex 3 Z-coordinate + // \units m + // \type real + // N13, \field Vertex 4 X-coordinate + // \units m + // \type real + // N14, \field Vertex 4 Y-coordinate + // \type real + // \units m + // N15; \field Vertex 4 Z-coordinate + // \units m + // \type real - // For reporting purposes, the legacy surface order is also saved in DataSurfaces::AllSurfaceListReportOrder: - // All shadowing surfaces (if mirrored, Mir- surface follows immediately after original) - // Shading:Site - // Shading:Building - // Shading:Zone (and variants) - // For each zone: - // Walls - // subsurfaces for each wall (windows, doors, in input order, not sorted) follow the base surface - // Floors - // subsurfaces for each floor (windows, doors, in input order, not sorted) follow the base surface - // Roofs/Ceilings - // subsurfaces for each roof/ceiling (windows, doors, in input order, not sorted) follow the base surface - // Internal Mass - // After reordering, MovedSurfs should equal TotSurfaces + // The vertices are stored in the surface derived type. + // +(1)-------------------------(4)+ + // | | + // | | + // | | + // +(2)-------------------------(3)+ + // The above diagram shows the actual coordinate points of a typical wall + // (you're on the outside looking toward the wall) as stored into + // Surface%Vertex(1:) - MovedSurfs = 0; - Array1D SurfaceTmpClassMoved; // Tmp class is moved - SurfaceTmpClassMoved.dimension(state.dataSurface->TotSurfaces, false); - state.dataSurface->AllSurfaceListReportOrder.reserve(state.dataSurface->TotSurfaces); + static constexpr std::string_view RoutineName = "GetSurfaceData: "; + using namespace Vectors; + using namespace DataErrorTracking; - CreateMissingSpaces(state, state.dataSurfaceGeometry->SurfaceTmp); + int MovedSurfs; // Number of Moved Surfaces (when sorting into hierarchical structure) + bool SurfError(false); // General Surface Error, causes fatal error at end of routine + // Simple Surfaces (Rectangular) + int LayNumOutside; // Outside material numbers for a shaded construction + // entries with two glazing systems + int NeedToAddSurfaces; // Surfaces that will be added due to "unentered" other zone surface + int NeedToAddSubSurfaces; // SubSurfaces that will be added due to "unentered" other zone surface + int CurNewSurf = 0; + Real64 SurfWorldAz; + Real64 SurfTilt; - // Old SurfNum to New SurfNum - // Old = order in state.dataSurfaceGeometry->SurfaceTmp - // New = order in state.dataSurface->Surface - EPVector oldToNewSurfNums; - oldToNewSurfNums.resize(state.dataSurface->TotSurfaces, -1); + bool subSurfaceError(false); + bool errFlag; - // Move all shading Surfaces to Front - for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { - auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); - if (surfTemp.Class != SurfaceClass::Detached_F && surfTemp.Class != SurfaceClass::Detached_B && surfTemp.Class != SurfaceClass::Shading) { - continue; - } + // Get the total number of surfaces to allocate derived type and for surface loops - // A shading surface - ++MovedSurfs; - // Store list of moved surface numbers in reporting order - state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); - SurfaceTmpClassMoved(SurfNum) = true; //'Moved' - state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum); - oldToNewSurfNums(SurfNum) = MovedSurfs; + if (state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag) { + return; } + state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag = true; - // For each zone - - for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) { - for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) { - // Group air boundary surfaces first within each space - for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { - auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); - if (SurfaceTmpClassMoved(SurfNum)) { - continue; - } - if (surfTemp.spaceNum != spaceNum) { - continue; - } - int constNum = surfTemp.Construction; - if (constNum == 0) { - continue; - } - if (!state.dataConstruction->Construct(constNum).TypeIsAirBoundary) { - continue; - } + GetGeometryParameters(state, ErrorsFound); - // An air boundary surface - surfTemp.IsAirBoundarySurf = true; - ++MovedSurfs; - state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); - // If base Surface Type (Wall, Floor, Roof/Ceiling) - if ((surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(1)) || - (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(2)) || - (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(3))) { - // Store list of moved surface numbers in reporting order. We use the old position, we'll reconcile later - // We don't do it for Air Door/Air Windows yet, we want them listed below each base surf they belong to - state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum); - } - oldToNewSurfNums(SurfNum) = MovedSurfs; - SurfaceTmpClassMoved(SurfNum) = true; //'Moved' + if (state.dataSurface->WorldCoordSystem && !state.dataSurfaceGeometry->WarningDisplayed) { + bool RelWarning = (state.dataHeatBal->BuildingAzimuth != 0.0); + for (int ZoneNum = 1; !RelWarning && ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) { + auto const &zone = state.dataHeatBal->Zone(ZoneNum); + if (zone.RelNorth != 0.0 || zone.OriginX != 0.0 || zone.OriginY != 0.0 || zone.OriginZ != 0.0) { + RelWarning = true; } + } + if (RelWarning) { + ShowWarningError( + state, + EnergyPlus::format( + "{}World Coordinate System selected. Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.", + RoutineName)); + ShowContinueError(state, + "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs."); + state.dataSurfaceGeometry->WarningDisplayed = true; + } + } - // For each Base Surface Type (Wall, Floor, Roof/Ceiling) - put these first - - for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) { + int TotDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site:Detailed"); + int TotDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building:Detailed"); + int TotRectDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site"); + int TotRectDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building"); + int TotHTSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "BuildingSurface:Detailed"); + int TotDetailedWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Detailed"); + int TotDetailedRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RoofCeiling:Detailed"); + int TotDetailedFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Detailed"); + int TotHTSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "FenestrationSurface:Detailed"); + int TotShdSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Zone:Detailed"); + int TotOverhangs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang"); + int TotOverhangsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang:Projection"); + int TotFins = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin"); + int TotFinsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin:Projection"); + int TotRectWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window"); + int TotRectDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door"); + int TotRectGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor"); + int TotRectIZWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window:Interzone"); + int TotRectIZDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door:Interzone"); + int TotRectIZGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor:Interzone"); + int TotRectExtWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Exterior"); + int TotRectIntWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Adiabatic"); + int TotRectIZWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Interzone"); + int TotRectUGWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Underground"); + int TotRectRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Roof"); + int TotRectCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Adiabatic"); + int TotRectIZCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Interzone"); + int TotRectGCFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:GroundContact"); + int TotRectIntFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Adiabatic"); + int TotRectIZFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Interzone"); - for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { - auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); + state.dataSurface->TotOSC = 0; - if (SurfaceTmpClassMoved(SurfNum)) { - continue; - } - if (surfTemp.Zone == 0) { - continue; - } + int TotIntMassSurfaces = GetNumIntMassSurfaces(state); - if (surfTemp.spaceNum != spaceNum) { - continue; - } - if (surfTemp.Class != Loop) { - continue; - } + state.dataSurface->TotSurfaces = (TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg) * 2 + TotHTSurfs + + TotHTSubs + TotShdSubs * 2 + TotIntMassSurfaces + TotOverhangs * 2 + TotOverhangsProjection * 2 + + TotFins * 4 + TotFinsProjection * 4 + TotDetailedWalls + TotDetailedRoofs + TotDetailedFloors + + TotRectWindows + TotRectDoors + TotRectGlazedDoors + TotRectIZWindows + TotRectIZDoors + + TotRectIZGlazedDoors + TotRectExtWalls + TotRectIntWalls + TotRectIZWalls + TotRectUGWalls + TotRectRoofs + + TotRectCeilings + TotRectIZCeilings + TotRectGCFloors + TotRectIntFloors + TotRectIZFloors; - ++MovedSurfs; - state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); - oldToNewSurfNums(SurfNum) = MovedSurfs; - SurfaceTmpClassMoved(SurfNum) = true; // 'Moved' - // Store list of moved surface numbers in order reporting order (subsurfaces follow their base surface) - state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum); + state.dataSurfaceGeometry->SurfaceTmp.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately + state.dataSurfaceGeometry->UniqueSurfaceNames.reserve(state.dataSurface->TotSurfaces); + // SurfaceTmp structure is allocated via derived type initialization. - // Find all subsurfaces to this surface - just to update Report them in order - for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) { - // Gotta avoid pushing myself again! - if (SubSurfNum == SurfNum) { - continue; - } - // We don't check if already moved, because we didn't add them to AllSurfaceListReportOrder above! - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Zone == 0) { - continue; - } - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).BaseSurf != SurfNum) { - continue; - } - // Add original sub-surface numbers as placeholders in surface list for reporting - state.dataSurface->AllSurfaceListReportOrder.push_back(SubSurfNum); - } - } - } + int NumSurfs = 0; + int AddedSubSurfaces = 0; + state.dataErrTracking->AskForSurfacesReport = true; - // Internal mass goes next - for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { - if (SurfaceTmpClassMoved(SurfNum)) { - continue; - } + GetDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotDetachedFixed, TotDetachedBldg); - auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); - if (surfTemp.spaceNum != spaceNum) { - continue; - } - if (surfTemp.Class != SurfaceClass::IntMass) { - continue; - } - ++MovedSurfs; - state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); - oldToNewSurfNums(SurfNum) = MovedSurfs; - SurfaceTmpClassMoved(SurfNum) = true; // 'Moved' - // Store list of moved surface numbers in reporting order - state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum); - } + GetRectDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotRectDetachedFixed, TotRectDetachedBldg); - // Opaque door goes next - for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) { + GetHTSurfaceData(state, + ErrorsFound, + NumSurfs, + TotHTSurfs, + TotDetailedWalls, + TotDetailedRoofs, + TotDetailedFloors, + state.dataSurfaceGeometry->BaseSurfCls, + state.dataSurfaceGeometry->BaseSurfIDs, + NeedToAddSurfaces); - if (SurfaceTmpClassMoved(SubSurfNum)) { - continue; - } - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) { - continue; - } - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Door) { - continue; - } + GetRectSurfaces(state, + ErrorsFound, + NumSurfs, + TotRectExtWalls, + TotRectIntWalls, + TotRectIZWalls, + TotRectUGWalls, + TotRectRoofs, + TotRectCeilings, + TotRectIZCeilings, + TotRectGCFloors, + TotRectIntFloors, + TotRectIZFloors, + state.dataSurfaceGeometry->BaseSurfIDs, + NeedToAddSurfaces); - ++MovedSurfs; - state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum); - oldToNewSurfNums(SubSurfNum) = MovedSurfs; - SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved' - } + GetHTSubSurfaceData(state, + ErrorsFound, + NumSurfs, + TotHTSubs, + state.dataSurfaceGeometry->SubSurfCls, + state.dataSurfaceGeometry->SubSurfIDs, + AddedSubSurfaces, + NeedToAddSubSurfaces); - // The exterior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next - for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) { + GetRectSubSurfaces(state, + ErrorsFound, + NumSurfs, + TotRectWindows, + TotRectDoors, + TotRectGlazedDoors, + TotRectIZWindows, + TotRectIZDoors, + TotRectIZGlazedDoors, + state.dataSurfaceGeometry->SubSurfIDs, + AddedSubSurfaces, + NeedToAddSubSurfaces); - if (SurfaceTmpClassMoved(SubSurfNum)) { - continue; - } - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) { - continue; - } - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond > 0) { - continue; // Exterior window - } - if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) && - (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor)) { - continue; - } + GetAttShdSurfaceData(state, ErrorsFound, NumSurfs, TotShdSubs); - ++MovedSurfs; - state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum); - oldToNewSurfNums(SubSurfNum) = MovedSurfs; - SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved' - } + GetSimpleShdSurfaceData(state, ErrorsFound, NumSurfs, TotOverhangs, TotOverhangsProjection, TotFins, TotFinsProjection); - // The interior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next - for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) { + GetIntMassSurfaceData(state, ErrorsFound, NumSurfs); - if (SurfaceTmpClassMoved(SubSurfNum)) { - continue; - } - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) { - continue; - } - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond <= 0) { - continue; - } - if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) && - (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor)) { - continue; - } + state.dataSurface->TotSurfaces = NumSurfs + AddedSubSurfaces + NeedToAddSurfaces + NeedToAddSubSurfaces; - ++MovedSurfs; - state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum); - oldToNewSurfNums(SubSurfNum) = MovedSurfs; - SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved' - } + if (ErrorsFound) { + ShowFatalError(state, EnergyPlus::format("{}Errors discovered, program terminates.", RoutineName)); + } - // The SurfaceClass::TDD_Diffuser (OriginalClass = Window) goes next - for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) { + state.dataSurface->Surface.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately + state.dataSurface->SurfaceWindow.allocate(state.dataSurface->TotSurfaces); + state.dataSurface->surfShades.allocate(state.dataSurface->TotSurfaces); + AllocateSurfaceArrays(state); + AllocateSurfaceWindows(state, state.dataSurface->TotSurfaces); - if (SurfaceTmpClassMoved(SubSurfNum)) { - continue; - } - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) { - continue; - } - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Diffuser) { - continue; - } + // Have to make room for added surfaces, if needed + int FirstTotalSurfaces = NumSurfs + AddedSubSurfaces; + if (NeedToAddSurfaces + NeedToAddSubSurfaces > 0) { + state.dataSurfaceGeometry->SurfaceTmp.redimension(state.dataSurface->TotSurfaces); + CurNewSurf = FirstTotalSurfaces; + } - ++MovedSurfs; - state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum); - oldToNewSurfNums(SubSurfNum) = MovedSurfs; - SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved' + // add the "need to add" surfaces + // Debug write(outputfiledebug,*) ' need to add ',NeedtoAddSurfaces+NeedToAddSubSurfaces + for (int SurfNum = 1; SurfNum <= FirstTotalSurfaces; ++SurfNum) { + auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); + if ((surfTemp.ExtBoundCond != unenteredAdjacentZoneSurface) && (surfTemp.ExtBoundCond != unenteredAdjacentSpaceSurface)) { + continue; + } + // Need to add surface + ++CurNewSurf; + // Debug write(outputfiledebug,*) ' adding surface=',curnewsurf + auto &newSurf = state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf); + newSurf = surfTemp; + // Basic parameters are the same for both surfaces. + if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) { + int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones); + if (Found == 0) { + continue; } + newSurf.Zone = Found; + auto &newZone = state.dataHeatBal->Zone(Found); + newSurf.ZoneName = newZone.Name; + assert(!newZone.spaceIndexes.empty()); + newSurf.spaceNum = 0; // clear this here and set later + } else if (surfTemp.ExtBoundCond == unenteredAdjacentSpaceSurface) { + int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->space, state.dataGlobal->numSpaces); + if (Found == 0) { + continue; + } + newSurf.spaceNum = Found; + int zoneNum = state.dataHeatBal->space(Found).zoneNum; + newSurf.Zone = zoneNum; + newSurf.ZoneName = state.dataHeatBal->Zone(zoneNum).Name; + } + // Reverse Construction + newSurf.Construction = DataHeatBalance::AssignReverseConstructionNumber(state, surfTemp.Construction, SurfError); + newSurf.ConstructionStoredInputValue = newSurf.Construction; + // Reverse Vertices + int NVert = surfTemp.Sides; + for (int Vert = 1; Vert <= surfTemp.Sides; ++Vert) { + newSurf.Vertex(Vert) = surfTemp.Vertex(NVert); + --NVert; + } + if (newSurf.Sides > 2) { + Vectors::CreateNewellAreaVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellAreaVector); + newSurf.GrossArea = Vectors::VecLength(newSurf.NewellAreaVector); + newSurf.Area = newSurf.GrossArea; + newSurf.NetAreaShadowCalc = newSurf.Area; + Vectors::CreateNewellSurfaceNormalVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellSurfaceNormalVector); + Vectors::DetermineAzimuthAndTilt( + newSurf.Vertex, SurfWorldAz, SurfTilt, newSurf.lcsx, newSurf.lcsy, newSurf.lcsz, newSurf.NewellSurfaceNormalVector); + newSurf.Azimuth = SurfWorldAz; + newSurf.Tilt = SurfTilt; + newSurf.convOrientation = Convect::GetSurfConvOrientation(newSurf.Tilt); - // Last but not least, SurfaceClass::TDD_Dome - for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) { - - if (SurfaceTmpClassMoved(SubSurfNum)) { - continue; + // Sine and cosine of azimuth and tilt + newSurf.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad); + newSurf.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad); + newSurf.SinTilt = std::sin(SurfTilt * Constant::DegToRad); + newSurf.CosTilt = std::cos(SurfTilt * Constant::DegToRad); + // Outward normal unit vector (pointing away from room) + newSurf.OutNormVec = newSurf.NewellSurfaceNormalVector; + for (int n = 1; n <= 3; ++n) { + if (std::abs(newSurf.OutNormVec(n) - 1.0) < 1.e-06) { + newSurf.OutNormVec(n) = +1.0; } - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) { - continue; + if (std::abs(newSurf.OutNormVec(n) + 1.0) < 1.e-06) { + newSurf.OutNormVec(n) = -1.0; } - if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Dome) { - continue; + if (std::abs(newSurf.OutNormVec(n)) < 1.e-06) { + newSurf.OutNormVec(n) = 0.0; } - - ++MovedSurfs; - state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum); - oldToNewSurfNums(SubSurfNum) = MovedSurfs; - SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved' } - } - } - // Validity checking - assert(state.dataSurface->TotSurfaces == MovedSurfs); - assert(state.dataSurface->TotSurfaces == static_cast(state.dataSurface->AllSurfaceListReportOrder.size())); - assert(state.dataSurface->TotSurfaces == static_cast(oldToNewSurfNums.size())); - - // Assert validity of indices - assert(std::find_if(state.dataSurface->AllSurfaceListReportOrder.cbegin(), state.dataSurface->AllSurfaceListReportOrder.cend(), [](int i) { - return i < 1; - }) == state.dataSurface->AllSurfaceListReportOrder.cend()); + // Can perform tests on this surface here + newSurf.ViewFactorSky = 0.5 * (1.0 + newSurf.CosTilt); + newSurf.ViewFactorGround = 0.5 * (1.0 - newSurf.CosTilt); - assert(std::find_if(oldToNewSurfNums.cbegin(), oldToNewSurfNums.cend(), [](int i) { return i < 1; }) == oldToNewSurfNums.cend()); + // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing + // surfaces + newSurf.ViewFactorSkyIR = newSurf.ViewFactorSky; + newSurf.ViewFactorGroundIR = 0.5 * (1.0 - newSurf.CosTilt); + } - if (MovedSurfs != state.dataSurface->TotSurfaces) { - ShowSevereError( - state, - EnergyPlus::format( - "{}Reordered # of Surfaces ({}) not = Total # of Surfaces ({})", RoutineName, MovedSurfs, state.dataSurface->TotSurfaces)); - SurfError = true; - for (int Loop = 1; Loop <= state.dataSurface->TotSurfaces; ++Loop) { - if (!SurfaceTmpClassMoved(Loop) && state.dataSurfaceGeometry->SurfaceTmp(Loop).Class == SurfaceClass::Invalid) { - ShowSevereError(state, - EnergyPlus::format("{}Error in Surface= \"{} indicated Zone=\"{}\"", - RoutineName, - state.dataSurfaceGeometry->SurfaceTmp(Loop).Name, - state.dataSurfaceGeometry->SurfaceTmp(Loop).ZoneName)); + // Change Name + newSurf.Name = "iz-" + surfTemp.Name; + // Debug write(outputfiledebug,*) ' new surf name=',TRIM(SurfaceTmp(CurNewSurf)%Name) + // Debug write(outputfiledebug,*) ' new surf in zone=',TRIM(surfacetmp(curnewsurf)%zoneName) + newSurf.ExtBoundCond = unreconciledZoneSurface; + surfTemp.ExtBoundCond = unreconciledZoneSurface; + newSurf.ExtBoundCondName = surfTemp.Name; + surfTemp.ExtBoundCondName = newSurf.Name; + if (newSurf.Class == SurfaceClass::Roof || newSurf.Class == SurfaceClass::Wall || newSurf.Class == SurfaceClass::Floor) { + // base surface + if (surfTemp.Class == SurfaceClass::Roof) { + newSurf.Class = SurfaceClass::Floor; + // Debug write(outputfiledebug,*) ' new surfaces is a floor' + } else if (surfTemp.Class == SurfaceClass::Floor) { + newSurf.Class = SurfaceClass::Roof; + // Debug write(outputfiledebug,*) ' new surfaces is a roof' + } + newSurf.BaseSurf = CurNewSurf; + newSurf.BaseSurfName = newSurf.Name; + // Debug write(outputfiledebug,*) ' basesurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName) + } else { + // subsurface + int Found = + Util::FindItemInList("iz-" + surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, FirstTotalSurfaces + CurNewSurf - 1); + if (Found > 0) { + newSurf.BaseSurfName = "iz-" + surfTemp.BaseSurfName; + newSurf.BaseSurf = Found; + auto &foundBaseSurf = state.dataSurfaceGeometry->SurfaceTmp(Found); + foundBaseSurf.Area -= newSurf.Area; + if (newSurf.Class == SurfaceClass::Window || newSurf.Class == SurfaceClass::GlassDoor) { + foundBaseSurf.NetAreaShadowCalc -= newSurf.Area / newSurf.Multiplier; + } else { // Door, TDD:Diffuser, TDD:DOME + foundBaseSurf.NetAreaShadowCalc -= newSurf.Area; + } + newSurf.ExtBoundCond = foundBaseSurf.ExtBoundCond; + newSurf.ExtBoundCondName = surfTemp.Name; + newSurf.ExtSolar = foundBaseSurf.ExtSolar; + newSurf.ExtWind = foundBaseSurf.ExtWind; + newSurf.Zone = foundBaseSurf.Zone; + newSurf.ZoneName = foundBaseSurf.ZoneName; + newSurf.spaceNum = foundBaseSurf.spaceNum; + newSurf.OSCPtr = foundBaseSurf.OSCPtr; + // Debug write(outputfiledebug,*) ' subsurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName) + // Debug write(outputfiledebug,*) ' subsurf, basesurf=',TRIM('iz-'//SurfaceTmp(SurfNum)%BaseSurfName) + } else { + ShowSevereError( + state, + EnergyPlus::format("{}Adding unentered subsurface, could not find base surface=iz-{}", RoutineName, surfTemp.BaseSurfName)); + SurfError = true; } } - ShowWarningError( - state, - EnergyPlus::format("{}Remaining surface checks will use \"reordered number of surfaces\", not number of original surfaces", - RoutineName)); } - - // Realign the relationship: surface to base surface + //********************************************************************************** + // After all of the surfaces have been defined then the base surfaces for the + // sub-surfaces can be defined. Loop through surfaces and match with the sub-surface + // names. for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { - auto &movedSurf = state.dataSurface->Surface(SurfNum); - if (movedSurf.BaseSurf > 0) { - int newBaseSurfNum = oldToNewSurfNums(movedSurf.BaseSurf); - movedSurf.BaseSurf = newBaseSurfNum; + auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); + if (!surfTemp.HeatTransSurf) { + continue; + } - if (newBaseSurfNum < 1) { - ShowFatalError(state, - EnergyPlus::format( - "{}Couldn't find the new Surface Number for surface index {} named '{}'. Looking for BaseSurf old index of {}", - RoutineName, - SurfNum, - movedSurf.Name, - movedSurf.BaseSurf)); + int Found = 0; + // why are we doing this again? this should have already been done. + if (Util::SameString(surfTemp.BaseSurfName, surfTemp.Name)) { + Found = SurfNum; + } else { + Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces); + } + if (Found > 0) { + surfTemp.BaseSurf = Found; + if (SurfNum != Found) { // for subsurfaces + if (surfTemp.HeatTransSurf) { + ++state.dataSurfaceGeometry->SurfaceTmp(Found).NumSubSurfaces; + } + if (surfTemp.Class < SurfaceClass::Window || surfTemp.Class > SurfaceClass::TDD_Diffuser) { + if (surfTemp.Class == SurfaceClass::None) { + ShowSevereError(state, EnergyPlus::format("{}Invalid SubSurface detected, Surface={}", RoutineName, surfTemp.Name)); + } else { + ShowSevereError(state, + EnergyPlus::format("{}Invalid SubSurface detected, Surface={}, class={} invalid class for subsurface", + RoutineName, + surfTemp.Name, + state.dataSurfaceGeometry->BaseSurfCls(int(surfTemp.Class)))); + SurfError = true; + } + } } } - auto &reportOrderNum = state.dataSurface->AllSurfaceListReportOrder[SurfNum - 1]; - if (reportOrderNum > 0) { - int newReportOrderNum = oldToNewSurfNums(reportOrderNum); - reportOrderNum = newReportOrderNum; - } - } - state.dataSurfaceGeometry->SurfaceTmp.deallocate(); // DeAllocate the Temp Surface derived type + } // ...end of the Surface DO loop for finding BaseSurf + //********************************************************************************** + // The surfaces need to be hierarchical by space. Input is allowed to be in any order. In + // this section the surfaces are reordered into: + // All shadowing surfaces (if mirrored, Mir- surface follows immediately after original) + // Shading:Site + // Shading:Building + // Shading:space (and variants) + // For each space: + // Walls + // Floors + // Roofs/Ceilings + // Internal Mass + // Non-Window subsurfaces (including doors) + // Window subsurfaces (including TubularDaylightingDiffusers) + // TubularDaylightingDomes + // After reordering, MovedSurfs should equal TotSurfaces - createSpaceSurfaceLists(state); + // For reporting purposes, the legacy surface order is also saved in DataSurfaces::AllSurfaceListReportOrder: + // All shadowing surfaces (if mirrored, Mir- surface follows immediately after original) + // Shading:Site + // Shading:Building + // Shading:Zone (and variants) + // For each zone: + // Walls + // subsurfaces for each wall (windows, doors, in input order, not sorted) follow the base surface + // Floors + // subsurfaces for each floor (windows, doors, in input order, not sorted) follow the base surface + // Roofs/Ceilings + // subsurfaces for each roof/ceiling (windows, doors, in input order, not sorted) follow the base surface + // Internal Mass + // After reordering, MovedSurfs should equal TotSurfaces - // For each Base Surface Type (Wall, Floor, Roof) + MovedSurfs = 0; + Array1D SurfaceTmpClassMoved; // Tmp class is moved + SurfaceTmpClassMoved.dimension(state.dataSurface->TotSurfaces, false); + state.dataSurface->AllSurfaceListReportOrder.reserve(state.dataSurface->TotSurfaces); - for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) { - for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { + CreateMissingSpaces(state, state.dataSurfaceGeometry->SurfaceTmp); - if (state.dataSurface->Surface(SurfNum).Zone == 0) { - continue; - } + // Old SurfNum to New SurfNum + // Old = order in state.dataSurfaceGeometry->SurfaceTmp + // New = order in state.dataSurface->Surface + EPVector oldToNewSurfNums; + oldToNewSurfNums.resize(state.dataSurface->TotSurfaces, -1); - if (state.dataSurface->Surface(SurfNum).Class != Loop) { - continue; - } + // Move all shading Surfaces to Front + for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { + auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); + if (surfTemp.Class != SurfaceClass::Detached_F && surfTemp.Class != SurfaceClass::Detached_B && surfTemp.Class != SurfaceClass::Shading) { + continue; + } - // Find all subsurfaces to this surface - for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) { + // A shading surface + ++MovedSurfs; + // Store list of moved surface numbers in reporting order + state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); + SurfaceTmpClassMoved(SurfNum) = true; //'Moved' + state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum); + oldToNewSurfNums(SurfNum) = MovedSurfs; + } - if (SurfNum == SubSurfNum) { - continue; - } - if (state.dataSurface->Surface(SubSurfNum).Zone == 0) { + // For each zone + + for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) { + for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) { + // Group air boundary surfaces first within each space + for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { + auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); + if (SurfaceTmpClassMoved(SurfNum)) { continue; } - if (state.dataSurface->Surface(SubSurfNum).BaseSurf != SurfNum) { + if (surfTemp.spaceNum != spaceNum) { continue; - } - - // Check facing angle of Sub compared to base - checkSubSurfAzTiltNorm(state, state.dataSurface->Surface(SurfNum), state.dataSurface->Surface(SubSurfNum), subSurfaceError); - if (subSurfaceError) { - SurfError = true; - } - } - } - } - - //********************************************************************************** - // Now, match up interzone surfaces - NonMatch = false; - izConstDiffMsg = false; - for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces - // Clean up Shading Surfaces, make sure they don't go through here. - if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) { - continue; - } - // If other surface, match it up - // Both interzone and "internal" surfaces have this pointer set - // Internal surfaces point to themselves, Interzone to another - if (state.dataSurface->Surface(SurfNum).ExtBoundCond == unreconciledZoneSurface) { - if (not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) { - int Found = 0; - if (state.dataSurface->Surface(SurfNum).ExtBoundCondName == state.dataSurface->Surface(SurfNum).Name) { - Found = SurfNum; - } else { - Found = Util::FindItemInList(state.dataSurface->Surface(SurfNum).ExtBoundCondName, state.dataSurface->Surface, MovedSurfs); - } - if (Found != 0) { - state.dataSurface->Surface(SurfNum).ExtBoundCond = Found; - // Check that matching surface is also "OtherZoneSurface" - if (state.dataSurface->Surface(Found).ExtBoundCond <= 0 && - state.dataSurface->Surface(Found).ExtBoundCond != unreconciledZoneSurface) { - ShowSevereError(state, EnergyPlus::format("{}Potential \"OtherZoneSurface\" is not matched correctly:", RoutineName)); - - ShowContinueError(state, - EnergyPlus::format("Surface={}, Zone={}", - state.dataSurface->Surface(SurfNum).Name, - state.dataSurface->Surface(SurfNum).ZoneName)); - ShowContinueError(state, - EnergyPlus::format("Nonmatched Other/InterZone Surface={}, Zone={}", - state.dataSurface->Surface(Found).Name, - state.dataSurface->Surface(Found).ZoneName)); - SurfError = true; - } - // Check that matching interzone surface has construction with reversed layers - if (Found != SurfNum) { // Interzone surface - // Make sure different zones too (CR 4110) - if (state.dataSurface->Surface(SurfNum).spaceNum == state.dataSurface->Surface(Found).spaceNum) { - ++state.dataSurfaceGeometry->ErrCount2; - if (state.dataSurfaceGeometry->ErrCount2 == 1 && !state.dataGlobal->DisplayExtraWarnings) { - ShowWarningError( - state, - EnergyPlus::format("{}CAUTION -- Interspace surfaces are occurring in the same space(s).", RoutineName)); - ShowContinueError( - state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual occurrences."); - } - if (state.dataGlobal->DisplayExtraWarnings) { - ShowWarningError( - state, EnergyPlus::format("{}CAUTION -- Interspace surfaces are usually in different spaces", RoutineName)); - ShowContinueError(state, - EnergyPlus::format("Surface={}, Space={}, Zone={}", - state.dataSurface->Surface(SurfNum).Name, - state.dataHeatBal->space(state.dataSurface->Surface(SurfNum).spaceNum).Name, - state.dataSurface->Surface(SurfNum).ZoneName)); - ShowContinueError(state, - EnergyPlus::format("Surface={}, Space={}, Zone={}", - state.dataSurface->Surface(Found).Name, - state.dataHeatBal->space(state.dataSurface->Surface(Found).spaceNum).Name, - state.dataSurface->Surface(Found).ZoneName)); - } - } - int ConstrNum = state.dataSurface->Surface(SurfNum).Construction; - int ConstrNumFound = state.dataSurface->Surface(Found).Construction; - if (ConstrNum <= 0 || ConstrNumFound <= 0) { - continue; - } - if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning && - state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning) { - continue; - } - if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning && - state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) { - continue; - } - TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers; - TotLayFound = state.dataConstruction->Construct(ConstrNumFound).TotLayers; - if (TotLay != TotLayFound) { // Different number of layers - // match on like Uvalues (nominal) - if (std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) { - ShowSevereError( - state, - EnergyPlus::format("{}Construction {} of interzone surface {} does not have the same number of layers as the " - "construction {} of adjacent surface {}", - RoutineName, - state.dataConstruction->Construct(ConstrNum).Name, - state.dataSurface->Surface(SurfNum).Name, - state.dataConstruction->Construct(ConstrNumFound).Name, - state.dataSurface->Surface(Found).Name)); - if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning || - !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning) { - ShowContinueError(state, "...this problem for this pair will not be reported again."); - state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning = true; - state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning = true; - } - SurfError = true; - } - } else { // Same number of layers; check for reverse layers - // check layers as number of layers is the same - izConstDiff = false; - // ok if same nominal U - CheckForReversedLayers(state, izConstDiff, ConstrNum, ConstrNumFound, TotLay); - if (izConstDiff && - std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) { - ShowSevereError( - state, - EnergyPlus::format("{}Construction {} of interzone surface {} does not have the same materials in the " - "reverse order as the construction {} of adjacent surface {}", - RoutineName, - state.dataConstruction->Construct(ConstrNum).Name, - state.dataSurface->Surface(SurfNum).Name, - state.dataConstruction->Construct(ConstrNumFound).Name, - state.dataSurface->Surface(Found).Name)); - ShowContinueError(state, - "or the properties of the reversed layers are not correct due to differing layer front and " - "back side values"); - if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning || - !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) { - ShowContinueError(state, "...this problem for this pair will not be reported again."); - state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true; - state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true; - } - SurfError = true; - } else if (izConstDiff) { - ShowWarningError( - state, - EnergyPlus::format("{}Construction {} of interzone surface {} does not have the same materials in the " - "reverse order as the construction {} of adjacent surface {}", - RoutineName, - state.dataConstruction->Construct(ConstrNum).Name, - state.dataSurface->Surface(SurfNum).Name, - state.dataConstruction->Construct(ConstrNumFound).Name, - state.dataSurface->Surface(Found).Name)); - ShowContinueError(state, - "or the properties of the reversed layers are not correct due to differing layer front and " - "back side values"); - ShowContinueError( - state, - EnergyPlus::format( - "...but Nominal U values are similar, diff=[{:.4R}] ... simulation proceeds.", - std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)))); - if (!izConstDiffMsg) { - ShowContinueError(state, - "...if the two zones are expected to have significantly different temperatures, the proper " - "\"reverse\" construction should be created."); - izConstDiffMsg = true; - } - if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning || - !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) { - ShowContinueError(state, "...this problem for this pair will not be reported again."); - state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true; - state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true; - } - } - } + } + int constNum = surfTemp.Construction; + if (constNum == 0) { + continue; + } + if (!state.dataConstruction->Construct(constNum).TypeIsAirBoundary) { + continue; + } - // If significantly different areas -- this would not be good - MultFound = state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).Multiplier * - state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).ListMultiplier; - MultSurfNum = state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).Multiplier * - state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).ListMultiplier; - if (state.dataSurface->Surface(Found).Area > 0.0) { - if (std::abs((state.dataSurface->Surface(Found).Area * MultFound - - state.dataSurface->Surface(SurfNum).Area * MultSurfNum) / - state.dataSurface->Surface(Found).Area * MultFound) > 0.02) { // 2% difference in areas - ++state.dataSurfaceGeometry->ErrCount4; - if (state.dataSurfaceGeometry->ErrCount4 == 1 && !state.dataGlobal->DisplayExtraWarnings) { - ShowWarningError( - state, - EnergyPlus::format( - "{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:", - RoutineName)); - ShowContinueError( - state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual mismatches."); - } - if (state.dataGlobal->DisplayExtraWarnings) { - ShowWarningError( - state, - EnergyPlus::format( - "{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:", - RoutineName)); + // An air boundary surface + surfTemp.IsAirBoundarySurf = true; + ++MovedSurfs; + state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); + // If base Surface Type (Wall, Floor, Roof/Ceiling) + if ((surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(1)) || + (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(2)) || + (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(3))) { + // Store list of moved surface numbers in reporting order. We use the old position, we'll reconcile later + // We don't do it for Air Door/Air Windows yet, we want them listed below each base surf they belong to + state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum); + } + oldToNewSurfNums(SurfNum) = MovedSurfs; + SurfaceTmpClassMoved(SurfNum) = true; //'Moved' + } - if (MultFound == 1 && MultSurfNum == 1) { - ShowContinueError(state, - EnergyPlus::format(" Area={:.1T} in Surface={}, Zone={}", - state.dataSurface->Surface(SurfNum).Area, - state.dataSurface->Surface(SurfNum).Name, - state.dataSurface->Surface(SurfNum).ZoneName)); - ShowContinueError(state, - EnergyPlus::format(" Area={:.1T} in Surface={}, Zone={}", - state.dataSurface->Surface(Found).Area, - state.dataSurface->Surface(Found).Name, - state.dataSurface->Surface(Found).ZoneName)); - } else { // Show multiplier info - ShowContinueError( - state, - EnergyPlus::format(" Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}", - state.dataSurface->Surface(SurfNum).Area, - MultSurfNum, - state.dataSurface->Surface(SurfNum).Area * MultSurfNum, - state.dataSurface->Surface(SurfNum).Name, - state.dataSurface->Surface(SurfNum).ZoneName)); + // For each Base Surface Type (Wall, Floor, Roof/Ceiling) - put these first - ShowContinueError( - state, - EnergyPlus::format(" Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}", - state.dataSurface->Surface(Found).Area, - MultFound, - state.dataSurface->Surface(Found).Area * MultFound, - state.dataSurface->Surface(Found).Name, - state.dataSurface->Surface(Found).ZoneName)); - } - } - } - } - // Check opposites Azimuth and Tilt - // Tilt - if (std::abs(std::abs(state.dataSurface->Surface(Found).Tilt + state.dataSurface->Surface(SurfNum).Tilt) - 180.0) > 1.0) { - ShowWarningError(state, EnergyPlus::format("{}InterZone Surface Tilts do not match as expected.", RoutineName)); - ShowContinueError(state, - EnergyPlus::format(" Tilt={:.1T} in Surface={}, Zone={}", - state.dataSurface->Surface(SurfNum).Tilt, - state.dataSurface->Surface(SurfNum).Name, - state.dataSurface->Surface(SurfNum).ZoneName)); - ShowContinueError(state, - EnergyPlus::format(" Tilt={:.1T} in Surface={}, Zone={}", - state.dataSurface->Surface(Found).Tilt, - state.dataSurface->Surface(Found).Name, - state.dataSurface->Surface(Found).ZoneName)); - } - // check surface class match. interzone surface. + for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) { - if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Wall && - state.dataSurface->Surface(Found).Class != SurfaceClass::Wall) || - (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall && - state.dataSurface->Surface(Found).Class == SurfaceClass::Wall)) { - ShowWarningError(state, EnergyPlus::format("{}InterZone Surface Classes do not match as expected.", RoutineName)); - ShowContinueError(state, - EnergyPlus::format("Surface=\"{}\", surface class={}", - state.dataSurface->Surface(SurfNum).Name, - cSurfaceClass(state.dataSurface->Surface(SurfNum).Class))); - ShowContinueError(state, - EnergyPlus::format("Adjacent Surface=\"{}\", surface class={}", - state.dataSurface->Surface(Found).Name, - cSurfaceClass(state.dataSurface->Surface(Found).Class))); - ShowContinueError(state, "Other errors/warnings may follow about these surfaces."); - } - if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Roof && - state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) || - (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof && - state.dataSurface->Surface(Found).Class == SurfaceClass::Floor)) { - ShowWarningError(state, EnergyPlus::format("{}InterZone Surface Classes do not match as expected.", RoutineName)); - ShowContinueError(state, - EnergyPlus::format("Surface=\"{}\", surface class={}", - state.dataSurface->Surface(SurfNum).Name, - cSurfaceClass(state.dataSurface->Surface(SurfNum).Class))); - ShowContinueError(state, - EnergyPlus::format("Adjacent Surface=\"{}\", surface class={}", - state.dataSurface->Surface(Found).Name, - cSurfaceClass(state.dataSurface->Surface(Found).Class))); - ShowContinueError(state, "Other errors/warnings may follow about these surfaces."); - } - if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof && - state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Floor) { - // Walls, Windows, Doors, Glass Doors - if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall) { - // Surface is a Door, Window or Glass Door - if (state.dataSurface->Surface(SurfNum).BaseSurf == 0) { - continue; // error detected elsewhere - } - if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Roof || - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Floor) { - continue; - } - } - if (std::abs(std::abs(state.dataSurface->Surface(SurfNum).Azimuth - state.dataSurface->Surface(Found).Azimuth) - - 180.0) > 1.0) { - if (std::abs(state.dataSurface->Surface(SurfNum).SinTilt) > 0.5 || state.dataGlobal->DisplayExtraWarnings) { - // if horizontal surfaces, then these are windows/doors/etc in those items. - ShowWarningError(state, - EnergyPlus::format("{}InterZone Surface Azimuths do not match as expected.", RoutineName)); - ShowContinueError(state, - EnergyPlus::format(" Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}", - state.dataSurface->Surface(SurfNum).Azimuth, - state.dataSurface->Surface(SurfNum).Tilt, - state.dataSurface->Surface(SurfNum).Name, - state.dataSurface->Surface(SurfNum).ZoneName)); - ShowContinueError(state, - EnergyPlus::format(" Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}", - state.dataSurface->Surface(Found).Azimuth, - state.dataSurface->Surface(Found).Tilt, - state.dataSurface->Surface(Found).Name, - state.dataSurface->Surface(Found).ZoneName)); - ShowContinueError(state, - EnergyPlus::format("..surface class of first surface={}", - cSurfaceClass(state.dataSurface->Surface(SurfNum).Class))); - ShowContinueError(state, - EnergyPlus::format("..surface class of second surface={}", - cSurfaceClass(state.dataSurface->Surface(Found).Class))); - } - } - } + for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { + auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); - // Make sure exposures (Sun, Wind) are the same.....and are "not" - if (state.dataSurface->Surface(SurfNum).ExtSolar || state.dataSurface->Surface(Found).ExtSolar) { - ShowWarningError( - state, EnergyPlus::format("{}Interzone surfaces cannot be \"SunExposed\" -- removing SunExposed", RoutineName)); - ShowContinueError(state, - EnergyPlus::format(" Surface={}, Zone={}", - state.dataSurface->Surface(SurfNum).Name, - state.dataSurface->Surface(SurfNum).ZoneName)); - ShowContinueError(state, - EnergyPlus::format(" Surface={}, Zone={}", - state.dataSurface->Surface(Found).Name, - state.dataSurface->Surface(Found).ZoneName)); - state.dataSurface->Surface(SurfNum).ExtSolar = false; - state.dataSurface->Surface(Found).ExtSolar = false; - } - if (state.dataSurface->Surface(SurfNum).ExtWind || state.dataSurface->Surface(Found).ExtWind) { - ShowWarningError( - state, EnergyPlus::format("{}Interzone surfaces cannot be \"WindExposed\" -- removing WindExposed", RoutineName)); - ShowContinueError(state, - EnergyPlus::format(" Surface={}, Zone={}", - state.dataSurface->Surface(SurfNum).Name, - state.dataSurface->Surface(SurfNum).ZoneName)); - ShowContinueError(state, - EnergyPlus::format(" Surface={}, Zone={}", - state.dataSurface->Surface(Found).Name, - state.dataSurface->Surface(Found).ZoneName)); - state.dataSurface->Surface(SurfNum).ExtWind = false; - state.dataSurface->Surface(Found).ExtWind = false; - } + if (SurfaceTmpClassMoved(SurfNum)) { + continue; } - // Set opposing surface back to this one (regardless of error) - state.dataSurface->Surface(Found).ExtBoundCond = SurfNum; - // Check subsurfaces... make sure base surface is also an interzone surface - if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface - if ((state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) && - not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) { - // if not internal subsurface - if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond == - state.dataSurface->Surface(SurfNum).BaseSurf) { - // base surface is not interzone surface - ShowSevereError(state, - EnergyPlus::format("{}SubSurface=\"{}\" is an interzone subsurface.", - RoutineName, - state.dataSurface->Surface(SurfNum).Name)); - ShowContinueError( - state, - EnergyPlus::format("..but the Base Surface is not an interzone surface, Surface=\"{}\".", - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name)); - SurfError = true; - } - } + if (surfTemp.Zone == 0) { + continue; } - } else { - // Seems unlikely that an internal surface would be missing itself, so this message - // only indicates for adjacent (interzone) surfaces. - ShowSevereError(state, - EnergyPlus::format("{}Adjacent Surface not found: {} adjacent to surface {}", - RoutineName, - state.dataSurface->Surface(SurfNum).ExtBoundCondName, - state.dataSurface->Surface(SurfNum).Name)); - NonMatch = true; - SurfError = true; - } - } else if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface - if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0 && - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond != - state.dataSurface->Surface(SurfNum).BaseSurf) { // If Interzone surface, subsurface must be also. - ShowSevereError(state, EnergyPlus::format("{}SubSurface on Interzone Surface must be an Interzone SubSurface.", RoutineName)); - ShowContinueError( - state, EnergyPlus::format("...OutsideFaceEnvironment is blank, in Surface={}", state.dataSurface->Surface(SurfNum).Name)); - SurfError = true; - } else { - ++state.dataSurfaceGeometry->ErrCount3; - if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) { - ShowWarningError(state, EnergyPlus::format("{}Blank name for Outside Boundary Condition Objects.", RoutineName)); - ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces."); + + if (surfTemp.spaceNum != spaceNum) { + continue; } - if (state.dataGlobal->DisplayExtraWarnings) { - ShowWarningError(state, - EnergyPlus::format("{}Blank name for Outside Boundary Condition Object, in surface={}", - RoutineName, - state.dataSurface->Surface(SurfNum).Name)); - ShowContinueError(state, - EnergyPlus::format("Resetting this surface to be an internal zone surface, zone={}", - state.dataSurface->Surface(SurfNum).ZoneName)); + if (surfTemp.Class != Loop) { + continue; + } + + ++MovedSurfs; + state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); + oldToNewSurfNums(SurfNum) = MovedSurfs; + SurfaceTmpClassMoved(SurfNum) = true; // 'Moved' + // Store list of moved surface numbers in order reporting order (subsurfaces follow their base surface) + state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum); + + // Find all subsurfaces to this surface - just to update Report them in order + for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) { + // Gotta avoid pushing myself again! + if (SubSurfNum == SurfNum) { + continue; + } + // We don't check if already moved, because we didn't add them to AllSurfaceListReportOrder above! + if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Zone == 0) { + continue; + } + if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).BaseSurf != SurfNum) { + continue; + } + // Add original sub-surface numbers as placeholders in surface list for reporting + state.dataSurface->AllSurfaceListReportOrder.push_back(SubSurfNum); } - state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name; - state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum; - } - } else { - ++state.dataSurfaceGeometry->ErrCount3; - if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) { - ShowSevereError(state, EnergyPlus::format("{}Blank name for Outside Boundary Condition Objects.", RoutineName)); - ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces."); - } - if (state.dataGlobal->DisplayExtraWarnings) { - ShowWarningError(state, - EnergyPlus::format("{}Blank name for Outside Boundary Condition Object, in surface={}", - RoutineName, - state.dataSurface->Surface(SurfNum).Name)); - ShowContinueError(state, - EnergyPlus::format("Resetting this surface to be an internal zone (adiabatic) surface, zone={}", - state.dataSurface->Surface(SurfNum).ZoneName)); } - state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name; - state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum; - SurfError = true; } + + // Helper lambda: move all surfaces in this space that match a predicate, + // optionally adding them to the report-order list. + auto moveSurfacesMatching = [&](auto const &matchFn, bool addToReportOrder) { + for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { + if (SurfaceTmpClassMoved(SurfNum)) { + continue; + } + auto const &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); + if (surfTemp.spaceNum != spaceNum) { + continue; + } + if (!matchFn(surfTemp)) { + continue; + } + ++MovedSurfs; + state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum); + oldToNewSurfNums(SurfNum) = MovedSurfs; + SurfaceTmpClassMoved(SurfNum) = true; // 'Moved' + if (addToReportOrder) { + state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum); + } + } + }; + + // Internal mass goes next + moveSurfacesMatching([](auto const &s) { return s.Class == SurfaceClass::IntMass; }, true); + + // Opaque door goes next + moveSurfacesMatching([](auto const &s) { return s.Class == SurfaceClass::Door; }, false); + + // Exterior window subsurfaces (Window and GlassDoor) + moveSurfacesMatching( + [](auto const &s) { return s.ExtBoundCond <= 0 && (s.Class == SurfaceClass::Window || s.Class == SurfaceClass::GlassDoor); }, + false); + + // Interior window subsurfaces (Window and GlassDoor) + moveSurfacesMatching( + [](auto const &s) { return s.ExtBoundCond > 0 && (s.Class == SurfaceClass::Window || s.Class == SurfaceClass::GlassDoor); }, + false); + + // TDD_Diffuser + moveSurfacesMatching([](auto const &s) { return s.Class == SurfaceClass::TDD_Diffuser; }, false); + + // TDD_Dome + moveSurfacesMatching([](auto const &s) { return s.Class == SurfaceClass::TDD_Dome; }, false); } + } - } // ...end of the Surface DO loop for finding BaseSurf - if (NonMatch) { - ShowSevereError(state, EnergyPlus::format("{}Non matching interzone surfaces found", RoutineName)); + // Validity checking + assert(state.dataSurface->TotSurfaces == MovedSurfs); + assert(state.dataSurface->TotSurfaces == static_cast(state.dataSurface->AllSurfaceListReportOrder.size())); + assert(state.dataSurface->TotSurfaces == static_cast(oldToNewSurfNums.size())); + + // Assert validity of indices + assert(std::find_if(state.dataSurface->AllSurfaceListReportOrder.cbegin(), state.dataSurface->AllSurfaceListReportOrder.cend(), [](int i) { + return i < 1; + }) == state.dataSurface->AllSurfaceListReportOrder.cend()); + + assert(std::find_if(oldToNewSurfNums.cbegin(), oldToNewSurfNums.cend(), [](int i) { return i < 1; }) == oldToNewSurfNums.cend()); + + if (MovedSurfs != state.dataSurface->TotSurfaces) { + ShowSevereError( + state, + EnergyPlus::format( + "{}Reordered # of Surfaces ({}) not = Total # of Surfaces ({})", RoutineName, MovedSurfs, state.dataSurface->TotSurfaces)); + SurfError = true; + for (int Loop = 1; Loop <= state.dataSurface->TotSurfaces; ++Loop) { + if (!SurfaceTmpClassMoved(Loop) && state.dataSurfaceGeometry->SurfaceTmp(Loop).Class == SurfaceClass::Invalid) { + ShowSevereError(state, + EnergyPlus::format("{}Error in Surface= \"{} indicated Zone=\"{}\"", + RoutineName, + state.dataSurfaceGeometry->SurfaceTmp(Loop).Name, + state.dataSurfaceGeometry->SurfaceTmp(Loop).ZoneName)); + } + } + ShowWarningError( + state, + EnergyPlus::format("{}Remaining surface checks will use \"reordered number of surfaces\", not number of original surfaces", + RoutineName)); } - //********************************************************************************** - // Warn about interzone surfaces that have adiabatic windows/vice versa - SubSurfaceSevereDisplayed = false; + // Realign the relationship: surface to base surface for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { - if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) { - continue; + auto &movedSurf = state.dataSurface->Surface(SurfNum); + if (movedSurf.BaseSurf > 0) { + int newBaseSurfNum = oldToNewSurfNums(movedSurf.BaseSurf); + movedSurf.BaseSurf = newBaseSurfNum; + + if (newBaseSurfNum < 1) { + ShowFatalError(state, + EnergyPlus::format( + "{}Couldn't find the new Surface Number for surface index {} named '{}'. Looking for BaseSurf old index of {}", + RoutineName, + SurfNum, + movedSurf.Name, + movedSurf.BaseSurf)); + } } - if (state.dataSurface->Surface(SurfNum).BaseSurf == SurfNum) { - continue; // base surface + auto &reportOrderNum = state.dataSurface->AllSurfaceListReportOrder[SurfNum - 1]; + if (reportOrderNum > 0) { + int newReportOrderNum = oldToNewSurfNums(reportOrderNum); + reportOrderNum = newReportOrderNum; } - // not base surface. Check it. - if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond <= 0) { // exterior or other base surface - if (state.dataSurface->Surface(SurfNum).ExtBoundCond != - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) { // should match base surface - if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) { - ShowSevereError( - state, - EnergyPlus::format( - "{}Subsurface=\"{}\" exterior condition [adiabatic surface] in a base surface=\"{}\" with exterior condition [{}]", - RoutineName, - state.dataSurface->Surface(SurfNum).Name, - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name, - DataSurfaces::cExtBoundCondition( - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond))); - SurfError = true; - } else if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) { - ShowSevereError( - state, - EnergyPlus::format( - "{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior condition [{}]", - RoutineName, - state.dataSurface->Surface(SurfNum).Name, - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name, - DataSurfaces::cExtBoundCondition( - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond))); - SurfError = true; - } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond == - DataSurfaces::OtherSideCondModeledExt) { - ShowWarningError( - state, - EnergyPlus::format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]", - RoutineName, - state.dataSurface->Surface(SurfNum).Name, - DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond), - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name, - DataSurfaces::cExtBoundCondition( - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond))); - ShowContinueError(state, "...SubSurface will not use the exterior condition model of the base surface."); - } else { - ShowSevereError( - state, - EnergyPlus::format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]", - RoutineName, - state.dataSurface->Surface(SurfNum).Name, - DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond), - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name, - DataSurfaces::cExtBoundCondition( - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond))); - SurfError = true; - } - if (!SubSurfaceSevereDisplayed && SurfError) { - ShowContinueError(state, "...calculations for heat balance would be compromised."); - SubSurfaceSevereDisplayed = true; - } + } + + state.dataSurfaceGeometry->SurfaceTmp.deallocate(); // DeAllocate the Temp Surface derived type + + createSpaceSurfaceLists(state); + + // For each Base Surface Type (Wall, Floor, Roof) + + for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) { + for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { + + if (state.dataSurface->Surface(SurfNum).Zone == 0) { + continue; } - } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).BaseSurf == - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) { - // adiabatic surface. make sure subsurfaces match - if (state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) { // not adiabatic surface - if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) { - ShowSevereError( - state, - EnergyPlus::format("{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior " - "condition [adiabatic surface]", - RoutineName, - state.dataSurface->Surface(SurfNum).Name, - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name)); - } else { - ShowSevereError( - state, - EnergyPlus::format( - "{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [adiabatic surface]", - RoutineName, - state.dataSurface->Surface(SurfNum).Name, - DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond), - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name)); + + if (state.dataSurface->Surface(SurfNum).Class != Loop) { + continue; + } + + // Find all subsurfaces to this surface + for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) { + + if (SurfNum == SubSurfNum) { + continue; } - if (!SubSurfaceSevereDisplayed) { - ShowContinueError(state, "...calculations for heat balance would be compromised."); - SubSurfaceSevereDisplayed = true; + if (state.dataSurface->Surface(SubSurfNum).Zone == 0) { + continue; } - SurfError = true; - } - } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0) { // interzone surface - if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) { - ShowSevereError(state, - EnergyPlus::format("{}Subsurface=\"{}\" is an adiabatic surface in an Interzone base surface=\"{}\"", - RoutineName, - state.dataSurface->Surface(SurfNum).Name, - state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name)); - if (!SubSurfaceSevereDisplayed) { - ShowContinueError(state, "...calculations for heat balance would be compromised."); - SubSurfaceSevereDisplayed = true; + if (state.dataSurface->Surface(SubSurfNum).BaseSurf != SurfNum) { + continue; + } + + // Check facing angle of Sub compared to base + checkSubSurfAzTiltNorm(state, state.dataSurface->Surface(SurfNum), state.dataSurface->Surface(SubSurfNum), subSurfaceError); + if (subSurfaceError) { + SurfError = true; } - // SurfError=.TRUE. } } } + //********************************************************************************** + // Now, match up interzone surfaces + matchInterzoneSurfaces(state, RoutineName, MovedSurfs, SurfError); + + //********************************************************************************** + // Warn about interzone surfaces that have adiabatic windows/vice versa + checkSubSurfaceExtBoundConsistency(state, RoutineName, SurfError); + setSurfaceFirstLast(state); // Set up Floor Areas for Zones and Spaces @@ -2624,99 +2608,8 @@ namespace SurfaceGeometry { } } - // Reserve space to avoid excess allocations - state.dataSurface->AllHTSurfaceList.reserve(state.dataSurface->TotSurfaces); - state.dataSurface->AllExtSolarSurfaceList.reserve(state.dataSurface->TotSurfaces); - state.dataSurface->AllShadowPossObstrSurfaceList.reserve(state.dataSurface->TotSurfaces); - state.dataSurface->AllIZSurfaceList.reserve(state.dataSurface->TotSurfaces); - state.dataSurface->AllHTNonWindowSurfaceList.reserve(state.dataSurface->TotSurfaces - state.dataSurface->TotWindows); - state.dataSurface->AllHTWindowSurfaceList.reserve(state.dataSurface->TotWindows); - state.dataSurface->AllExtSolWindowSurfaceList.reserve(state.dataSurface->TotWindows); - state.dataSurface->AllExtSolWinWithFrameSurfaceList.reserve(state.dataSurface->TotWindows); - state.dataSurface->AllHTKivaSurfaceList.reserve(state.dataSurface->TotSurfaces); - - // Set flag that determines whether a surface can be an exterior obstruction - // Also set associated surfaces for Kiva foundations and build heat transfer surface lists - for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { - auto &surf = state.dataSurface->Surface(SurfNum); - surf.IsShadowPossibleObstruction = false; - if (surf.ExtSolar) { - // This may include some attached shading surfaces - state.dataSurface->AllExtSolarSurfaceList.push_back(SurfNum); - } - if (surf.HeatTransSurf) { - // Outside light shelves get tagged later as HeatTransSurf=true but they haven't been processed yet - state.dataSurface->AllHTSurfaceList.push_back(SurfNum); - int const zoneNum(surf.Zone); - auto &surfZone(state.dataHeatBal->Zone(zoneNum)); - surfZone.ZoneHTSurfaceList.push_back(SurfNum); - // Sort window vs non-window surfaces - if (surf.Class == DataSurfaces::SurfaceClass::Window) { - state.dataSurface->AllHTWindowSurfaceList.push_back(SurfNum); - surfZone.ZoneHTWindowSurfaceList.push_back(SurfNum); - if (surf.ExtSolar) { - state.dataSurface->AllExtSolWindowSurfaceList.push_back(SurfNum); - if (surf.FrameDivider > 0) { - state.dataSurface->AllExtSolWinWithFrameSurfaceList.push_back(SurfNum); - } - } - } else { - state.dataSurface->AllHTNonWindowSurfaceList.push_back(SurfNum); - surfZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum); - } - int const surfExtBoundCond(surf.ExtBoundCond); - // Build zone and interzone surface lists - if ((surfExtBoundCond > 0) && (surfExtBoundCond != SurfNum)) { - state.dataSurface->AllIZSurfaceList.push_back(SurfNum); - surfZone.ZoneIZSurfaceList.push_back(SurfNum); - auto &adjZone(state.dataHeatBal->Zone(state.dataSurface->Surface(surfExtBoundCond).Zone)); - adjZone.ZoneHTSurfaceList.push_back(SurfNum); - adjZone.ZoneIZSurfaceList.push_back(SurfNum); - // Sort window vs non-window surfaces - if (surf.Class == DataSurfaces::SurfaceClass::Window) { - adjZone.ZoneHTWindowSurfaceList.push_back(SurfNum); - } else { - adjZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum); - } - } - } - - // Exclude non-exterior heat transfer surfaces (but not OtherSideCondModeledExt = -4 CR7640) - if (surf.HeatTransSurf && surf.ExtBoundCond > 0) { - continue; - } - if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::Ground) { - continue; - } - if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::KivaFoundation) { - state.dataSurface->AllHTKivaSurfaceList.push_back(SurfNum); - if (!ErrorsFound) { - state.dataSurfaceGeometry->kivaManager.foundationInputs[surf.OSCPtr].surfaces.push_back(SurfNum); - } - continue; - } - if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt) { - continue; - } - if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) { - continue; - } - // Exclude windows and doors, i.e., consider only their base surfaces as possible obstructions - if (surf.Class == SurfaceClass::Window || surf.Class == SurfaceClass::Door) { - continue; - } - // Exclude duplicate shading surfaces - if (surf.MirroredSurf) { - continue; - } - // Exclude air boundary surfaces - if (surf.IsAirBoundarySurf) { - continue; - } - - surf.IsShadowPossibleObstruction = true; - state.dataSurface->AllShadowPossObstrSurfaceList.push_back(SurfNum); - } // for (SurfNum) + // Build all surface classification lists and set obstruction flags + buildSurfaceLists(state, ErrorsFound); // Check for IRT surfaces in invalid places. if (std::any_of(state.dataConstruction->Construct.begin(), @@ -2753,43 +2646,6 @@ namespace SurfaceGeometry { } } - // Populate SurfaceFilter lists - for (int iSurfaceFilter = 1; iSurfaceFilter < static_cast(DataSurfaces::SurfaceFilter::Num); ++iSurfaceFilter) { - state.dataSurface->SurfaceFilterLists[iSurfaceFilter].reserve(state.dataSurface->TotSurfaces); - } - - for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { - auto const &surf = state.dataSurface->Surface(SurfNum); - if (!surf.HeatTransSurf) { - continue; - } - if (surf.ExtBoundCond > 0) { - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllInteriorSurfaces)].push_back(SurfNum); - if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) { - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllInteriorWindows)].push_back(SurfNum); - } else if (surf.Class == SurfaceClass::Wall) { - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllInteriorWalls)].push_back(SurfNum); - } else if (surf.Class == SurfaceClass::Floor) { - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllInteriorFloors)].push_back(SurfNum); - } else if (surf.Class == SurfaceClass::Roof) { - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllInteriorRoofs)].push_back(SurfNum); - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum); - } - } else { - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllExteriorSurfaces)].push_back(SurfNum); - if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) { - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllExteriorWindows)].push_back(SurfNum); - } else if (surf.Class == SurfaceClass::Wall) { - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllExteriorWalls)].push_back(SurfNum); - } else if (surf.Class == SurfaceClass::Floor) { - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllExteriorFloors)].push_back(SurfNum); - } else if (surf.Class == SurfaceClass::Roof) { - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllExteriorRoofs)].push_back(SurfNum); - state.dataSurface->SurfaceFilterLists[static_cast(DataSurfaces::SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum); - } - } - } // for (SurfNum) - // Note, could do same for Window Area and detecting if Interzone Surface in Zone if (state.dataSurfaceGeometry->Warning1Count > 0) { diff --git a/src/EnergyPlus/SystemAvailabilityManager.cc b/src/EnergyPlus/SystemAvailabilityManager.cc index 55b463067f3..85e14c82105 100644 --- a/src/EnergyPlus/SystemAvailabilityManager.cc +++ b/src/EnergyPlus/SystemAvailabilityManager.cc @@ -2264,6 +2264,127 @@ namespace Avail { return false; } + // Find the first time step in a day schedule where the value is positive. + // Returns the corresponding hour as a Real64, or 0.0 if none found. + static Real64 findFanStartTime(std::vector const &dayVals, int const TimeStepsInHour, bool const useInclusiveBound = false) + { + // POSSIBLE BUG: original code uses ts <= TimeStepsInHour for today's schedule, + // which accesses index hr*TimeStepsInHour + TimeStepsInHour (potentially out-of-bounds). + // Preserving original behavior via useInclusiveBound parameter. + int const tsBound = useInclusiveBound ? TimeStepsInHour + 1 : TimeStepsInHour; + for (int hr = 0; hr < Constant::iHoursInDay; ++hr) { + for (int ts = 0; ts < tsBound; ++ts) { + if (dayVals[hr * TimeStepsInHour + ts] > 0.0) { + return hr + (1.0 / TimeStepsInHour) * (ts + 1) - 0.01; + } + } + } + return 0.0; + } + + // Compute PreStartTime, PreStartTimeTmr and OverNightStartFlag from DeltaTime. + static void calcPreStartTimes(Real64 const DeltaTime, + Real64 const FanStartTime, + Real64 const FanStartTimeTmr, + Real64 &PreStartTime, + Real64 &PreStartTimeTmr, + bool &OverNightStartFlag) + { + PreStartTime = FanStartTime - DeltaTime; + if (PreStartTime < 0.0) { + PreStartTime = -0.1; + } + PreStartTimeTmr = FanStartTimeTmr - DeltaTime; + if (PreStartTimeTmr < 0.0) { + PreStartTimeTmr += 24.0; + OverNightStartFlag = true; + } else { + OverNightStartFlag = false; + } + } + + // Update adaptive temperature gradient tracking for heating or cooling. + // timeOffset is 0.0 for daytime cases and 24.0 for overnight cases. + static void updateAdaptiveTempGrad(EnergyPlusData &state, + int const zoneIndex, + bool const isHeating, + Real64 const timeOffset, + int const NumPreDays, + Real64 &ATGUpdateTime1, + Real64 &ATGUpdateTime2, + Real64 &ATGUpdateTemp1, + Real64 &ATGUpdateTemp2, + bool &ATGUpdateFlag1, + bool &ATGUpdateFlag2) + { + if (state.dataGlobal->WarmupFlag) { + return; + } + Real64 const zoneTemp = state.dataHeatBalFanSys->TempTstatAir(zoneIndex); + if (ATGUpdateFlag1) { + ATGUpdateTime1 = state.dataGlobal->CurrentTime; + ATGUpdateTemp1 = zoneTemp; + ATGUpdateFlag1 = false; + } + bool setpointReached; + if (isHeating) { + setpointReached = (zoneTemp >= state.dataZoneCtrls->OccRoomTSetPointHeat(zoneIndex)); + } else { + setpointReached = (zoneTemp <= state.dataZoneCtrls->OccRoomTSetPointCool(zoneIndex)); + } + if (setpointReached && ATGUpdateFlag2) { + ATGUpdateTime2 = state.dataGlobal->CurrentTime; + ATGUpdateTemp2 = zoneTemp; + ATGUpdateFlag2 = false; + Real64 const tempDelta = isHeating ? (ATGUpdateTemp2 - ATGUpdateTemp1) : (ATGUpdateTemp1 - ATGUpdateTemp2); + Real64 const timeDelta = ATGUpdateTime2 - ATGUpdateTime1 + timeOffset; + auto &gradArray = isHeating ? state.dataAvail->OptStart_AdaTempGradTrdHeat : state.dataAvail->OptStart_AdaTempGradTrdCool; + if (std::abs(timeDelta) > 1.e-10) { + gradArray(NumPreDays) = tempDelta / timeDelta; + } else { + gradArray(NumPreDays) = tempDelta * state.dataGlobal->TimeStepsInHour; + } + } + } + + // Update adaptive temperature gradient history: initialize during warmup/day1, + // shift the trailing average on subsequent days. + static void updateAdaptiveTempGradHistory(EnergyPlusData &state, + SysAvailManagerOptimumStart const &OptStartMgr, + int const NumPreDays, + Real64 const FanStartTime, + Real64 &AdaTempGradHeat, + Real64 &AdaTempGradCool, + bool &FirstTimeATGFlag) + { + if (state.dataGlobal->WarmupFlag) { + AdaTempGradHeat = OptStartMgr.InitTGradHeat; + AdaTempGradCool = OptStartMgr.InitTGradCool; + } else if (state.dataGlobal->DayOfSim == 1 && state.dataGlobal->BeginDayFlag) { + state.dataAvail->OptStart_AdaTempGradTrdHeat = OptStartMgr.InitTGradHeat; + AdaTempGradHeat = OptStartMgr.InitTGradHeat; + state.dataAvail->OptStart_AdaTempGradTrdCool = OptStartMgr.InitTGradCool; + AdaTempGradCool = OptStartMgr.InitTGradCool; + } else { + if (state.dataGlobal->BeginDayFlag && FirstTimeATGFlag) { + FirstTimeATGFlag = false; + AdaTempGradHeat += state.dataAvail->OptStart_AdaTempGradTrdHeat(NumPreDays) / NumPreDays - + state.dataAvail->OptStart_AdaTempGradTrdHeat(1) / NumPreDays; + AdaTempGradCool += state.dataAvail->OptStart_AdaTempGradTrdCool(NumPreDays) / NumPreDays - + state.dataAvail->OptStart_AdaTempGradTrdCool(1) / NumPreDays; + if (FanStartTime > 0) { + for (int ATGCounter = 1; ATGCounter <= NumPreDays - 1; ++ATGCounter) { + state.dataAvail->OptStart_AdaTempGradTrdHeat(ATGCounter) = state.dataAvail->OptStart_AdaTempGradTrdHeat(ATGCounter + 1); + state.dataAvail->OptStart_AdaTempGradTrdCool(ATGCounter) = state.dataAvail->OptStart_AdaTempGradTrdCool(ATGCounter + 1); + } + } + } + } + if (state.dataGlobal->CurrentTime >= 1.0) { + FirstTimeATGFlag = true; + } + } + Status CalcOptStartSysAvailMgr(EnergyPlusData &state, int const SysAvailNum, // number of the current scheduled system availability manager int const PriAirSysNum, // number of the primary air system affected by this Avail. Manager @@ -2393,37 +2514,8 @@ namespace Avail { std::vector const &dayVals = OptStartMgr.fanSched->getDayVals(state); std::vector const &tmwDayVals = OptStartMgr.fanSched->getDayVals(state, TmrJDay, TmrDayOfWeek); - FanStartTime = 0.0; - FanStartTimeTmr = 0.0; - bool exitLoop = false; // exit loop on found data - for (int hr = 0; hr < Constant::iHoursInDay; ++hr) { - for (int ts = 0; ts <= state.dataGlobal->TimeStepsInHour; ++ts) { - if (dayVals[hr * state.dataGlobal->TimeStepsInHour + ts] <= 0.0) { - continue; - } - FanStartTime = hr + (1.0 / state.dataGlobal->TimeStepsInHour) * (ts + 1) - 0.01; - exitLoop = true; - break; - } - if (exitLoop) { - break; - } - } - - exitLoop = false; - for (int hr = 0; hr < Constant::iHoursInDay; ++hr) { - for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) { - if (tmwDayVals[hr * state.dataGlobal->TimeStepsInHour + ts] <= 0.0) { - continue; - } - FanStartTimeTmr = hr + (1.0 / state.dataGlobal->TimeStepsInHour) * (ts + 1) - 0.01; - exitLoop = true; - break; - } - if (exitLoop) { - break; - } - } + FanStartTime = findFanStartTime(dayVals, state.dataGlobal->TimeStepsInHour, true); // today: original used <= + FanStartTimeTmr = findFanStartTime(tmwDayVals, state.dataGlobal->TimeStepsInHour); if (FanStartTimeTmr == 0.0) { FanStartTimeTmr = 24.0; @@ -2463,17 +2555,7 @@ namespace Avail { if (DeltaTime > OptStartMgr.MaxOptStartTime) { DeltaTime = OptStartMgr.MaxOptStartTime; } - PreStartTime = FanStartTime - DeltaTime; - if (PreStartTime < 0.0) { - PreStartTime = -0.1; - } - PreStartTimeTmr = FanStartTimeTmr - DeltaTime; - if (PreStartTimeTmr < 0.0) { - PreStartTimeTmr += 24.0; - OverNightStartFlag = true; - } else { - OverNightStartFlag = false; - } + calcPreStartTimes(DeltaTime, FanStartTime, FanStartTimeTmr, PreStartTime, PreStartTimeTmr, OverNightStartFlag); if (!OverNightStartFlag) { if (FanStartTime == 0.0 || state.dataGlobal->PreviousHour > FanStartTime) { availStatus = Status::NoAction; @@ -2533,17 +2615,7 @@ namespace Avail { if (DeltaTime > OptStartMgr.MaxOptStartTime) { DeltaTime = OptStartMgr.MaxOptStartTime; } - PreStartTime = FanStartTime - DeltaTime; - if (PreStartTime < 0) { - PreStartTime = -0.1; - } - PreStartTimeTmr = FanStartTimeTmr - DeltaTime; - if (PreStartTimeTmr < 0) { - PreStartTimeTmr += 24.0; - OverNightStartFlag = true; - } else { - OverNightStartFlag = false; - } + calcPreStartTimes(DeltaTime, FanStartTime, FanStartTimeTmr, PreStartTime, PreStartTimeTmr, OverNightStartFlag); if (!OverNightStartFlag) { if (FanStartTime == 0.0 || state.dataGlobal->CurrentTime > FanStartTime) { CycleOnFlag = false; @@ -2603,17 +2675,7 @@ namespace Avail { if (DeltaTime > OptStartMgr.MaxOptStartTime) { DeltaTime = OptStartMgr.MaxOptStartTime; } - PreStartTime = FanStartTime - DeltaTime; - if (PreStartTime < 0) { - PreStartTime = -0.1; - } - PreStartTimeTmr = FanStartTimeTmr - DeltaTime; - if (PreStartTimeTmr < 0) { - PreStartTimeTmr += 24.0; - OverNightStartFlag = true; - } else { - OverNightStartFlag = false; - } + calcPreStartTimes(DeltaTime, FanStartTime, FanStartTimeTmr, PreStartTime, PreStartTimeTmr, OverNightStartFlag); if (!OverNightStartFlag) { if (FanStartTime == 0.0 || state.dataGlobal->CurrentTime > FanStartTime) { availStatus = Status::NoAction; @@ -2693,17 +2755,7 @@ namespace Avail { if (DeltaTime > OptStartMgr.MaxOptStartTime) { DeltaTime = OptStartMgr.MaxOptStartTime; } - PreStartTime = FanStartTime - DeltaTime; - if (PreStartTime < 0) { - PreStartTime = -0.1; - } - PreStartTimeTmr = FanStartTimeTmr - DeltaTime; - if (PreStartTimeTmr < 0) { - PreStartTimeTmr += 24.0; - OverNightStartFlag = true; - } else { - OverNightStartFlag = false; - } + calcPreStartTimes(DeltaTime, FanStartTime, FanStartTimeTmr, PreStartTime, PreStartTimeTmr, OverNightStartFlag); if (!OverNightStartFlag) { if (FanStartTime == 0.0 || state.dataGlobal->CurrentTime > FanStartTime) { availStatus = Status::NoAction; @@ -2765,17 +2817,7 @@ namespace Avail { if (DeltaTime > OptStartMgr.MaxOptStartTime) { DeltaTime = OptStartMgr.MaxOptStartTime; } - PreStartTime = FanStartTime - DeltaTime; - if (PreStartTime < 0) { - PreStartTime = -0.1; - } - PreStartTimeTmr = FanStartTimeTmr - DeltaTime; - if (PreStartTimeTmr < 0) { - PreStartTimeTmr += 24.0; - OverNightStartFlag = true; - } else { - OverNightStartFlag = false; - } + calcPreStartTimes(DeltaTime, FanStartTime, FanStartTimeTmr, PreStartTime, PreStartTimeTmr, OverNightStartFlag); if (!OverNightStartFlag) { if (FanStartTime == 0.0 || state.dataGlobal->CurrentTime > FanStartTime) { availStatus = Status::NoAction; @@ -2830,7 +2872,6 @@ namespace Avail { } break; case ControlAlgorithm::AdaptiveTemperatureGradient: { - int ATGCounter; if (OptStartMgr.optimumStartControlType == OptimumStartControlType::ControlZone) { ZoneNum = OptStartMgr.ZoneNum; if (!allocated(state.dataHeatBalFanSys->TempTstatAir) || !allocated(state.dataHeatBalFanSys->zoneTstatSetpts)) { @@ -2846,38 +2887,7 @@ namespace Avail { } } } - // Store adaptive temperature gradients for previous days and calculate the adaptive temp gradients - //----------------------------------------------------------------------------- - if (state.dataGlobal->WarmupFlag) { - AdaTempGradHeat = OptStartMgr.InitTGradHeat; - AdaTempGradCool = OptStartMgr.InitTGradCool; - } else if (state.dataGlobal->DayOfSim == 1 && state.dataGlobal->BeginDayFlag) { - state.dataAvail->OptStart_AdaTempGradTrdHeat = OptStartMgr.InitTGradHeat; - AdaTempGradHeat = OptStartMgr.InitTGradHeat; - state.dataAvail->OptStart_AdaTempGradTrdCool = OptStartMgr.InitTGradCool; - AdaTempGradCool = OptStartMgr.InitTGradCool; - } else { - if (state.dataGlobal->BeginDayFlag && FirstTimeATGFlag) { - FirstTimeATGFlag = false; - AdaTempGradHeat += state.dataAvail->OptStart_AdaTempGradTrdHeat(NumPreDays) / NumPreDays - - state.dataAvail->OptStart_AdaTempGradTrdHeat(1) / NumPreDays; - AdaTempGradCool += state.dataAvail->OptStart_AdaTempGradTrdCool(NumPreDays) / NumPreDays - - state.dataAvail->OptStart_AdaTempGradTrdCool(1) / NumPreDays; - if (FanStartTime > 0) { - for (ATGCounter = 1; ATGCounter <= NumPreDays - 1; ++ATGCounter) { - state.dataAvail->OptStart_AdaTempGradTrdHeat(ATGCounter) = - state.dataAvail->OptStart_AdaTempGradTrdHeat(ATGCounter + 1); - state.dataAvail->OptStart_AdaTempGradTrdCool(ATGCounter) = - state.dataAvail->OptStart_AdaTempGradTrdCool(ATGCounter + 1); - } - } - } - } - - if (state.dataGlobal->CurrentTime >= 1.0) { - FirstTimeATGFlag = true; - } - //------------------------------------------------------------------------------ + updateAdaptiveTempGradHistory(state, OptStartMgr, NumPreDays, FanStartTime, AdaTempGradHeat, AdaTempGradCool, FirstTimeATGFlag); if (TempDiffHi < 0.0) { TempDiff = TempDiffLo; @@ -2887,17 +2897,7 @@ namespace Avail { if (DeltaTime > OptStartMgr.MaxOptStartTime) { DeltaTime = OptStartMgr.MaxOptStartTime; } - PreStartTime = FanStartTime - DeltaTime; - if (PreStartTime < 0.0) { - PreStartTime = -0.1; - } - PreStartTimeTmr = FanStartTimeTmr - DeltaTime; - if (PreStartTimeTmr < 0.0) { - PreStartTimeTmr += 24.0; - OverNightStartFlag = true; - } else { - OverNightStartFlag = false; - } + calcPreStartTimes(DeltaTime, FanStartTime, FanStartTimeTmr, PreStartTime, PreStartTimeTmr, OverNightStartFlag); if (!OverNightStartFlag) { if (FanStartTime == 0.0 || state.dataGlobal->CurrentTime > FanStartTime) { availStatus = Status::NoAction; @@ -2909,28 +2909,18 @@ namespace Avail { if (state.dataGlobal->CurrentTime > FanStartTime) { CycleOnFlag = false; } - // Calculate the current day actual temperature gradient -------------------------- - if (!state.dataGlobal->WarmupFlag) { - if (ATGUpdateFlag1) { - ATGUpdateTime1 = state.dataGlobal->CurrentTime; - ATGUpdateTemp1 = state.dataHeatBalFanSys->TempTstatAir(ZoneNum); - ATGUpdateFlag1 = false; - } - if (state.dataHeatBalFanSys->TempTstatAir(ZoneNum) >= state.dataZoneCtrls->OccRoomTSetPointHeat(ZoneNum) && - ATGUpdateFlag2) { - ATGUpdateTime2 = state.dataGlobal->CurrentTime; - ATGUpdateTemp2 = state.dataHeatBalFanSys->TempTstatAir(ZoneNum); - ATGUpdateFlag2 = false; - if (std::abs(ATGUpdateTime2 - ATGUpdateTime1) > 1.e-10) { - state.dataAvail->OptStart_AdaTempGradTrdHeat(NumPreDays) = - (ATGUpdateTemp2 - ATGUpdateTemp1) / (ATGUpdateTime2 - ATGUpdateTime1); - } else { - state.dataAvail->OptStart_AdaTempGradTrdHeat(NumPreDays) = - (ATGUpdateTemp2 - ATGUpdateTemp1) * state.dataGlobal->TimeStepsInHour; - } - } - } - //--------------------------------------------------------------------------------- + updateAdaptiveTempGrad(state, + ZoneNum, + true, + 0.0, + NumPreDays, + + ATGUpdateTime1, + ATGUpdateTime2, + ATGUpdateTemp1, + ATGUpdateTemp2, + ATGUpdateFlag1, + ATGUpdateFlag2); } else if (PreStartTime < state.dataGlobal->CurrentTime) { if (OSReportVarFlag) { NumHoursBeforeOccupancy = DeltaTime; @@ -2958,28 +2948,18 @@ namespace Avail { if (state.dataGlobal->CurrentTime > FanStartTime && state.dataGlobal->CurrentTime < PreStartTimeTmr) { CycleOnFlag = false; } - // Calculate the current day actual temperature gradient -------------------------- - if (!state.dataGlobal->WarmupFlag) { - if (ATGUpdateFlag1) { - ATGUpdateTime1 = state.dataGlobal->CurrentTime; - ATGUpdateTemp1 = state.dataHeatBalFanSys->TempTstatAir(ZoneNum); - ATGUpdateFlag1 = false; - } - if (state.dataHeatBalFanSys->TempTstatAir(ZoneNum) >= state.dataZoneCtrls->OccRoomTSetPointHeat(ZoneNum) && - ATGUpdateFlag2) { - ATGUpdateTime2 = state.dataGlobal->CurrentTime; - ATGUpdateTemp2 = state.dataHeatBalFanSys->TempTstatAir(ZoneNum); - ATGUpdateFlag2 = false; - if (std::abs(ATGUpdateTime2 - ATGUpdateTime1 + 24.0) > 1.e-10) { - state.dataAvail->OptStart_AdaTempGradTrdHeat(NumPreDays) = - (ATGUpdateTemp2 - ATGUpdateTemp1) / (ATGUpdateTime2 - ATGUpdateTime1 + 24.0); - } else { - state.dataAvail->OptStart_AdaTempGradTrdHeat(NumPreDays) = - (ATGUpdateTemp2 - ATGUpdateTemp1) * state.dataGlobal->TimeStepsInHour; - } - } - } - //--------------------------------------------------------------------------------- + updateAdaptiveTempGrad(state, + ZoneNum, + true, + 24.0, + NumPreDays, + + ATGUpdateTime1, + ATGUpdateTime2, + ATGUpdateTemp1, + ATGUpdateTemp2, + ATGUpdateFlag1, + ATGUpdateFlag2); } else if (PreStartTime < state.dataGlobal->CurrentTime || PreStartTimeTmr < state.dataGlobal->CurrentTime) { if (OSReportVarFlag) { NumHoursBeforeOccupancy = DeltaTime; @@ -3006,17 +2986,7 @@ namespace Avail { if (DeltaTime > OptStartMgr.MaxOptStartTime) { DeltaTime = OptStartMgr.MaxOptStartTime; } - PreStartTime = FanStartTime - DeltaTime; - if (PreStartTime < 0.0) { - PreStartTime = -0.1; - } - PreStartTimeTmr = FanStartTimeTmr - DeltaTime; - if (PreStartTimeTmr < 0.0) { - PreStartTimeTmr += 24.0; - OverNightStartFlag = true; - } else { - OverNightStartFlag = false; - } + calcPreStartTimes(DeltaTime, FanStartTime, FanStartTimeTmr, PreStartTime, PreStartTimeTmr, OverNightStartFlag); if (!OverNightStartFlag) { if (FanStartTime == 0.0 || state.dataGlobal->CurrentTime > FanStartTime) { availStatus = Status::NoAction; @@ -3144,38 +3114,7 @@ namespace Avail { } } } - // Store adaptive temperature gradients for previous days and calculate the adaptive temp gradients - //----------------------------------------------------------------------------- - if (state.dataGlobal->WarmupFlag) { - AdaTempGradHeat = OptStartMgr.InitTGradHeat; - AdaTempGradCool = OptStartMgr.InitTGradCool; - } else if (state.dataGlobal->DayOfSim == 1 && state.dataGlobal->BeginDayFlag) { - state.dataAvail->OptStart_AdaTempGradTrdHeat = OptStartMgr.InitTGradHeat; - AdaTempGradHeat = OptStartMgr.InitTGradHeat; - state.dataAvail->OptStart_AdaTempGradTrdCool = OptStartMgr.InitTGradCool; - AdaTempGradCool = OptStartMgr.InitTGradCool; - } else { - if (state.dataGlobal->BeginDayFlag && FirstTimeATGFlag) { - FirstTimeATGFlag = false; - AdaTempGradHeat += state.dataAvail->OptStart_AdaTempGradTrdHeat(NumPreDays) / NumPreDays - - state.dataAvail->OptStart_AdaTempGradTrdHeat(1) / NumPreDays; - AdaTempGradCool += state.dataAvail->OptStart_AdaTempGradTrdCool(NumPreDays) / NumPreDays - - state.dataAvail->OptStart_AdaTempGradTrdCool(1) / NumPreDays; - if (FanStartTime > 0) { - for (ATGCounter = 1; ATGCounter <= NumPreDays - 1; ++ATGCounter) { - state.dataAvail->OptStart_AdaTempGradTrdHeat(ATGCounter) = - state.dataAvail->OptStart_AdaTempGradTrdHeat(ATGCounter + 1); - state.dataAvail->OptStart_AdaTempGradTrdCool(ATGCounter) = - state.dataAvail->OptStart_AdaTempGradTrdCool(ATGCounter + 1); - } - } - } - } - - if (state.dataGlobal->CurrentTime >= 1.0) { - FirstTimeATGFlag = true; - } - //------------------------------------------------------------------------------ + updateAdaptiveTempGradHistory(state, OptStartMgr, NumPreDays, FanStartTime, AdaTempGradHeat, AdaTempGradCool, FirstTimeATGFlag); if ((TempDiffHi < 0.0 && TempDiffLo < 0.0) || (std::abs(TempDiffLo) > std::abs(TempDiffHi) && TempDiffLo < 0.0)) { // Heating Mode TempDiff = TempDiffLo; @@ -3184,17 +3123,7 @@ namespace Avail { if (DeltaTime > OptStartMgr.MaxOptStartTime) { DeltaTime = OptStartMgr.MaxOptStartTime; } - PreStartTime = FanStartTime - DeltaTime; - if (PreStartTime < 0.0) { - PreStartTime = -0.1; - } - PreStartTimeTmr = FanStartTimeTmr - DeltaTime; - if (PreStartTimeTmr < 0.0) { - PreStartTimeTmr += 24.0; - OverNightStartFlag = true; - } else { - OverNightStartFlag = false; - } + calcPreStartTimes(DeltaTime, FanStartTime, FanStartTimeTmr, PreStartTime, PreStartTimeTmr, OverNightStartFlag); if (!OverNightStartFlag) { if (FanStartTime == 0.0 || state.dataGlobal->CurrentTime > FanStartTime) { OSReportVarFlag = true; @@ -3206,29 +3135,18 @@ namespace Avail { if (state.dataGlobal->CurrentTime > FanStartTime) { CycleOnFlag = false; } - // Calculate the current day actual temperature gradient -------------------------- - if (!state.dataGlobal->WarmupFlag) { - if (ATGUpdateFlag1) { - ATGUpdateTime1 = state.dataGlobal->CurrentTime; - ATGUpdateTemp1 = state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumLo); - ATGUpdateFlag1 = false; - } - if (state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumLo) >= - state.dataZoneCtrls->OccRoomTSetPointHeat(ATGWCZoneNumLo) && - ATGUpdateFlag2) { - ATGUpdateTime2 = state.dataGlobal->CurrentTime; - ATGUpdateTemp2 = state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumLo); - ATGUpdateFlag2 = false; - if (std::abs(ATGUpdateTime2 - ATGUpdateTime1) > 1.e-10) { - state.dataAvail->OptStart_AdaTempGradTrdHeat(NumPreDays) = - (ATGUpdateTemp2 - ATGUpdateTemp1) / (ATGUpdateTime2 - ATGUpdateTime1); - } else { - state.dataAvail->OptStart_AdaTempGradTrdHeat(NumPreDays) = - (ATGUpdateTemp2 - ATGUpdateTemp1) * state.dataGlobal->TimeStepsInHour; - } - } - } - //--------------------------------------------------------------------------------- + updateAdaptiveTempGrad(state, + ATGWCZoneNumLo, + true, + 0.0, + NumPreDays, + + ATGUpdateTime1, + ATGUpdateTime2, + ATGUpdateTemp1, + ATGUpdateTemp2, + ATGUpdateFlag1, + ATGUpdateFlag2); } else if (PreStartTime < state.dataGlobal->CurrentTime) { if (OSReportVarFlag) { NumHoursBeforeOccupancy = DeltaTime; @@ -3252,29 +3170,18 @@ namespace Avail { OSReportVarFlag = true; } else if (CycleOnFlag) { availStatus = Status::CycleOn; - // Calculate the current day actual temperature gradient -------------------------- - if (!state.dataGlobal->WarmupFlag) { - if (ATGUpdateFlag1) { - ATGUpdateTime1 = state.dataGlobal->CurrentTime; - ATGUpdateTemp1 = state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumLo); - ATGUpdateFlag1 = false; - } - if (state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumLo) >= - state.dataZoneCtrls->OccRoomTSetPointHeat(ATGWCZoneNumLo) && - ATGUpdateFlag2) { - ATGUpdateTime2 = state.dataGlobal->CurrentTime; - ATGUpdateTemp2 = state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumLo); - ATGUpdateFlag2 = false; - if (std::abs(ATGUpdateTime2 - ATGUpdateTime1 + 24.0) > 1.e-10) { - state.dataAvail->OptStart_AdaTempGradTrdHeat(NumPreDays) = - (ATGUpdateTemp2 - ATGUpdateTemp1) / (ATGUpdateTime2 - ATGUpdateTime1 + 24.0); - } else { - state.dataAvail->OptStart_AdaTempGradTrdHeat(NumPreDays) = - (ATGUpdateTemp2 - ATGUpdateTemp1) * state.dataGlobal->TimeStepsInHour; - } - } - } - //--------------------------------------------------------------------------------- + updateAdaptiveTempGrad(state, + ATGWCZoneNumLo, + true, + 24.0, + NumPreDays, + + ATGUpdateTime1, + ATGUpdateTime2, + ATGUpdateTemp1, + ATGUpdateTemp2, + ATGUpdateFlag1, + ATGUpdateFlag2); OptStartMgr.SetOptStartFlag(state, PriAirSysNum, zoneNum); if (state.dataGlobal->CurrentTime > FanStartTime && state.dataGlobal->CurrentTime < PreStartTimeTmr) { CycleOnFlag = false; @@ -3306,17 +3213,7 @@ namespace Avail { if (DeltaTime > OptStartMgr.MaxOptStartTime) { DeltaTime = OptStartMgr.MaxOptStartTime; } - PreStartTime = FanStartTime - DeltaTime; - if (PreStartTime < 0) { - PreStartTime = -0.1; - } - PreStartTimeTmr = FanStartTimeTmr - DeltaTime; - if (PreStartTimeTmr < 0) { - PreStartTimeTmr += 24.0; - OverNightStartFlag = true; - } else { - OverNightStartFlag = false; - } + calcPreStartTimes(DeltaTime, FanStartTime, FanStartTimeTmr, PreStartTime, PreStartTimeTmr, OverNightStartFlag); if (!OverNightStartFlag) { if (FanStartTime == 0.0 || state.dataGlobal->CurrentTime > FanStartTime) { availStatus = Status::NoAction; @@ -3324,29 +3221,18 @@ namespace Avail { OSReportVarFlag = true; } else if (CycleOnFlag) { availStatus = Status::CycleOn; - // Calculate the current day actual temperature gradient -------------------------- - if (!state.dataGlobal->WarmupFlag) { - if (ATGUpdateFlag1) { - ATGUpdateTime1 = state.dataGlobal->CurrentTime; - ATGUpdateTemp1 = state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumHi); - ATGUpdateFlag1 = false; - } - if (state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumHi) <= - state.dataZoneCtrls->OccRoomTSetPointCool(ATGWCZoneNumHi) && - ATGUpdateFlag2) { - ATGUpdateTime2 = state.dataGlobal->CurrentTime; - ATGUpdateTemp2 = state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumHi); - ATGUpdateFlag2 = false; - if (std::abs(ATGUpdateTime2 - ATGUpdateTime1) > 1.e-10) { - state.dataAvail->OptStart_AdaTempGradTrdCool(NumPreDays) = - (ATGUpdateTemp1 - ATGUpdateTemp2) / (ATGUpdateTime2 - ATGUpdateTime1); - } else { - state.dataAvail->OptStart_AdaTempGradTrdCool(NumPreDays) = - (ATGUpdateTemp1 - ATGUpdateTemp2) * state.dataGlobal->TimeStepsInHour; - } - } - } - //--------------------------------------------------------------------------------- + updateAdaptiveTempGrad(state, + ATGWCZoneNumHi, + false, + 0.0, + NumPreDays, + + ATGUpdateTime1, + ATGUpdateTime2, + ATGUpdateTemp1, + ATGUpdateTemp2, + ATGUpdateFlag1, + ATGUpdateFlag2); OptStartMgr.SetOptStartFlag(state, PriAirSysNum, zoneNum); } else if (PreStartTime < state.dataGlobal->CurrentTime) { if (OSReportVarFlag) { @@ -3371,29 +3257,18 @@ namespace Avail { OSReportVarFlag = true; } else if (CycleOnFlag) { availStatus = Status::CycleOn; - // Calculate the current day actual temperature gradient -------------------------- - if (!state.dataGlobal->WarmupFlag) { - if (ATGUpdateFlag1) { - ATGUpdateTime1 = state.dataGlobal->CurrentTime; - ATGUpdateTemp1 = state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumHi); - ATGUpdateFlag1 = false; - } - if (state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumHi) <= - state.dataZoneCtrls->OccRoomTSetPointCool(ATGWCZoneNumHi) && - ATGUpdateFlag2) { - ATGUpdateTime2 = state.dataGlobal->CurrentTime; - ATGUpdateTemp2 = state.dataHeatBalFanSys->TempTstatAir(ATGWCZoneNumHi); - ATGUpdateFlag2 = false; - if (std::abs(ATGUpdateTime2 - ATGUpdateTime1 + 24.0) > 1.e-10) { - state.dataAvail->OptStart_AdaTempGradTrdCool(NumPreDays) = - (ATGUpdateTemp1 - ATGUpdateTemp2) / (ATGUpdateTime2 - ATGUpdateTime1 + 24.0); - } else { - state.dataAvail->OptStart_AdaTempGradTrdCool(NumPreDays) = - (ATGUpdateTemp1 - ATGUpdateTemp2) * state.dataGlobal->TimeStepsInHour; - } - } - } - //--------------------------------------------------------------------------------- + updateAdaptiveTempGrad(state, + ATGWCZoneNumHi, + false, + 24.0, + NumPreDays, + + ATGUpdateTime1, + ATGUpdateTime2, + ATGUpdateTemp1, + ATGUpdateTemp2, + ATGUpdateFlag1, + ATGUpdateFlag2); OptStartMgr.SetOptStartFlag(state, PriAirSysNum, zoneNum); } else if (PreStartTime < state.dataGlobal->CurrentTime || PreStartTimeTmr < state.dataGlobal->CurrentTime) { if (OSReportVarFlag) { diff --git a/src/EnergyPlus/UnitarySystem.cc b/src/EnergyPlus/UnitarySystem.cc index 06bd75e2ca5..7c7b2d1ae00 100644 --- a/src/EnergyPlus/UnitarySystem.cc +++ b/src/EnergyPlus/UnitarySystem.cc @@ -112,8 +112,127 @@ namespace UnitarySystems { int constexpr SuppHeatCoil = 2; static constexpr std::string_view blankString; + + // Helper: build the residual functor used by SolveRoot throughout controlUnitarySystemOutput. + // Captures the common arguments and returns a callable matching std::function. + static std::function makeLoadResidualFunc(EnergyPlusData &state, + int unitarySysNum, + bool FirstHVACIteration, + HVAC::CompressorOp compressorOp, + Real64 loadToBeMet, + Real64 coolHeatFlag, + Real64 sensibleLoad, + Real64 OnOffAirFlowRatio, + bool HXUnitOn, + int AirLoopNum) + { + return [&state, + unitarySysNum, + FirstHVACIteration, + compressorOp, + loadToBeMet, + coolHeatFlag, + sensibleLoad, + OnOffAirFlowRatio, + HXUnitOn, + AirLoopNum](Real64 const PartLoadRatio) { + return UnitarySys::calcUnitarySystemLoadResidual(state, + PartLoadRatio, + unitarySysNum, + FirstHVACIteration, + compressorOp, + loadToBeMet, + coolHeatFlag, + sensibleLoad, + OnOffAirFlowRatio, + HXUnitOn, + AirLoopNum); + }; + } + // Helper: report "PLR out of range" warning for either sensible or latent solver failures. + // Consolidates identical warning blocks used in controlUnitarySystemOutput. + static void warnPLROutOfRange(EnergyPlusData &state, + std::string_view unitType, + std::string_view unitName, + std::string_view loadLabel, // "sensible" or "Latent" + std::string_view LoadLabel, // "Sensible" or "Latent" + int &failedIndex, + Real64 loadValue) + { + if (failedIndex == 0) { + ShowWarningMessage(state, EnergyPlus::format("Coil control failed for {}:{}", unitType, unitName)); + ShowContinueError(state, EnergyPlus::format(" {} part-load ratio determined to be outside the range of 0-1.", loadLabel)); + ShowContinueErrorTimeStamp(state, + EnergyPlus::format("{} load to be met = {:.2T} (watts), and the simulation continues.", LoadLabel, loadValue)); + } + ShowRecurringWarningErrorAtEnd(state, + std::string(unitType) + " \"" + std::string(unitName) + "\" - " + std::string(loadLabel) + + " part-load ratio out of range error continues. " + std::string(LoadLabel) + " load statistics:", + failedIndex, + loadValue, + loadValue); + } + + // Helper: report "iteration limit exceeded" warning for sensible or latent PLR solver failures. + static void warnPLRMaxIterExceeded(EnergyPlusData &state, + std::string_view unitType, + std::string_view unitName, + std::string_view loadLabel, // "sensible" or "Latent" + std::string_view LoadLabel, // "Sensible" or "Latent" + int &maxIterIndex, + Real64 loadValue, + Real64 outputValue) + { + if (maxIterIndex == 0) { + ShowWarningMessage(state, EnergyPlus::format("Coil control failed to converge for {}:{}", unitType, unitName)); + ShowContinueError(state, EnergyPlus::format(" Iteration limit exceeded in calculating system {} part-load ratio.", loadLabel)); + ShowContinueErrorTimeStamp( + state, + EnergyPlus::format("{} load to be met = {:.2T} (watts), {} output = {:.2T} (watts), and the simulation continues.", + LoadLabel, + loadValue, + loadLabel, + outputValue)); + } + ShowRecurringWarningErrorAtEnd(state, + std::string(unitType) + " \"" + std::string(unitName) + "\" - Iteration limit exceeded in calculating " + + std::string(loadLabel) + " part-load ratio error continues. " + std::string(LoadLabel) + + " load statistics:", + maxIterIndex, + loadValue, + loadValue); + } + static const std::string blankStdString; + // Helper: check that a coil air flow rate does not exceed the fan capacity; reset and warn if so. + static void checkCoilFlowVsFan(EnergyPlusData &state, + std::string_view cCurrentModuleObject, + std::string_view thisObjectName, + Real64 FanVolFlowRate, + const std::string &fanName, + Real64 &designFanVolFlowRate, + Real64 &maxCoilFlow, + bool coilExists, + std::string_view modeLabel) + { + if (FanVolFlowRate < maxCoilFlow && maxCoilFlow != DataSizing::AutoSize && coilExists) { + std::string modeLower{modeLabel}; + modeLower[0] = static_cast(std::tolower(static_cast(modeLower[0]))); + ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); + ShowContinueError(state, + EnergyPlus::format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air " + "flow rate in {} mode.", + FanVolFlowRate, + fanName, + modeLower)); + ShowContinueError( + state, EnergyPlus::format(" The {} Supply Air Flow Rate is reset to the fan flow rate and the simulation continues.", modeLabel)); + maxCoilFlow = FanVolFlowRate; + designFanVolFlowRate = FanVolFlowRate; + } + } + void UnitarySys::simulate(EnergyPlusData &state, std::string_view Name, bool const FirstHVACIteration, @@ -385,9 +504,7 @@ namespace UnitarySystems { static constexpr std::string_view routineName("InitUnitarySystems"); // only access for zone equipment, UnitaySystem does not yet have input for Availability Manager List Name - if (this->m_IsZoneEquipment && - (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP) && - !state.dataAvail->ZoneComp.empty()) { + if (this->m_IsZoneEquipment && this->isPackagedUnit() && !state.dataAvail->ZoneComp.empty()) { // need to move to better location and save thisObjectIndex and thisObjectType in struct // this->m_EquipCompNum is by parent type, not total UnitarySystems // e.g., PTAC = 1,2,3; PTHP = 1,2; PTWSHP = 1,2,3,4; UnitarySystems = 9 total @@ -1153,7 +1270,7 @@ namespace UnitarySystems { state.dataUnitarySystems->m_massFlow2 = 0.0; state.dataUnitarySystems->m_runTimeFraction1 = 0.0; state.dataUnitarySystems->m_runTimeFraction2 = 0.0; - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { // this should be done in the child. DXElecHeatingPower not reset to 0 if coil is off, ZoneSysAvailManager // zero the fan and DX coils electricity consumption state.dataHVACGlobal->DXElecCoolingPower = 0.0; @@ -1460,6 +1577,113 @@ namespace UnitarySystems { } } + // Helper: auto-size any DataSizing::AutoSize entries in a vol-flow-ratio array. + // Sets each auto-sized entry to (speed / numSpeeds). Used for both cooling and heating + // designSpecMSHP ratios in sizeSystem. + static void autosizeMSHPVolFlowRatios(std::vector &volFlowRatios, int numSpeeds) + { + for (int iter = numSpeeds; iter >= 1; --iter) { + if (volFlowRatios[iter - 1] == DataSizing::AutoSize) { + volFlowRatios[iter - 1] = double(iter) / double(numSpeeds); + } + } + } + + // Helper: compute multi-speed cooling flow rates from MSHP design spec ratios and set noLoad values. + // Replaces the repeated block: autosize ratios -> compute vol/mass/speed-ratio -> set noLoad. + static void computeMSHPCoolingFlowRates(DesignSpecMSHP &msHP, + std::vector &coolVolFlow, + std::vector &coolMassFlow, + std::vector &coolSpeedRatio, + Real64 maxCoolAirVolFlow, + Real64 designFanVolFlowRate, + Real64 stdRhoAir, + Real64 &maxNoCoolHeatAirVolFlow, + Real64 &maxNoCoolHeatAirMassFlow, + Real64 &noLoadAirFlowRateRatio) + { + autosizeMSHPVolFlowRatios(msHP.coolingVolFlowRatio, msHP.numOfSpeedCooling); + for (int iter = msHP.numOfSpeedCooling; iter > 0; --iter) { + coolVolFlow[iter] = maxCoolAirVolFlow * msHP.coolingVolFlowRatio[iter - 1]; + coolMassFlow[iter] = coolVolFlow[iter] * stdRhoAir; + coolSpeedRatio[iter] = coolVolFlow[iter] / designFanVolFlowRate; + } + maxNoCoolHeatAirVolFlow = maxCoolAirVolFlow * msHP.noLoadAirFlowRateRatio; + maxNoCoolHeatAirMassFlow = maxNoCoolHeatAirVolFlow * stdRhoAir; + noLoadAirFlowRateRatio = maxNoCoolHeatAirVolFlow / designFanVolFlowRate; + } + + // Helper: ensure multi-speed flow rate arrays are allocated to the required size. + // Used for both cooling and heating arrays in sizeSystem. + static void + ensureMultiSpeedArrays(std::vector &volFlowRate, std::vector &massFlowRate, std::vector &speedRatio, int numSpeeds) + { + if (numSpeeds <= 0) { + return; + } + if (volFlowRate.empty()) { + volFlowRate.resize(numSpeeds + 1); + } + if (massFlowRate.empty()) { + massFlowRate.resize(numSpeeds + 1); + } + if (speedRatio.empty()) { + speedRatio.resize(numSpeeds + 1); + } + } + + // Helper: size an outdoor air flow rate field and report design vs user-specified values. + // Used for cooling, heating, and no-load OA flow rate sizing in sizeSystem. + static void sizeOutdoorAirFlowRate(EnergyPlusData &state, + Real64 &outAirVolFlow, + Real64 desFlowValue, + bool sizingDesRunThisZone, + std::string_view unitType, + std::string_view unitName, + std::string_view operationDesc) + { + bool const isAutoSize = (outAirVolFlow == DataSizing::AutoSize); + if (!isAutoSize && !sizingDesRunThisZone) { + if (outAirVolFlow > 0.0) { + BaseSizer::reportSizerOutput( + state, unitType, unitName, EnergyPlus::format("User-Specified Outdoor Air Flow Rate {} [m3/s]", operationDesc), outAirVolFlow); + } + return; + } + CheckZoneSizing(state, unitType, unitName); + if (desFlowValue < HVAC::SmallAirVolFlow) { + desFlowValue = 0.0; + } + if (isAutoSize) { + outAirVolFlow = desFlowValue; + BaseSizer::reportSizerOutput( + state, unitType, unitName, EnergyPlus::format("Design Size Outdoor Air Flow Rate {} [m3/s]", operationDesc), desFlowValue); + } else { + if (outAirVolFlow > 0.0 && desFlowValue > 0.0 && sizingDesRunThisZone) { + Real64 const userValue = outAirVolFlow; + BaseSizer::reportSizerOutput(state, + unitType, + unitName, + EnergyPlus::format("Design Size Outdoor Air Flow Rate {} [m3/s]", operationDesc), + desFlowValue, + EnergyPlus::format("User-Specified Outdoor Air Flow Rate {} [m3/s]", operationDesc), + userValue); + if (state.dataGlobal->DisplayExtraWarnings) { + if ((std::abs(desFlowValue - userValue) / userValue) > state.dataSize->AutoVsHardSizingThreshold) { + ShowMessage(state, EnergyPlus::format("SizePTUnit: Potential issue with equipment sizing for {} {}", unitType, unitName)); + ShowContinueError(state, + EnergyPlus::format("User-Specified Outdoor Air Flow Rate {} of {:.5R} [m3/s]", operationDesc, userValue)); + ShowContinueError( + state, + EnergyPlus::format("differs from Design Size Outdoor Air Flow Rate {} of {:.5R} [m3/s]", operationDesc, desFlowValue)); + ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); + ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); + } + } + } + } + } + void UnitarySys::sizeSystem(EnergyPlusData &state, bool const FirstHVACIteration, int const AirLoopNum) { @@ -2104,114 +2328,75 @@ namespace UnitarySystems { // PT Units report sizing for cooling then heating, UnitarySystem reverses that order // temporarily reverse reporting for PT units so eio diffs are cleaner, remove later - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP) { - if (this->m_CoolCoilExists) { - // allow design size to report - if (this->m_MaxCoolAirVolFlow != DataSizing::AutoSize) { - EqSizing.CoolingAirFlow = false; - } - if (this->m_MaxCoolAirVolFlow <= 0.0) { // attempt to catch any missed logic in GetUnitarySystem - this->m_MaxCoolAirVolFlow = DataSizing::AutoSize; - } - state.dataSize->DataEMSOverrideON = this->m_MaxCoolAirVolFlowEMSOverrideOn; - state.dataSize->DataEMSOverride = this->m_MaxCoolAirVolFlowEMSOverrideValue; - TempSize = this->m_MaxCoolAirVolFlow; - bool errorsFound = false; - CoolingAirFlowSizer sizingCoolingAirFlow; - std::string stringOverride = "Cooling Supply Air Flow Rate [m3/s]"; - if (state.dataGlobal->isEpJSON) { - stringOverride = "cooling_supply_air_flow_rate [m3/s]"; - } - sizingCoolingAirFlow.overrideSizingString(stringOverride); - // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - this->m_MaxCoolAirVolFlow = sizingCoolingAirFlow.size(state, TempSize, errorsFound); - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataConstantUsedForSizing = 0.0; + bool const isPackagedType = + (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP); + + // Size cooling air flow (packaged does this first, non-packaged does it second) + auto sizeCoolingAirFlowBlock = [&]() { + if (!this->m_CoolCoilExists) { + return; } - if (this->m_HeatCoilExists) { - // allow design size to report - if (this->m_MaxHeatAirVolFlow != DataSizing::AutoSize) { - EqSizing.HeatingAirFlow = false; - } - SizingMethod = HVAC::HeatingAirflowSizing; - if (this->m_MaxHeatAirVolFlow <= 0.0) { // attempt to catch any missed logic in GetUnitarySystem - this->m_MaxHeatAirVolFlow = DataSizing::AutoSize; - } - bool saveEqSizingAirFlow = EqSizing.AirFlow; - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) { - EqSizing.AirFlow = false; - } - FieldNum = 7; // N7 , \field Heating Supply Air Flow Rate - state.dataSize->DataEMSOverrideON = this->m_MaxHeatAirVolFlowEMSOverrideOn; - state.dataSize->DataEMSOverride = this->m_MaxHeatAirVolFlowEMSOverrideValue; - TempSize = this->m_MaxHeatAirVolFlow; - // SizingString = UnitarySystemNumericFields(UnitarySysNum).FieldNames(FieldNum) + " [m3/s]"; - SizingString = "Heating Supply Air Flow Rate [m3/s]"; - bool errorsFound = false; - HeatingAirFlowSizer sizingHeatingAirFlow; - sizingHeatingAirFlow.overrideSizingString(SizingString); - // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - this->m_MaxHeatAirVolFlow = sizingHeatingAirFlow.size(state, TempSize, errorsFound); - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataConstantUsedForSizing = 0.0; - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) { - EqSizing.AirFlow = saveEqSizingAirFlow; - } + if (isPackagedType && this->m_MaxCoolAirVolFlow != DataSizing::AutoSize) { + EqSizing.CoolingAirFlow = false; } - - } else { - if (this->m_HeatCoilExists) { - - SizingMethod = HVAC::HeatingAirflowSizing; - if (this->m_MaxHeatAirVolFlow <= 0.0) { // attempt to catch any missed logic in GetUnitarySystem - this->m_MaxHeatAirVolFlow = DataSizing::AutoSize; - } - bool saveEqSizingAirFlow = EqSizing.AirFlow; - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) { - EqSizing.AirFlow = false; - } - FieldNum = 7; // N7 , \field Heating Supply Air Flow Rate - state.dataSize->DataEMSOverrideON = this->m_MaxHeatAirVolFlowEMSOverrideOn; - state.dataSize->DataEMSOverride = this->m_MaxHeatAirVolFlowEMSOverrideValue; - TempSize = this->m_MaxHeatAirVolFlow; - // SizingString = UnitarySystemNumericFields(UnitarySysNum).FieldNames(FieldNum) + " [m3/s]"; - SizingString = "Heating Supply Air Flow Rate [m3/s]"; - bool errorsFound = false; - HeatingAirFlowSizer sizingHeatingAirFlow; - sizingHeatingAirFlow.overrideSizingString(SizingString); - // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - this->m_MaxHeatAirVolFlow = sizingHeatingAirFlow.size(state, TempSize, errorsFound); - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataConstantUsedForSizing = 0.0; - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) { - EqSizing.AirFlow = saveEqSizingAirFlow; - } + if (this->m_MaxCoolAirVolFlow <= 0.0) { + this->m_MaxCoolAirVolFlow = DataSizing::AutoSize; } + state.dataSize->DataEMSOverrideON = this->m_MaxCoolAirVolFlowEMSOverrideOn; + state.dataSize->DataEMSOverride = this->m_MaxCoolAirVolFlowEMSOverrideValue; + TempSize = this->m_MaxCoolAirVolFlow; + bool errorsFound = false; + CoolingAirFlowSizer sizingCoolingAirFlow; + std::string stringOverride = "Cooling Supply Air Flow Rate [m3/s]"; + if (state.dataGlobal->isEpJSON) { + stringOverride = "cooling_supply_air_flow_rate [m3/s]"; + } + sizingCoolingAirFlow.overrideSizingString(stringOverride); + sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + this->m_MaxCoolAirVolFlow = sizingCoolingAirFlow.size(state, TempSize, errorsFound); + state.dataSize->DataEMSOverrideON = false; + state.dataSize->DataConstantUsedForSizing = 0.0; + }; - if (this->m_CoolCoilExists) { - - if (this->m_MaxCoolAirVolFlow <= 0.0) { // attempt to catch any missed logic in GetUnitarySystem - this->m_MaxCoolAirVolFlow = DataSizing::AutoSize; - } - state.dataSize->DataEMSOverrideON = this->m_MaxCoolAirVolFlowEMSOverrideOn; - state.dataSize->DataEMSOverride = this->m_MaxCoolAirVolFlowEMSOverrideValue; - TempSize = this->m_MaxCoolAirVolFlow; - bool errorsFound = false; - CoolingAirFlowSizer sizingCoolingAirFlow; - std::string stringOverride = "Cooling Supply Air Flow Rate [m3/s]"; - if (state.dataGlobal->isEpJSON) { - stringOverride = "cooling_supply_air_flow_rate [m3/s]"; - } - sizingCoolingAirFlow.overrideSizingString(stringOverride); - // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - this->m_MaxCoolAirVolFlow = sizingCoolingAirFlow.size(state, TempSize, errorsFound); - state.dataSize->DataEMSOverrideON = false; - state.dataSize->DataConstantUsedForSizing = 0.0; + // Size heating air flow (shared between packaged and non-packaged paths) + auto sizeHeatingAirFlowBlock = [&]() { + if (!this->m_HeatCoilExists) { + return; + } + if (isPackagedType && this->m_MaxHeatAirVolFlow != DataSizing::AutoSize) { + EqSizing.HeatingAirFlow = false; + } + SizingMethod = HVAC::HeatingAirflowSizing; + if (this->m_MaxHeatAirVolFlow <= 0.0) { + this->m_MaxHeatAirVolFlow = DataSizing::AutoSize; + } + bool saveEqSizingAirFlow = EqSizing.AirFlow; + if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) { + EqSizing.AirFlow = false; + } + FieldNum = 7; // N7 , \field Heating Supply Air Flow Rate + state.dataSize->DataEMSOverrideON = this->m_MaxHeatAirVolFlowEMSOverrideOn; + state.dataSize->DataEMSOverride = this->m_MaxHeatAirVolFlowEMSOverrideValue; + TempSize = this->m_MaxHeatAirVolFlow; + SizingString = "Heating Supply Air Flow Rate [m3/s]"; + bool errorsFound = false; + HeatingAirFlowSizer sizingHeatingAirFlow; + sizingHeatingAirFlow.overrideSizingString(SizingString); + sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + this->m_MaxHeatAirVolFlow = sizingHeatingAirFlow.size(state, TempSize, errorsFound); + state.dataSize->DataEMSOverrideON = false; + state.dataSize->DataConstantUsedForSizing = 0.0; + if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) { + EqSizing.AirFlow = saveEqSizingAirFlow; } + }; + + if (isPackagedType) { + sizeCoolingAirFlowBlock(); + sizeHeatingAirFlowBlock(); + } else { + sizeHeatingAirFlowBlock(); + sizeCoolingAirFlowBlock(); } // If not set, set DesignFanVolFlowRate as greater of cooling and heating to make sure this value > 0. @@ -2433,170 +2618,29 @@ namespace UnitarySystems { } if (this->OAMixerExists) { - IsAutoSize = false; - if (this->m_CoolOutAirVolFlow == DataSizing::AutoSize) { - IsAutoSize = true; - } - if (!IsAutoSize && !SizingDesRunThisZone) { // Simulation continue - if (this->m_CoolOutAirVolFlow > 0.0) { - BaseSizer::reportSizerOutput(state, - this->UnitType, - this->Name, - "User-Specified Outdoor Air Flow Rate During Cooling Operation [m3/s]", - this->m_CoolOutAirVolFlow); - } - } else { - CheckZoneSizing(state, this->UnitType, this->Name); - Real64 CoolOutAirVolFlowDes = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA; - if (CoolOutAirVolFlowDes < HVAC::SmallAirVolFlow) { - CoolOutAirVolFlowDes = 0.0; - } - if (IsAutoSize) { - this->m_CoolOutAirVolFlow = CoolOutAirVolFlowDes; - BaseSizer::reportSizerOutput( - state, this->UnitType, this->Name, "Design Size Outdoor Air Flow Rate During Cooling Operation [m3/s]", CoolOutAirVolFlowDes); - } else { - if (this->m_CoolOutAirVolFlow > 0.0 && CoolOutAirVolFlowDes > 0.0 && SizingDesRunThisZone) { - Real64 CoolOutAirVolFlowUser = this->m_CoolOutAirVolFlow; - BaseSizer::reportSizerOutput(state, - this->UnitType, - this->Name, - "Design Size Outdoor Air Flow Rate During Cooling Operation [m3/s]", - CoolOutAirVolFlowDes, - "User-Specified Outdoor Air Flow Rate During Cooling Operation [m3/s]", - CoolOutAirVolFlowUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(CoolOutAirVolFlowDes - CoolOutAirVolFlowUser) / CoolOutAirVolFlowUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage( - state, - EnergyPlus::format("SizePTUnit: Potential issue with equipment sizing for {} {}", this->UnitType, this->Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Outdoor Air Flow Rate During Cooling Operation of {:.5R} [m3/s]", - CoolOutAirVolFlowUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Outdoor Air Flow Rate During Cooling Operation of {:.5R} [m3/s]", - CoolOutAirVolFlowDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } - } - - IsAutoSize = false; - if (this->m_HeatOutAirVolFlow == DataSizing::AutoSize) { - IsAutoSize = true; - } - if (!IsAutoSize && !SizingDesRunThisZone) { // Simulation continue - if (this->m_HeatOutAirVolFlow > 0.0) { - BaseSizer::reportSizerOutput(state, - this->UnitType, - this->Name, - "User-Specified Outdoor Air Flow Rate During Heating Operation [m3/s]", - this->m_HeatOutAirVolFlow); - } - } else { - CheckZoneSizing(state, this->UnitType, this->Name); - Real64 HeatOutAirVolFlowDes = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA; - if (HeatOutAirVolFlowDes < HVAC::SmallAirVolFlow) { - HeatOutAirVolFlowDes = 0.0; - } - if (IsAutoSize) { - this->m_HeatOutAirVolFlow = HeatOutAirVolFlowDes; - BaseSizer::reportSizerOutput( - state, this->UnitType, this->Name, "Design Size Outdoor Air Flow Rate During Heating Operation [m3/s]", HeatOutAirVolFlowDes); - } else { - if (this->m_HeatOutAirVolFlow > 0.0 && HeatOutAirVolFlowDes > 0.0 && SizingDesRunThisZone) { - Real64 HeatOutAirVolFlowUser = this->m_HeatOutAirVolFlow; - BaseSizer::reportSizerOutput(state, - this->UnitType, - this->Name, - "Design Size Outdoor Air Flow Rate During Heating Operation [m3/s]", - HeatOutAirVolFlowDes, - "User-Specified Outdoor Air Flow Rate During Heating Operation [m3/s]", - HeatOutAirVolFlowUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(HeatOutAirVolFlowDes - HeatOutAirVolFlowUser) / HeatOutAirVolFlowUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage( - state, - EnergyPlus::format("SizePTUnit: Potential issue with equipment sizing for {} {}", this->UnitType, this->Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Outdoor Air Flow Rate During Heating Operation of {:.5R} [m3/s]", - HeatOutAirVolFlowUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Outdoor Air Flow Rate During Heating Operation of {:.5R} [m3/s]", - HeatOutAirVolFlowDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } - } - - IsAutoSize = false; - if (this->m_NoCoolHeatOutAirVolFlow == DataSizing::AutoSize) { - IsAutoSize = true; - } - if (!IsAutoSize && !SizingDesRunThisZone) { // Simulation continue - if (this->m_NoCoolHeatOutAirVolFlow > 0.0) { - BaseSizer::reportSizerOutput(state, - this->UnitType, - this->Name, - "User-Specified Outdoor Air Flow Rate When No Cooling or Heating is Needed [m3/s]", - this->m_NoCoolHeatOutAirVolFlow); - } - } else { - CheckZoneSizing(state, this->UnitType, this->Name); - Real64 NoCoolHeatOutAirVolFlowDes = - min(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA, this->m_MaxNoCoolHeatAirVolFlow); - if (NoCoolHeatOutAirVolFlowDes < HVAC::SmallAirVolFlow) { - NoCoolHeatOutAirVolFlowDes = 0.0; - } - if (IsAutoSize) { - this->m_NoCoolHeatOutAirVolFlow = NoCoolHeatOutAirVolFlowDes; - BaseSizer::reportSizerOutput(state, - this->UnitType, - this->Name, - "Design Size Outdoor Air Flow Rate When No Cooling or Heating is Needed [m3/s]", - NoCoolHeatOutAirVolFlowDes); - } else { - if (this->m_NoCoolHeatOutAirVolFlow > 0.0 && NoCoolHeatOutAirVolFlowDes > 0.0 && SizingDesRunThisZone) { - Real64 NoCoolHeatOutAirVolFlowUser = this->m_NoCoolHeatOutAirVolFlow; - BaseSizer::reportSizerOutput(state, - this->UnitType, - this->Name, - "Design Size Outdoor Air Flow Rate When No Cooling or Heating is Needed [m3/s]", - NoCoolHeatOutAirVolFlowDes, - "User-Specified Outdoor Air Flow Rate When No Cooling or Heating is Needed [m3/s]", - NoCoolHeatOutAirVolFlowUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(NoCoolHeatOutAirVolFlowDes - NoCoolHeatOutAirVolFlowUser) / NoCoolHeatOutAirVolFlowUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage( - state, - EnergyPlus::format("SizePTUnit: Potential issue with equipment sizing for {} {}", this->UnitType, this->Name)); - ShowContinueError( - state, - EnergyPlus::format("User-Specified Outdoor Air Flow Rate When No Cooling or Heating is Needed of {:.5R} [m3/s]", - NoCoolHeatOutAirVolFlowUser)); - ShowContinueError( - state, - EnergyPlus::format( - "differs from Design Size Outdoor Air Flow Rate When No Cooling or Heating is Needed of {:.5R} [m3/s]", - NoCoolHeatOutAirVolFlowDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } - } + sizeOutdoorAirFlowRate(state, + this->m_CoolOutAirVolFlow, + state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA, + SizingDesRunThisZone, + this->UnitType, + this->Name, + "During Cooling Operation"); + + sizeOutdoorAirFlowRate(state, + this->m_HeatOutAirVolFlow, + state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA, + SizingDesRunThisZone, + this->UnitType, + this->Name, + "During Heating Operation"); + + sizeOutdoorAirFlowRate(state, + this->m_NoCoolHeatOutAirVolFlow, + min(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA, this->m_MaxNoCoolHeatAirVolFlow), + SizingDesRunThisZone, + this->UnitType, + this->Name, + "When No Cooling or Heating is Needed"); } if (this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP) { PrintFlag = false; @@ -2658,26 +2702,12 @@ namespace UnitarySystems { // initialize multi-speed coils if ((this->m_CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPVSEquationFit) || (this->m_CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed)) { - if (this->m_NumOfSpeedCooling > 0) { - if (this->m_CoolVolumeFlowRate.empty()) { - this->m_CoolVolumeFlowRate.resize(this->m_NumOfSpeedCooling + 1); - } - if (this->m_CoolMassFlowRate.empty()) { - this->m_CoolMassFlowRate.resize(this->m_NumOfSpeedCooling + 1); - } - if (this->m_MSCoolingSpeedRatio.empty()) { - this->m_MSCoolingSpeedRatio.resize(this->m_NumOfSpeedCooling + 1); - } - } + ensureMultiSpeedArrays(this->m_CoolVolumeFlowRate, this->m_CoolMassFlowRate, this->m_MSCoolingSpeedRatio, this->m_NumOfSpeedCooling); MSHPIndex = this->m_DesignSpecMSHPIndex; if (MSHPIndex > -1) { - for (Iter = state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling; Iter >= 1; --Iter) { - if (state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] == DataSizing::AutoSize) { - state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] = - double(Iter) / double(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling); - } - } + autosizeMSHPVolFlowRatios(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio, + state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling); } VariableSpeedCoils::SimVariableSpeedCoils(state, @@ -2760,13 +2790,8 @@ namespace UnitarySystems { // it feels like we are jamming the rectangular DXCoil into an oval box here MSHPIndex = this->m_DesignSpecMSHPIndex; if (MSHPIndex > -1) { - for (Iter = state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling; Iter >= 1; - --Iter) { // use reverse order since we divide by HeatVolumeFlowRate(max) - if (state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] == DataSizing::AutoSize) { - state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] = - double(Iter) / double(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling); - } - } + autosizeMSHPVolFlowRatios(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio, + state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling); } // TODO: Determine operating mode based on dehumidification stuff, using normalMode for now @@ -2805,47 +2830,28 @@ namespace UnitarySystems { } if (MSHPIndex > -1) { - for (Iter = state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling; Iter > 0; --Iter) { - if (state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] == DataSizing::AutoSize) { - state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] = - double(Iter) / double(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling); - } - this->m_CoolVolumeFlowRate[Iter] = - this->m_MaxCoolAirVolFlow * state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1]; - this->m_CoolMassFlowRate[Iter] = this->m_CoolVolumeFlowRate[Iter] * state.dataEnvrn->StdRhoAir; - this->m_MSCoolingSpeedRatio[Iter] = this->m_CoolVolumeFlowRate[Iter] / this->m_DesignFanVolFlowRate; - } - this->m_MaxNoCoolHeatAirVolFlow = - this->m_MaxCoolAirVolFlow * state.dataUnitarySystems->designSpecMSHP[MSHPIndex].noLoadAirFlowRateRatio; - this->MaxNoCoolHeatAirMassFlow = this->m_MaxNoCoolHeatAirVolFlow * state.dataEnvrn->StdRhoAir; - this->m_NoLoadAirFlowRateRatio = this->m_MaxNoCoolHeatAirVolFlow / this->m_DesignFanVolFlowRate; + computeMSHPCoolingFlowRates(state.dataUnitarySystems->designSpecMSHP[MSHPIndex], + this->m_CoolVolumeFlowRate, + this->m_CoolMassFlowRate, + this->m_MSCoolingSpeedRatio, + this->m_MaxCoolAirVolFlow, + this->m_DesignFanVolFlowRate, + state.dataEnvrn->StdRhoAir, + this->m_MaxNoCoolHeatAirVolFlow, + this->MaxNoCoolHeatAirMassFlow, + this->m_NoLoadAirFlowRateRatio); } else if (this->m_CoolVolumeFlowRate.empty()) { this->m_NoLoadAirFlowRateRatio = this->m_MaxNoCoolHeatAirVolFlow / this->m_DesignFanVolFlowRate; } } } else if (this->m_CoolingCoilType_Num == HVAC::CoilDX_Cooling) { - if (this->m_NumOfSpeedCooling > 0) { - if (this->m_CoolVolumeFlowRate.empty()) { - this->m_CoolVolumeFlowRate.resize(this->m_NumOfSpeedCooling + 1); - } - if (this->m_CoolMassFlowRate.empty()) { - this->m_CoolMassFlowRate.resize(this->m_NumOfSpeedCooling + 1); - } - if (this->m_MSCoolingSpeedRatio.empty()) { - this->m_MSCoolingSpeedRatio.resize(this->m_NumOfSpeedCooling + 1); - } - } + ensureMultiSpeedArrays(this->m_CoolVolumeFlowRate, this->m_CoolMassFlowRate, this->m_MSCoolingSpeedRatio, this->m_NumOfSpeedCooling); // it feels like we are jamming the rectangular DXCoil into an oval box here MSHPIndex = this->m_DesignSpecMSHPIndex; if (MSHPIndex > -1) { - for (Iter = state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling; Iter >= 1; - --Iter) { // use reverse order since we divide by HeatVolumeFlowRate(max) - if (state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] == DataSizing::AutoSize) { - state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] = - double(Iter) / double(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling); - } - } + autosizeMSHPVolFlowRatios(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio, + state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling); } // mine capacity from Coil:Cooling:DX object @@ -2886,36 +2892,22 @@ namespace UnitarySystems { } if (MSHPIndex > -1) { - for (Iter = state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling; Iter > 0; --Iter) { - if (state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] == DataSizing::AutoSize) { - state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] = - double(Iter) / double(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling); - } - this->m_CoolVolumeFlowRate[Iter] = - this->m_MaxCoolAirVolFlow * state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1]; - this->m_CoolMassFlowRate[Iter] = this->m_CoolVolumeFlowRate[Iter] * state.dataEnvrn->StdRhoAir; - this->m_MSCoolingSpeedRatio[Iter] = this->m_CoolVolumeFlowRate[Iter] / this->m_DesignFanVolFlowRate; - } - this->m_MaxNoCoolHeatAirVolFlow = - this->m_MaxCoolAirVolFlow * state.dataUnitarySystems->designSpecMSHP[MSHPIndex].noLoadAirFlowRateRatio; - this->MaxNoCoolHeatAirMassFlow = this->m_MaxNoCoolHeatAirVolFlow * state.dataEnvrn->StdRhoAir; - this->m_NoLoadAirFlowRateRatio = this->m_MaxNoCoolHeatAirVolFlow / this->m_DesignFanVolFlowRate; + computeMSHPCoolingFlowRates(state.dataUnitarySystems->designSpecMSHP[MSHPIndex], + this->m_CoolVolumeFlowRate, + this->m_CoolMassFlowRate, + this->m_MSCoolingSpeedRatio, + this->m_MaxCoolAirVolFlow, + this->m_DesignFanVolFlowRate, + state.dataEnvrn->StdRhoAir, + this->m_MaxNoCoolHeatAirVolFlow, + this->MaxNoCoolHeatAirMassFlow, + this->m_NoLoadAirFlowRateRatio); } else if (this->m_CoolVolumeFlowRate.empty()) { this->m_NoLoadAirFlowRateRatio = this->m_MaxNoCoolHeatAirVolFlow / this->m_DesignFanVolFlowRate; } } else if (this->m_CoolingCoilType_Num == HVAC::CoilDX_MultiSpeedCooling || this->m_CoolingCoilType_Num == HVAC::CoilDX_CoolingTwoSpeed) { - if (this->m_NumOfSpeedCooling > 0) { - if (this->m_CoolVolumeFlowRate.empty()) { - this->m_CoolVolumeFlowRate.resize(this->m_NumOfSpeedCooling + 1); - } - if (this->m_CoolMassFlowRate.empty()) { - this->m_CoolMassFlowRate.resize(this->m_NumOfSpeedCooling + 1); - } - if (this->m_MSCoolingSpeedRatio.empty()) { - this->m_MSCoolingSpeedRatio.resize(this->m_NumOfSpeedCooling + 1); - } - } + ensureMultiSpeedArrays(this->m_CoolVolumeFlowRate, this->m_CoolMassFlowRate, this->m_MSCoolingSpeedRatio, this->m_NumOfSpeedCooling); // set the multi-speed high flow rate variable in case a non-zero air flow rate resides on the coil inlet during sizing (e.g., upstream // system ran prior to this one) @@ -2935,20 +2927,16 @@ namespace UnitarySystems { if (MSHPIndex > -1) { // use reverse order since we divide by CoolVolumeFlowRate(max) - for (Iter = state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling; Iter > 0; --Iter) { - if (state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] == DataSizing::AutoSize) { - state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] = - double(Iter) / double(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling); - } - this->m_CoolVolumeFlowRate[Iter] = - this->m_MaxCoolAirVolFlow * state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1]; - this->m_CoolMassFlowRate[Iter] = this->m_CoolVolumeFlowRate[Iter] * state.dataEnvrn->StdRhoAir; - this->m_MSCoolingSpeedRatio[Iter] = this->m_CoolVolumeFlowRate[Iter] / this->m_DesignFanVolFlowRate; - } - this->m_MaxNoCoolHeatAirVolFlow = - this->m_MaxCoolAirVolFlow * state.dataUnitarySystems->designSpecMSHP[MSHPIndex].noLoadAirFlowRateRatio; - this->MaxNoCoolHeatAirMassFlow = this->m_MaxNoCoolHeatAirVolFlow * state.dataEnvrn->StdRhoAir; - this->m_NoLoadAirFlowRateRatio = this->m_MaxNoCoolHeatAirVolFlow / this->m_DesignFanVolFlowRate; + computeMSHPCoolingFlowRates(state.dataUnitarySystems->designSpecMSHP[MSHPIndex], + this->m_CoolVolumeFlowRate, + this->m_CoolMassFlowRate, + this->m_MSCoolingSpeedRatio, + this->m_MaxCoolAirVolFlow, + this->m_DesignFanVolFlowRate, + state.dataEnvrn->StdRhoAir, + this->m_MaxNoCoolHeatAirVolFlow, + this->MaxNoCoolHeatAirMassFlow, + this->m_NoLoadAirFlowRateRatio); } else if (this->m_CoolVolumeFlowRate.empty()) { this->m_NoLoadAirFlowRateRatio = this->m_MaxNoCoolHeatAirVolFlow / this->m_DesignFanVolFlowRate; } else { @@ -2961,34 +2949,20 @@ namespace UnitarySystems { this->m_NoLoadAirFlowRateRatio = this->m_MaxNoCoolHeatAirVolFlow / this->m_DesignFanVolFlowRate; } } else if (this->m_CoolingCoilType_Num == HVAC::Coil_CoolingWater || this->m_CoolingCoilType_Num == HVAC::Coil_CoolingWaterDetailed) { - if (this->m_NumOfSpeedCooling > 0) { - if (this->m_CoolVolumeFlowRate.empty()) { - this->m_CoolVolumeFlowRate.resize(this->m_NumOfSpeedCooling + 1); - } - if (this->m_CoolMassFlowRate.empty()) { - this->m_CoolMassFlowRate.resize(this->m_NumOfSpeedCooling + 1); - } - if (this->m_MSCoolingSpeedRatio.empty()) { - this->m_MSCoolingSpeedRatio.resize(this->m_NumOfSpeedCooling + 1); - } - } + ensureMultiSpeedArrays(this->m_CoolVolumeFlowRate, this->m_CoolMassFlowRate, this->m_MSCoolingSpeedRatio, this->m_NumOfSpeedCooling); MSHPIndex = this->m_DesignSpecMSHPIndex; if (MSHPIndex > -1) { - for (Iter = state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling; Iter > 0; --Iter) { - if (state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] == DataSizing::AutoSize) { - state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1] = - double(Iter) / double(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedCooling); - } - this->m_CoolVolumeFlowRate[Iter] = - this->m_MaxCoolAirVolFlow * state.dataUnitarySystems->designSpecMSHP[MSHPIndex].coolingVolFlowRatio[Iter - 1]; - this->m_CoolMassFlowRate[Iter] = this->m_CoolVolumeFlowRate[Iter] * state.dataEnvrn->StdRhoAir; - this->m_MSCoolingSpeedRatio[Iter] = this->m_CoolVolumeFlowRate[Iter] / this->m_DesignFanVolFlowRate; - } - this->m_MaxNoCoolHeatAirVolFlow = - this->m_MaxCoolAirVolFlow * state.dataUnitarySystems->designSpecMSHP[MSHPIndex].noLoadAirFlowRateRatio; - this->MaxNoCoolHeatAirMassFlow = this->m_MaxNoCoolHeatAirVolFlow * state.dataEnvrn->StdRhoAir; - this->m_NoLoadAirFlowRateRatio = this->m_MaxNoCoolHeatAirVolFlow / this->m_DesignFanVolFlowRate; + computeMSHPCoolingFlowRates(state.dataUnitarySystems->designSpecMSHP[MSHPIndex], + this->m_CoolVolumeFlowRate, + this->m_CoolMassFlowRate, + this->m_MSCoolingSpeedRatio, + this->m_MaxCoolAirVolFlow, + this->m_DesignFanVolFlowRate, + state.dataEnvrn->StdRhoAir, + this->m_MaxNoCoolHeatAirVolFlow, + this->MaxNoCoolHeatAirMassFlow, + this->m_NoLoadAirFlowRateRatio); } else if (this->m_CoolVolumeFlowRate.empty()) { this->m_NoLoadAirFlowRateRatio = this->m_MaxNoCoolHeatAirVolFlow / this->m_DesignFanVolFlowRate; } @@ -2996,17 +2970,7 @@ namespace UnitarySystems { if (this->m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || this->m_HeatingCoilType_Num == HVAC::Coil_HeatingElectric_MultiStage || this->m_HeatingCoilType_Num == HVAC::Coil_HeatingGas_MultiStage) { - if (this->m_NumOfSpeedHeating > 0) { - if (this->m_HeatVolumeFlowRate.empty()) { - this->m_HeatVolumeFlowRate.resize(this->m_NumOfSpeedHeating + 1); - } - if (this->m_HeatMassFlowRate.empty()) { - this->m_HeatMassFlowRate.resize(this->m_NumOfSpeedHeating + 1); - } - if (this->m_MSHeatingSpeedRatio.empty()) { - this->m_MSHeatingSpeedRatio.resize(this->m_NumOfSpeedHeating + 1); - } - } + ensureMultiSpeedArrays(this->m_HeatVolumeFlowRate, this->m_HeatMassFlowRate, this->m_MSHeatingSpeedRatio, this->m_NumOfSpeedHeating); MSHPIndex = this->m_DesignSpecMSHPIndex; @@ -3074,12 +3038,8 @@ namespace UnitarySystems { this->m_HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) { MSHPIndex = this->m_DesignSpecMSHPIndex; if (MSHPIndex > -1) { - for (Iter = state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedHeating; Iter > 0; --Iter) { - if (state.dataUnitarySystems->designSpecMSHP[MSHPIndex].heatingVolFlowRatio[Iter - 1] == DataSizing::AutoSize) { - state.dataUnitarySystems->designSpecMSHP[MSHPIndex].heatingVolFlowRatio[Iter - 1] = - double(Iter) / double(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedHeating); - } - } + autosizeMSHPVolFlowRatios(state.dataUnitarySystems->designSpecMSHP[MSHPIndex].heatingVolFlowRatio, + state.dataUnitarySystems->designSpecMSHP[MSHPIndex].numOfSpeedHeating); } VariableSpeedCoils::SimVariableSpeedCoils(state, @@ -3103,17 +3063,7 @@ namespace UnitarySystems { state.dataVariableSpeedCoils->VarSpeedCoil(this->m_HeatingCoilIndex).Name)); } - if (this->m_NumOfSpeedHeating > 0) { - if (this->m_HeatVolumeFlowRate.empty()) { - this->m_HeatVolumeFlowRate.resize(this->m_NumOfSpeedHeating + 1); - } - if (this->m_HeatMassFlowRate.empty()) { - this->m_HeatMassFlowRate.resize(this->m_NumOfSpeedHeating + 1); - } - if (this->m_MSHeatingSpeedRatio.empty()) { - this->m_MSHeatingSpeedRatio.resize(this->m_NumOfSpeedHeating + 1); - } - } + ensureMultiSpeedArrays(this->m_HeatVolumeFlowRate, this->m_HeatMassFlowRate, this->m_MSHeatingSpeedRatio, this->m_NumOfSpeedHeating); for (Iter = this->m_NumOfSpeedHeating; Iter >= 1; --Iter) { // using only for PTUnit to UnitarySystem conversion for the time being, should use this all the time @@ -3194,17 +3144,7 @@ namespace UnitarySystems { state.dataUnitarySystems->initUnitarySystemsErrorsFound); } - if (this->m_NumOfSpeedHeating > 0) { - if (this->m_HeatVolumeFlowRate.empty()) { - this->m_HeatVolumeFlowRate.resize(this->m_NumOfSpeedHeating + 1); - } - if (this->m_HeatMassFlowRate.empty()) { - this->m_HeatMassFlowRate.resize(this->m_NumOfSpeedHeating + 1); - } - if (this->m_MSHeatingSpeedRatio.empty()) { - this->m_MSHeatingSpeedRatio.resize(this->m_NumOfSpeedHeating + 1); - } - } + ensureMultiSpeedArrays(this->m_HeatVolumeFlowRate, this->m_HeatMassFlowRate, this->m_MSHeatingSpeedRatio, this->m_NumOfSpeedHeating); MSHPIndex = this->m_DesignSpecMSHPIndex; if (MSHPIndex > -1) { @@ -4836,17 +4776,6 @@ namespace UnitarySystems { thisCoolCoil.SupplyFanIndex); } } - if (this->m_HeatCoilExists) { - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple || - this->m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || - this->m_HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { - this->m_HeatPump = true; - } - } - // Push heating coil PLF curve index to DX coil if (HeatingCoilPLFCurveIndex > 0) { thisCoolCoil.HeatingCoilPLFCurvePTR = HeatingCoilPLFCurveIndex; @@ -4918,18 +4847,10 @@ namespace UnitarySystems { if (this->m_HeatCoilExists) { if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple || this->m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || this->m_HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { - this->m_HeatPump = true; - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed || - this->m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || - this->m_HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { - auto &newCoil = state.dataCoilCoolingDX->coilCoolingDXs[this->m_CoolingCoilIndex]; - newCoil.performance->ReportCoolingCoilCrankcasePower = false; - } + auto &newCoil = state.dataCoilCoolingDX->coilCoolingDXs[this->m_CoolingCoilIndex]; + newCoil.performance->ReportCoolingCoilCrankcasePower = false; } } } @@ -4966,17 +4887,6 @@ namespace UnitarySystems { if (HeatingCoilPLFCurveIndex > 0) { thisCoolCoil.HeatingCoilPLFCurvePTR = HeatingCoilPLFCurveIndex; } - - if (this->m_HeatCoilExists) { - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple || - this->m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || - this->m_HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { - this->m_HeatPump = true; - } - } } } // IF (IsNotOK) THEN @@ -5112,17 +5022,6 @@ namespace UnitarySystems { // what could we do for VS coil here? odd thing here } - if (this->m_HeatCoilExists) { - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple || - this->m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || - this->m_HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { - this->m_HeatPump = true; - } - } - } // IF (IsNotOK) THEN } else if (this->m_CoolingCoilType_Num == HVAC::CoilWater_CoolingHXAssisted) { ValidateComponent(state, input_data.cooling_coil_object_type, this->m_CoolingCoilName, isNotOK, cCurrentModuleObject); @@ -5245,17 +5144,6 @@ namespace UnitarySystems { } } - if (this->m_HeatCoilExists) { - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple || - this->m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || - this->m_HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { - this->m_HeatPump = true; - } - } - } else if (this->m_CoolingCoilType_Num == HVAC::CoilDX_MultiSpeedCooling) { ValidateComponent(state, input_data.cooling_coil_object_type, this->m_CoolingCoilName, isNotOK, cCurrentModuleObject); if (isNotOK) { @@ -5283,17 +5171,6 @@ namespace UnitarySystems { } } - if (this->m_HeatCoilExists) { - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple || - this->m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || - this->m_HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { - this->m_HeatPump = true; - } - } - } else if (this->m_CoolingCoilType_Num == HVAC::Coil_CoolingWater || this->m_CoolingCoilType_Num == HVAC::Coil_CoolingWaterDetailed) { ValidateComponent(state, input_data.cooling_coil_object_type, this->m_CoolingCoilName, isNotOK, cCurrentModuleObject); @@ -5365,17 +5242,6 @@ namespace UnitarySystems { } } - if (this->m_HeatCoilExists) { - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple || - this->m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || - this->m_HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { - this->m_HeatPump = true; - } - } - } else if (this->m_CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHP) { ValidateComponent(state, input_data.cooling_coil_object_type, this->m_CoolingCoilName, isNotOK, cCurrentModuleObject); if (isNotOK) { @@ -5398,17 +5264,6 @@ namespace UnitarySystems { } } - if (this->m_HeatCoilExists) { - if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP || - this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple || - this->m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || - this->m_HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { - this->m_HeatPump = true; - } - } - } else if (this->m_CoolingCoilType_Num == HVAC::Coil_UserDefined) { ValidateComponent(state, input_data.cooling_coil_object_type, this->m_CoolingCoilName, isNotOK, cCurrentModuleObject); if (isNotOK) { @@ -5470,6 +5325,17 @@ namespace UnitarySystems { errorsFound = true; } + // Set heat pump flag once after resolving cooling coil type — all cooling coil branches share the same condition + if (this->m_HeatCoilExists) { + if (this->m_HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed || + this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit || + this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP || + this->m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple || + this->m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || this->m_HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) { + this->m_HeatPump = true; + } + } + if (!input_data.dx_cooling_coil_system_sensor_node_name.empty()) { // used by CoilSystem:Cooling:DX this->CoolCtrlNode = Node::GetOnlySingleNode(state, input_data.dx_cooling_coil_system_sensor_node_name, @@ -5920,131 +5786,165 @@ namespace UnitarySystems { } } - // Determine supply air flow rate sizing method for cooling mode - if (Util::SameString(loc_m_CoolingSAFMethod, "SupplyAirFlowRate")) { - this->m_CoolingSAFMethod = DataSizing::SupplyAirFlowRate; - - if (loc_m_CoolingSAFMethod_SAFlow != -999.0) { - this->m_MaxCoolAirVolFlow = loc_m_CoolingSAFMethod_SAFlow; - if (this->m_MaxCoolAirVolFlow == DataSizing::AutoSize) { - this->m_RequestAutoSize = true; - } else { - if (this->m_MaxCoolAirVolFlow <= HVAC::SmallAirVolFlow && this->m_CoolCoilExists) { - ShowWarningError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Cooling Supply Air Flow Rate Method = SupplyAirFlowRate."); - ShowContinueError(state, - EnergyPlus::format("Suspicious Cooling Supply Air Flow Rate = {:.7R} when cooling coil is present.", - this->m_MaxCoolAirVolFlow)); - } - if (this->m_MaxCoolAirVolFlow < 0.0) { - errorsFound = true; + // Helper lambda: parse Cooling or Heating supply air flow rate method for the four + // named branches (SupplyAirFlowRate, FlowPerFloorArea, FractionOfAutosized, FlowPerCapacity). + // The None/blank branch differs between Cooling and Heating so it is handled separately below. + auto parseCoolHeatSAFMethod = [&](std::string_view methodStr, + std::string_view modeName, // "Cooling" or "Heating" + std::string_view fracKey, // "FractionOfAutosizedCoolingValue" / "...HeatingValue" + std::string_view capKey, // "FlowPerCoolingCapacity" / "FlowPerHeatingCapacity" + int fracEnum, + int capEnum, + Real64 localSAFlow, + Real64 localSAFlowPerFloorArea, + Real64 localFracOfAutosized, + Real64 localFlowPerCap, + int &safMethodOut, + Real64 &maxAirVolFlowInOut, + bool ownCoilExists) { + if (Util::SameString(methodStr, "SupplyAirFlowRate")) { + safMethodOut = DataSizing::SupplyAirFlowRate; + if (localSAFlow != -999.0) { + maxAirVolFlowInOut = localSAFlow; + if (maxAirVolFlowInOut == DataSizing::AutoSize) { + this->m_RequestAutoSize = true; + } else { + if (maxAirVolFlowInOut <= HVAC::SmallAirVolFlow && ownCoilExists) { + ShowWarningError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); + ShowContinueError(state, EnergyPlus::format("Input for {} Supply Air Flow Rate Method = SupplyAirFlowRate.", modeName)); + ShowContinueError(state, + EnergyPlus::format("Suspicious {} Supply Air Flow Rate = {:.7R} when {} coil is present.", + modeName, + maxAirVolFlowInOut, + Util::makeUPPER(modeName))); + } + if (maxAirVolFlowInOut < 0.0) { + errorsFound = true; + } } + } else { + ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); + ShowContinueError(state, EnergyPlus::format("Input for {} Supply Air Flow Rate Method = SupplyAirFlowRate.", modeName)); + ShowContinueError(state, EnergyPlus::format("Blank field not allowed for {} Supply Air Flow Rate.", modeName)); + errorsFound = true; } - - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Cooling Supply Air Flow Rate Method = SupplyAirFlowRate."); - ShowContinueError(state, "Blank field not allowed for Cooling Supply Air Flow Rate."); - errorsFound = true; - } - } else if (Util::SameString(loc_m_CoolingSAFMethod, "FlowPerFloorArea")) { - - this->m_CoolingSAFMethod = DataSizing::FlowPerFloorArea; - if (loc_m_CoolingSAFMethod_SAFlowPerFloorArea != -999.0) { - this->m_MaxCoolAirVolFlow = loc_m_CoolingSAFMethod_SAFlowPerFloorArea; - if (this->m_MaxCoolAirVolFlow != DataSizing::AutoSize) { - if (this->m_MaxCoolAirVolFlow <= 0.0001 && this->m_CoolCoilExists) { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Cooling Supply Air Flow Rate Method = FlowPerFloorArea."); - ShowContinueError( - state, - EnergyPlus::format( - "Suspicious Cooling Supply Air Flow Rate Per Floor Area = {:.7R} [m3/s/m2] when cooling coil is present.", - this->m_MaxCoolAirVolFlow)); - if (this->m_MaxCoolAirVolFlow < 0.0) { - errorsFound = true; + } else if (Util::SameString(methodStr, "FlowPerFloorArea")) { + safMethodOut = DataSizing::FlowPerFloorArea; + if (localSAFlowPerFloorArea != -999.0) { + maxAirVolFlowInOut = localSAFlowPerFloorArea; + if (maxAirVolFlowInOut != DataSizing::AutoSize) { + if (maxAirVolFlowInOut <= 0.0001 && ownCoilExists) { + ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); + ShowContinueError(state, EnergyPlus::format("Input for {} Supply Air Flow Rate Method = FlowPerFloorArea.", modeName)); + ShowContinueError(state, + EnergyPlus::format("Suspicious {} Supply Air Flow Rate Per Floor Area = {:.7R} [m3/s/m2] " + "when {} coil is present.", + modeName, + maxAirVolFlowInOut, + Util::makeUPPER(modeName))); + if (maxAirVolFlowInOut < 0.0) { + errorsFound = true; + } } + maxAirVolFlowInOut *= TotalFloorAreaOnAirLoop; + this->m_RequestAutoSize = true; + } else { + ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); + ShowContinueError(state, EnergyPlus::format("Input for {} Supply Air Flow Rate Method = FlowPerFloorArea.", modeName)); + ShowContinueError(state, EnergyPlus::format("Illegal {} Supply Air Flow Rate Per Floor Area = Autosize", modeName)); + errorsFound = true; } - this->m_MaxCoolAirVolFlow *= TotalFloorAreaOnAirLoop; - this->m_RequestAutoSize = true; - // AutoSized input is not allowed } else { ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Cooling Supply Air Flow Rate Method = FlowPerFloorArea."); - ShowContinueError(state, "Illegal Cooling Supply Air Flow Rate Per Floor Area = Autosize"); + ShowContinueError(state, EnergyPlus::format("Input for {} Supply Air Flow Rate Method = FlowPerFloorArea.", modeName)); + ShowContinueError(state, EnergyPlus::format("Blank field not allowed for {} Supply Air Flow Rate Per Floor Area.", modeName)); errorsFound = true; } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Cooling Supply Air Flow Rate Method = FlowPerFloorArea."); - ShowContinueError(state, "Blank field not allowed for Cooling Supply Air Flow Rate Per Floor Area."); - errorsFound = true; - } - } else if (Util::SameString(loc_m_CoolingSAFMethod, "FractionOfAutosizedCoolingValue")) { - - this->m_CoolingSAFMethod = DataSizing::FractionOfAutosizedCoolingAirflow; - if (loc_m_CoolingSAFMethod_FracOfAutosizedCoolingSAFlow != -999.0) { - this->m_MaxCoolAirVolFlow = loc_m_CoolingSAFMethod_FracOfAutosizedCoolingSAFlow; - if (this->m_MaxCoolAirVolFlow != DataSizing::AutoSize) { - if (this->m_MaxCoolAirVolFlow <= HVAC::SmallAirVolFlow && this->m_CoolCoilExists) { + } else if (Util::SameString(methodStr, fracKey)) { + safMethodOut = static_cast(fracEnum); + if (localFracOfAutosized != -999.0) { + maxAirVolFlowInOut = localFracOfAutosized; + if (maxAirVolFlowInOut != DataSizing::AutoSize) { + if (maxAirVolFlowInOut <= HVAC::SmallAirVolFlow && ownCoilExists) { + ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); + ShowContinueError(state, EnergyPlus::format("Input for {} Supply Air Flow Rate Method = {}.", modeName, fracKey)); + ShowContinueError(state, + EnergyPlus::format("Suspicious {} Fraction of Autosized {} Supply Air Flow Rate = {:.7R} [m3/s/m3] " + "when {} coil is present.", + modeName, + modeName, + maxAirVolFlowInOut, + Util::makeUPPER(modeName))); + if (maxAirVolFlowInOut < 0.0) { + errorsFound = true; + } + } + this->m_RequestAutoSize = true; + } else { ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Cooling Supply Air Flow Rate Method = FractionOfAutosizedCoolingValue."); + ShowContinueError(state, EnergyPlus::format("Input for {} Supply Air Flow Rate Method = {}.", modeName, fracKey)); ShowContinueError( - state, - EnergyPlus::format("Suspicious Cooling Fraction of Autosized Cooling Supply Air Flow Rate = {:.7R} [m3/s/m3] " - "when cooling coil is present.", - this->m_MaxCoolAirVolFlow)); - if (this->m_MaxCoolAirVolFlow < 0.0) { - errorsFound = true; - } + state, EnergyPlus::format("Illegal {} Fraction of Autosized {} Supply Air Flow Rate = Autosize", modeName, modeName)); + errorsFound = true; } - this->m_RequestAutoSize = true; - // AutoSized input is not allowed } else { ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Cooling Supply Air Flow Rate Method = FractionOfAutosizedCoolingValue."); - ShowContinueError(state, "Illegal Cooling Fraction of Autosized Cooling Supply Air Flow Rate = Autosize"); + ShowContinueError(state, EnergyPlus::format("Input for {} Supply Air Flow Rate Method = {}.", modeName, fracKey)); + ShowContinueError( + state, + EnergyPlus::format("Blank field not allowed for {} Fraction of Autosized {} Supply Air Flow Rate.", modeName, modeName)); errorsFound = true; } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Cooling Supply Air Flow Rate Method = FractionOfAutosizedCoolingValue."); - ShowContinueError(state, "Blank field not allowed for Cooling Fraction of Autosized Cooling Supply Air Flow Rate."); - errorsFound = true; - } - } else if (Util::SameString(loc_m_CoolingSAFMethod, "FlowPerCoolingCapacity")) { - - this->m_CoolingSAFMethod = DataSizing::FlowPerCoolingCapacity; - if (loc_m_CoolingSAFMethod_FlowPerCoolingCapacity != -999.0) { - this->m_MaxCoolAirVolFlow = loc_m_CoolingSAFMethod_FlowPerCoolingCapacity; - if (this->m_MaxCoolAirVolFlow != DataSizing::AutoSize) { - if (this->m_MaxCoolAirVolFlow <= 0.00001 && this->m_CoolCoilExists) { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Cooling Supply Air Flow Rate Method = FlowPerCoolingCapacity."); - ShowContinueError(state, - EnergyPlus::format("Suspicious Cooling Supply Air Flow Rate Per Unit of Capacity = {:.7R} [m3/s/W] when " - "cooling coil is present.", - this->m_MaxCoolAirVolFlow)); - if (this->m_MaxCoolAirVolFlow < 0.0) { - errorsFound = true; + } else if (Util::SameString(methodStr, capKey)) { + safMethodOut = static_cast(capEnum); + if (localFlowPerCap != -999.0) { + maxAirVolFlowInOut = localFlowPerCap; + if (maxAirVolFlowInOut != DataSizing::AutoSize) { + if (maxAirVolFlowInOut <= 0.00001 && ownCoilExists) { + ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); + ShowContinueError(state, EnergyPlus::format("Input for {} Supply Air Flow Rate Method = {}.", modeName, capKey)); + ShowContinueError(state, + EnergyPlus::format("Suspicious {} Supply Air Flow Rate Per Unit of Capacity = {:.7R} [m3/s/W] " + "when {} coil is present.", + modeName, + maxAirVolFlowInOut, + Util::makeUPPER(modeName))); + if (maxAirVolFlowInOut < 0.0) { + errorsFound = true; + } } + this->m_RequestAutoSize = true; + } else { + ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); + ShowContinueError(state, EnergyPlus::format("Input for {} Supply Air Flow Rate Method = {}.", modeName, capKey)); + ShowContinueError(state, EnergyPlus::format("Illegal {} Supply Air Flow Rate Per Unit of Capacity = Autosize", modeName)); + errorsFound = true; } - this->m_RequestAutoSize = true; - // AutoSized input is not allowed } else { ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Cooling Supply Air Flow Rate Method = FlowPerCoolingCapacity."); - ShowContinueError(state, "Illegal Cooling Supply Air Flow Rate Per Unit of Capacity = Autosize"); + ShowContinueError(state, EnergyPlus::format("Input for {} Supply Air Flow Rate Method = {}.", modeName, capKey)); + ShowContinueError(state, + EnergyPlus::format("Blank field not allowed for {} Supply Air Flow Rate Per Unit of Capacity.", modeName)); errorsFound = true; } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Cooling Supply Air Flow Rate Method = FlowPerCoolingCapacity."); - ShowContinueError(state, "Blank field not allowed for Cooling Supply Air Flow Rate Per Unit of Capacity."); - errorsFound = true; } + }; - } else if (Util::SameString(loc_m_CoolingSAFMethod, "None") || loc_m_CoolingSAFMethod.empty()) { + // Determine supply air flow rate sizing method for cooling mode + parseCoolHeatSAFMethod(loc_m_CoolingSAFMethod, + "Cooling", + "FractionOfAutosizedCoolingValue", + "FlowPerCoolingCapacity", + DataSizing::FractionOfAutosizedCoolingAirflow, + DataSizing::FlowPerCoolingCapacity, + loc_m_CoolingSAFMethod_SAFlow, + loc_m_CoolingSAFMethod_SAFlowPerFloorArea, + loc_m_CoolingSAFMethod_FracOfAutosizedCoolingSAFlow, + loc_m_CoolingSAFMethod_FlowPerCoolingCapacity, + this->m_CoolingSAFMethod, + this->m_MaxCoolAirVolFlow, + this->m_CoolCoilExists); + if (Util::SameString(loc_m_CoolingSAFMethod, "None") || loc_m_CoolingSAFMethod.empty()) { this->m_CoolingSAFMethod = DataSizing::None; if (this->m_CoolCoilExists && this->m_MaxCoolAirVolFlow == 0) { ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); @@ -6058,140 +5958,94 @@ namespace UnitarySystems { } // Determine supply air flow rate sizing method for heating mode - if (Util::SameString(loc_m_HeatingSAFMethod, "SupplyAirFlowRate")) { - this->m_HeatingSAFMethod = DataSizing::SupplyAirFlowRate; - if (loc_m_HeatingSAFMethod_SAFlow != -999.0) { - this->m_MaxHeatAirVolFlow = loc_m_HeatingSAFMethod_SAFlow; - if (this->m_MaxHeatAirVolFlow == DataSizing::AutoSize) { - this->m_RequestAutoSize = true; + parseCoolHeatSAFMethod(loc_m_HeatingSAFMethod, + "Heating", + "FractionOfAutosizedHeatingValue", + "FlowPerHeatingCapacity", + DataSizing::FractionOfAutosizedHeatingAirflow, + DataSizing::FlowPerHeatingCapacity, + loc_m_HeatingSAFMethod_SAFlow, + loc_m_HeatingSAFMethod_SAFlowPerFloorArea, + loc_m_HeatingSAFMethod_FracOfAutosizedHeatingSAFlow, + loc_m_HeatingSAFMethod_FlowPerHeatingCapacity, + this->m_HeatingSAFMethod, + this->m_MaxHeatAirVolFlow, + this->m_HeatCoilExists); + if (Util::SameString(loc_m_HeatingSAFMethod, "None") || loc_m_HeatingSAFMethod.empty()) { + this->m_HeatingSAFMethod = DataSizing::None; + if (this->m_HeatCoilExists && this->m_MaxHeatAirVolFlow == 0) { + ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); + if (loc_m_HeatingSAFMethod.empty()) { + ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method is blank."); } else { - if (this->m_MaxHeatAirVolFlow <= HVAC::SmallAirVolFlow && this->m_HeatCoilExists) { - ShowWarningError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = SupplyAirFlowRate."); - ShowContinueError(state, - EnergyPlus::format("Suspicious Heating Supply Air Flow Rate = {:.7R} when heating coil is present.", - this->m_MaxHeatAirVolFlow)); - } - if (this->m_MaxHeatAirVolFlow < 0.0) { - errorsFound = true; - } + ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = None."); } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = SupplyAirFlowRate."); - ShowContinueError(state, "Blank field not allowed for Heating Supply Air Flow Rate."); - errorsFound = true; - } - } else if (Util::SameString(loc_m_HeatingSAFMethod, "FlowPerFloorArea")) { - this->m_HeatingSAFMethod = DataSizing::FlowPerFloorArea; - if (loc_m_HeatingSAFMethod_SAFlowPerFloorArea != -999.0) { - this->m_MaxHeatAirVolFlow = loc_m_HeatingSAFMethod_SAFlowPerFloorArea; - if (this->m_MaxHeatAirVolFlow != DataSizing::AutoSize) { - if (this->m_MaxHeatAirVolFlow <= 0.0001 && this->m_HeatCoilExists) { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = FlowPerFloorArea."); - ShowContinueError( - state, - EnergyPlus::format( - "Suspicious Heating Supply Air Flow Rate Per Floor Area = {:.7R} [m3/s/m2] when heating coil is present.", - this->m_MaxHeatAirVolFlow)); - } - if (this->m_MaxHeatAirVolFlow < 0.0) { - errorsFound = true; - } - this->m_MaxHeatAirVolFlow *= TotalFloorAreaOnAirLoop; - this->m_RequestAutoSize = true; + if (this->m_CoolCoilExists) { + ShowContinueError(state, "Blank field not allowed for this coil type when cooling coil air flow rate is not AutoSized."); } else { - // AutoSized input is not allowed - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = FlowPerFloorArea."); - ShowContinueError(state, "Illegal Heating Supply Air Flow Rate Per Floor Area = Autosize"); - errorsFound = true; + ShowContinueError(state, "Blank field not allowed for this type of heating coil."); } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = FlowPerFloorArea."); - ShowContinueError(state, "Blank field not allowed for Heating Supply Air Flow Rate Per Floor Area."); errorsFound = true; } - } else if (Util::SameString(loc_m_HeatingSAFMethod, "FractionOfAutosizedHeatingValue")) { - this->m_HeatingSAFMethod = DataSizing::FractionOfAutosizedHeatingAirflow; - if (loc_m_HeatingSAFMethod_FracOfAutosizedHeatingSAFlow != -999.0) { - this->m_MaxHeatAirVolFlow = loc_m_HeatingSAFMethod_FracOfAutosizedHeatingSAFlow; - if (this->m_MaxHeatAirVolFlow != DataSizing::AutoSize) { - if (this->m_MaxHeatAirVolFlow <= HVAC::SmallAirVolFlow && this->m_HeatCoilExists) { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = FractionOfAutosizedHeatingValue."); + } + + // Helper lambda for NoCoolHeat FractionOfAutosized* and FlowPerCapacity* branches + // which share the same logical structure, differing only in method name, operation, + // units label, suspicious-value threshold, coil-existence guard, and warning severity. + auto parseNoCoolHeatFracOrFlowBranch = [&](int safEnum, + Real64 localValue, + std::string_view methodName, + std::string_view opName, + std::string_view units, + Real64 threshold, + bool coilExists, + bool warnOnly) { + this->m_NoCoolHeatSAFMethod = safEnum; + if (localValue != -999.0) { + this->m_MaxNoCoolHeatAirVolFlow = localValue; + if (this->m_MaxNoCoolHeatAirVolFlow != DataSizing::AutoSize) { + if (this->m_MaxNoCoolHeatAirVolFlow <= threshold && coilExists) { + if (warnOnly) { + ShowWarningError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); + } else { + ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); + } + ShowContinueError(state, EnergyPlus::format("Input for No Load Supply Air Flow Rate Method = {}.", methodName)); ShowContinueError( state, - EnergyPlus::format("Suspicious Heating Fraction of Autosized Heating Supply Air Flow Rate = {:.7R} [m3/s/m3] " - "when heating coil is present.", - this->m_MaxHeatAirVolFlow)); - if (this->m_MaxHeatAirVolFlow < 0.0) { + EnergyPlus::format("Suspicious No Load Supply Air Flow Rate Per Unit of Capacity During {} Operation = {:.7R} {}.", + opName, + this->m_MaxNoCoolHeatAirVolFlow, + units)); + if (this->m_MaxNoCoolHeatAirVolFlow < 0.0) { errorsFound = true; } } this->m_RequestAutoSize = true; - // AutoSized input is not allowed } else { ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = FractionOfAutosizedHeatingValue"); - ShowContinueError(state, "Illegal input for Heating Fraction of Autosized Heating Supply Air Flow Rate = Autosize"); - errorsFound = true; - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = FractionOfAutosizedHeatingValue"); - ShowContinueError(state, "Blank field not allowed for Heating Fraction of Autosized Heating Supply Air Flow Rate"); - errorsFound = true; - } - } else if (Util::SameString(loc_m_HeatingSAFMethod, "FlowPerHeatingCapacity")) { - this->m_HeatingSAFMethod = DataSizing::FlowPerHeatingCapacity; - if (loc_m_HeatingSAFMethod_FlowPerHeatingCapacity != -999.0) { - this->m_MaxHeatAirVolFlow = loc_m_HeatingSAFMethod_FlowPerHeatingCapacity; - if (this->m_MaxHeatAirVolFlow != DataSizing::AutoSize) { - if (this->m_MaxHeatAirVolFlow <= 0.00001 && this->m_HeatCoilExists) { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = FlowPerHeatingCapacity."); - ShowContinueError(state, - EnergyPlus::format("Suspicious Heating Supply Air Flow Rate Per Unit of Capacity = {:.7R} [m3/s/W] when " - "heating coil is present.", - this->m_MaxHeatAirVolFlow)); - if (this->m_MaxHeatAirVolFlow < 0.0) { - errorsFound = true; - } + ShowContinueError(state, EnergyPlus::format("Input for No Load Supply Air Flow Rate Method = {}", methodName)); + if (warnOnly) { + ShowContinueError( + state, + EnergyPlus::format("Illegal input for No Load Supply Air Flow Rate Per Unit of Capacity During {} Operation = Autosize", + opName)); + } else { + ShowContinueError( + state, + EnergyPlus::format("Illegal No Load Supply Air Flow Rate Per Unit of Capacity During {} Operation = Autosize", opName)); } - this->m_RequestAutoSize = true; - // AutoSized input is not allowed - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = FlowPerHeatingCapacity."); - ShowContinueError(state, "Illegal Heating Supply Air Flow Rate Per Unit of Capacity = Autosize"); errorsFound = true; } } else { ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = FlowPerHeatingCapacity"); - ShowContinueError(state, "Blank field not allowed for Heating Supply Air Flow Rate Per Unit of Capacity"); - errorsFound = true; - } - } else if (Util::SameString(loc_m_HeatingSAFMethod, "None") || loc_m_HeatingSAFMethod.empty()) { - this->m_HeatingSAFMethod = DataSizing::None; - if (this->m_HeatCoilExists && this->m_MaxHeatAirVolFlow == 0) { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - if (loc_m_HeatingSAFMethod.empty()) { - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method is blank."); - } else { - ShowContinueError(state, "Input for Heating Supply Air Flow Rate Method = None."); - } - if (this->m_CoolCoilExists) { - ShowContinueError(state, "Blank field not allowed for this coil type when cooling coil air flow rate is not AutoSized."); - } else { - ShowContinueError(state, "Blank field not allowed for this type of heating coil."); - } + ShowContinueError(state, EnergyPlus::format("Input for No Load Supply Air Flow Rate Method = {}.", methodName)); + ShowContinueError( + state, + EnergyPlus::format("Blank field not allowed for No Load Supply Air Flow Rate Per Unit of Capacity During {} Operation", opName)); errorsFound = true; } - } + }; // Determine supply air flow rate sizing method when cooling or heating is not needed if (Util::SameString(loc_m_NoCoolHeatSAFMethod, "SupplyAirFlowRate")) { @@ -6247,148 +6101,58 @@ namespace UnitarySystems { errorsFound = true; } } else if (Util::SameString(loc_m_NoCoolHeatSAFMethod, "FractionOfAutosizedCoolingValue")) { - this->m_NoCoolHeatSAFMethod = DataSizing::FractionOfAutosizedCoolingAirflow; - if (loc_m_NoCoolHeatSAFMethod_FracOfAutosizedCoolingSAFlow != -999.0) { - this->m_MaxNoCoolHeatAirVolFlow = loc_m_NoCoolHeatSAFMethod_FracOfAutosizedCoolingSAFlow; - if (this->m_MaxNoCoolHeatAirVolFlow != DataSizing::AutoSize) { - if (this->m_MaxNoCoolHeatAirVolFlow <= HVAC::SmallAirVolFlow) { - ShowWarningError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FractionOfAutosizedCoolingValue."); - ShowContinueError( - state, - EnergyPlus::format( - "Suspicious No Load Supply Air Flow Rate Per Unit of Capacity During Cooling Operation = {:.7R} [m3/s/m3].", - this->m_MaxNoCoolHeatAirVolFlow)); - if (this->m_MaxNoCoolHeatAirVolFlow < 0.0) { - errorsFound = true; - } - } - this->m_RequestAutoSize = true; - // AutoSized input is not allowed - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FractionOfAutosizedCoolingValue"); - ShowContinueError(state, - "Illegal input for No Load Supply Air Flow Rate Per Unit of Capacity During Cooling Operation = Autosize"); - errorsFound = true; - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FractionOfAutosizedCoolingValue."); - ShowContinueError(state, "Blank field not allowed for No Load Supply Air Flow Rate Per Unit of Capacity During Cooling Operation"); - errorsFound = true; - } + parseNoCoolHeatFracOrFlowBranch(DataSizing::FractionOfAutosizedCoolingAirflow, + loc_m_NoCoolHeatSAFMethod_FracOfAutosizedCoolingSAFlow, + "FractionOfAutosizedCoolingValue", + "Cooling", + "[m3/s/m3]", + HVAC::SmallAirVolFlow, + true, + true); } else if (Util::SameString(loc_m_NoCoolHeatSAFMethod, "FractionOfAutosizedHeatingValue")) { - this->m_NoCoolHeatSAFMethod = DataSizing::FractionOfAutosizedHeatingAirflow; - if (loc_m_NoCoolHeatSAFMethod_FracOfAutosizedHeatingSAFlow != -999.0) { - this->m_MaxNoCoolHeatAirVolFlow = loc_m_NoCoolHeatSAFMethod_FracOfAutosizedHeatingSAFlow; - if (this->m_MaxNoCoolHeatAirVolFlow != DataSizing::AutoSize) { - if (this->m_MaxNoCoolHeatAirVolFlow <= HVAC::SmallAirVolFlow) { - ShowWarningError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FractionOfAutosizedHeatingValue."); - ShowContinueError( - state, - EnergyPlus::format( - "Suspicious No Load Supply Air Flow Rate Per Unit of Capacity During Heating Operation = {:.7R} [m3/s/m3].", - this->m_MaxNoCoolHeatAirVolFlow)); - if (this->m_MaxNoCoolHeatAirVolFlow < 0.0) { - errorsFound = true; - } - } + parseNoCoolHeatFracOrFlowBranch(DataSizing::FractionOfAutosizedHeatingAirflow, + loc_m_NoCoolHeatSAFMethod_FracOfAutosizedHeatingSAFlow, + "FractionOfAutosizedHeatingValue", + "Heating", + "[m3/s/m3]", + HVAC::SmallAirVolFlow, + true, + true); + } else if (Util::SameString(loc_m_NoCoolHeatSAFMethod, "FlowPerCoolingCapacity")) { + parseNoCoolHeatFracOrFlowBranch(DataSizing::FlowPerCoolingCapacity, + loc_m_NoCoolHeatSAFMethod_FlowPerCoolingCapacity, + "FlowPerCoolingCapacity", + "Cooling", + "[m3/s/W]", + 0.00001, + this->m_CoolCoilExists, + false); + } else if (Util::SameString(loc_m_NoCoolHeatSAFMethod, "FlowPerHeatingCapacity")) { + parseNoCoolHeatFracOrFlowBranch(DataSizing::FlowPerHeatingCapacity, + loc_m_NoCoolHeatSAFMethod_FlowPerHeatingCapacity, + "FlowPerHeatingCapacity", + "Heating", + "[m3/s/W]", + 0.00001, + this->m_HeatCoilExists, + false); + } else if (Util::SameString(loc_m_NoCoolHeatSAFMethod, "None") || loc_m_NoCoolHeatSAFMethod.empty()) { + this->m_NoCoolHeatSAFMethod = DataSizing::None; + if (this->m_ControlType == UnitarySysCtrlType::CCMASHRAE) { + if (loc_m_NoCoolHeatSAFMethod_SAFlow == -99999.0) { // no load air flow is autosized + this->m_MaxNoCoolHeatAirVolFlow = DataSizing::AutoSize; this->m_RequestAutoSize = true; - // AutoSized input is not allowed - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FractionOfAutosizedHeatingValue"); - ShowContinueError(state, - "Illegal input for No Load Supply Air Flow Rate Per Unit of Capacity During Heating Operation = Autosize"); - errorsFound = true; - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FractionOfAutosizedHeatingValue."); - ShowContinueError(state, "Blank field not allowed for No Load Supply Air Flow Rate Per Unit of Capacity During Heating Operation"); - errorsFound = true; - } - } else if (Util::SameString(loc_m_NoCoolHeatSAFMethod, "FlowPerCoolingCapacity")) { - this->m_NoCoolHeatSAFMethod = DataSizing::FlowPerCoolingCapacity; - if (loc_m_NoCoolHeatSAFMethod_FlowPerCoolingCapacity != -999.0) { - this->m_MaxNoCoolHeatAirVolFlow = loc_m_NoCoolHeatSAFMethod_FlowPerCoolingCapacity; - if (this->m_MaxNoCoolHeatAirVolFlow != DataSizing::AutoSize) { - if (this->m_MaxNoCoolHeatAirVolFlow <= 0.00001 && this->m_CoolCoilExists) { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FlowPerCoolingCapacity."); - ShowContinueError( - state, - EnergyPlus::format( - "Suspicious No Load Supply Air Flow Rate Per Unit of Capacity During Cooling Operation = {:.7R} [m3/s/W].", - this->m_MaxNoCoolHeatAirVolFlow)); - if (this->m_MaxNoCoolHeatAirVolFlow < 0.0) { - errorsFound = true; - } - } - this->m_RequestAutoSize = true; - // AutoSized input is not allowed - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FlowPerCoolingCapacity."); - ShowContinueError(state, "Illegal No Load Supply Air Flow Rate Per Unit of Capacity During Cooling Operation = Autosize"); - errorsFound = true; - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FlowPerCoolingCapacity."); - ShowContinueError(state, "Blank field not allowed for No Load Supply Air Flow Rate Per Unit of Capacity During Cooling Operation"); - errorsFound = true; - } - } else if (Util::SameString(loc_m_NoCoolHeatSAFMethod, "FlowPerHeatingCapacity")) { - this->m_NoCoolHeatSAFMethod = DataSizing::FlowPerHeatingCapacity; - if (loc_m_NoCoolHeatSAFMethod_FlowPerHeatingCapacity != -999.0) { - this->m_MaxNoCoolHeatAirVolFlow = loc_m_NoCoolHeatSAFMethod_FlowPerHeatingCapacity; - if (this->m_MaxNoCoolHeatAirVolFlow != DataSizing::AutoSize) { - if (this->m_MaxNoCoolHeatAirVolFlow <= 0.00001 && this->m_HeatCoilExists) { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FlowPerHeatingCapacity."); - ShowContinueError( - state, - EnergyPlus::format( - "Suspicious No Load Supply Air Flow Rate Per Unit of Capacity During Heating Operation = {:.7R} [m3/s/W].", - this->m_MaxNoCoolHeatAirVolFlow)); - if (this->m_MaxNoCoolHeatAirVolFlow < 0.0) { - errorsFound = true; - } - } - this->m_RequestAutoSize = true; - // AutoSized input is not allowed - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FlowPerHeatingCapacity."); - ShowContinueError(state, "Illegal No Load Supply Air Flow Rate Per Unit of Capacity During Heating Operation = Autosize"); - errorsFound = true; - } - } else { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate Method = FlowPerHeatingCapacity."); - ShowContinueError(state, "Blank field not allowed for No Load Supply Air Flow Rate Per Unit of Capacity During Heating Operation"); - errorsFound = true; - } - } else if (Util::SameString(loc_m_NoCoolHeatSAFMethod, "None") || loc_m_NoCoolHeatSAFMethod.empty()) { - this->m_NoCoolHeatSAFMethod = DataSizing::None; - if (this->m_ControlType == UnitarySysCtrlType::CCMASHRAE) { - if (loc_m_NoCoolHeatSAFMethod_SAFlow == -99999.0) { // no load air flow is autosized - this->m_MaxNoCoolHeatAirVolFlow = DataSizing::AutoSize; - this->m_RequestAutoSize = true; - } else if (loc_m_NoCoolHeatSAFMethod_SAFlow == -999.0) { // no load air flow is blank - this->m_MaxNoCoolHeatAirVolFlow = DataSizing::AutoSize; - this->m_RequestAutoSize = true; - ShowWarningError(state, EnergyPlus::format("Input errors for {}:{}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, EnergyPlus::format("Control Type = {}", input_data.control_type)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate cannot be blank."); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate has been set to AutoSize and the simulation continues."); - } else if (loc_m_NoCoolHeatSAFMethod_SAFlow == 0.0) { // no load air flow for SZVAV cannot be 0 - ShowSevereError(state, EnergyPlus::format("Input errors for {}:{}", cCurrentModuleObject, thisObjectName)); - ShowContinueError(state, EnergyPlus::format("Control Type = {}", input_data.control_type)); - ShowContinueError(state, "Input for No Load Supply Air Flow Rate cannot be 0."); + } else if (loc_m_NoCoolHeatSAFMethod_SAFlow == -999.0) { // no load air flow is blank + this->m_MaxNoCoolHeatAirVolFlow = DataSizing::AutoSize; + this->m_RequestAutoSize = true; + ShowWarningError(state, EnergyPlus::format("Input errors for {}:{}", cCurrentModuleObject, thisObjectName)); + ShowContinueError(state, EnergyPlus::format("Control Type = {}", input_data.control_type)); + ShowContinueError(state, "Input for No Load Supply Air Flow Rate cannot be blank."); + ShowContinueError(state, "Input for No Load Supply Air Flow Rate has been set to AutoSize and the simulation continues."); + } else if (loc_m_NoCoolHeatSAFMethod_SAFlow == 0.0) { // no load air flow for SZVAV cannot be 0 + ShowSevereError(state, EnergyPlus::format("Input errors for {}:{}", cCurrentModuleObject, thisObjectName)); + ShowContinueError(state, EnergyPlus::format("Control Type = {}", input_data.control_type)); + ShowContinueError(state, "Input for No Load Supply Air Flow Rate cannot be 0."); errorsFound = true; } } @@ -6837,56 +6601,31 @@ namespace UnitarySystems { } if (FanVolFlowRate != DataSizing::AutoSize && this->m_FanExists) { - if (FanVolFlowRate < this->m_MaxCoolAirVolFlow && this->m_MaxCoolAirVolFlow != DataSizing::AutoSize && this->m_CoolCoilExists) { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError( - state, - EnergyPlus::format( - "... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in cooling mode.", - FanVolFlowRate, - this->m_FanName)); - ShowContinueError(state, " The Cooling Supply Air Flow Rate is reset to the fan flow rate and the simulation continues."); - this->m_MaxCoolAirVolFlow = FanVolFlowRate; - this->m_DesignFanVolFlowRate = FanVolFlowRate; - } - if (FanVolFlowRate < this->m_MaxHeatAirVolFlow && this->m_MaxHeatAirVolFlow != DataSizing::AutoSize && this->m_HeatCoilExists) { - ShowSevereError(state, EnergyPlus::format("{} = {}", cCurrentModuleObject, thisObjectName)); - ShowContinueError( - state, - EnergyPlus::format( - "... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in heating mode.", - FanVolFlowRate, - this->m_FanName)); - ShowContinueError(state, " The Heating Supply Air Flow Rate is reset to the fan flow rate and the simulation continues."); - this->m_MaxHeatAirVolFlow = FanVolFlowRate; - this->m_DesignFanVolFlowRate = FanVolFlowRate; - } - } - - if (this->m_fanOpModeSched != nullptr) { - if (!this->m_fanOpModeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 0.0)) { - // set air flow control mode: - // m_AirFlowControl = UseCompFlow::On means operate at last cooling or heating air flow requested when compressor is off - // m_AirFlowControl = UseCompFlow::Off means operate at no load air flow value specified by user - // AirFlowControl only valid if fan opmode = ContFanCycComp - if (this->m_MaxNoCoolHeatAirVolFlow == 0.0) { - this->m_AirFlowControl = UseCompFlow::On; - } else { - this->m_AirFlowControl = UseCompFlow::Off; - } - } + checkCoilFlowVsFan(state, + cCurrentModuleObject, + thisObjectName, + FanVolFlowRate, + this->m_FanName, + this->m_DesignFanVolFlowRate, + this->m_MaxCoolAirVolFlow, + this->m_CoolCoilExists, + "Cooling"); + checkCoilFlowVsFan(state, + cCurrentModuleObject, + thisObjectName, + FanVolFlowRate, + this->m_FanName, + this->m_DesignFanVolFlowRate, + this->m_MaxHeatAirVolFlow, + this->m_HeatCoilExists, + "Heating"); } // Set minimum OAT for heat pump compressor operation in cooling mode // get from coil module errFlag = false; - if (this->m_CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) { - this->m_MinOATCompressorCooling = DXCoils::GetMinOATCompressor(state, this->m_CoolingCoilIndex, errFlag); - } else if (this->m_CoolingCoilType_Num == HVAC::CoilDX_CoolingTwoSpeed) { - this->m_MinOATCompressorCooling = DXCoils::GetMinOATCompressor(state, this->m_CoolingCoilIndex, errFlag); - } else if (this->m_CoolingCoilType_Num == HVAC::CoilDX_MultiSpeedCooling) { - this->m_MinOATCompressorCooling = DXCoils::GetMinOATCompressor(state, this->m_CoolingCoilIndex, errFlag); - } else if (this->m_CoolingCoilType_Num == HVAC::CoilDX_CoolingTwoStageWHumControl) { + if (this->m_CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed || this->m_CoolingCoilType_Num == HVAC::CoilDX_CoolingTwoSpeed || + this->m_CoolingCoilType_Num == HVAC::CoilDX_MultiSpeedCooling || this->m_CoolingCoilType_Num == HVAC::CoilDX_CoolingTwoStageWHumControl) { this->m_MinOATCompressorCooling = DXCoils::GetMinOATCompressor(state, this->m_CoolingCoilIndex, errFlag); } else if (this->m_CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) { this->m_MinOATCompressorCooling = VariableSpeedCoils::GetVSCoilMinOATCompressor(state, this->m_CoolingCoilIndex, errFlag); @@ -8177,8 +7916,7 @@ namespace UnitarySystems { this->controlUnitarySystemOutput( state, AirLoopNum, FirstHVACIteration, OnOffAirFlowRatio, ZoneLoad, FullSensibleOutput, HXUnitOn, CompressorOn); } - if (state.dataLoopNodes->Node(this->AirOutNode).MassFlowRate < HVAC::SmallMassFlow && this->m_sysType != SysType::PackagedAC && - this->m_sysType != SysType::PackagedHP && this->m_sysType != SysType::PackagedWSHP) { + if (state.dataLoopNodes->Node(this->AirOutNode).MassFlowRate < HVAC::SmallMassFlow && !this->isPackagedUnit()) { state.dataUnitarySystems->CoolingLoad = false; state.dataUnitarySystems->HeatingLoad = false; state.dataUnitarySystems->MoistureLoad = 0.0; @@ -8531,8 +8269,7 @@ namespace UnitarySystems { state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->ControlZoneNum).RemainingOutputReqToHeatSP; state.dataUnitarySystems->MoistureLoad = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(this->ControlZoneNum).RemainingOutputReqToDehumidSP; - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || - this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { // ZoneSysAvailManager is turning on sooner than PTUnit in UnitarySystem. Mimic PTUnit logic. if (state.dataUnitarySystems->QToCoolSetPt < 0.0 && state.dataHeatBalFanSys->TempControlType(this->ControlZoneNum) != HVAC::SetptType::SingleHeat) { @@ -9799,22 +9536,16 @@ namespace UnitarySystems { } else { Real64 par6 = state.dataUnitarySystems->CoolingLoad ? 1.0 : 0.0; - auto f = [&state, this, FirstHVACIteration, CompressorONFlag, ZoneLoad, par6, OnOffAirFlowRatio, HXUnitOn, AirLoopNum]( - Real64 const PartLoadRatio) { - return UnitarySys::calcUnitarySystemLoadResidual(state, - PartLoadRatio, - this->m_UnitarySysNum, - FirstHVACIteration, - // par 3 not used? - CompressorONFlag, - ZoneLoad, - par6, - 1.0, - OnOffAirFlowRatio, - HXUnitOn, - // par 10 not used - AirLoopNum); - }; + auto f = makeLoadResidualFunc(state, + this->m_UnitarySysNum, + FirstHVACIteration, + CompressorONFlag, + ZoneLoad, + par6, + 1.0, + OnOffAirFlowRatio, + HXUnitOn, + AirLoopNum); // Tolerance is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate General::SolveRoot(state, this->m_CoolConvTol, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0); @@ -9865,23 +9596,16 @@ namespace UnitarySystems { CompressorONFlag); } // Now solve again with tighter PLR limits - auto f2 = // (AUTO_OK_LAMBDA) - [&state, this, FirstHVACIteration, CompressorONFlag, ZoneLoad, par6, OnOffAirFlowRatio, HXUnitOn, AirLoopNum]( - Real64 const PartLoadRatio) { - return UnitarySys::calcUnitarySystemLoadResidual(state, - PartLoadRatio, - this->m_UnitarySysNum, - FirstHVACIteration, - // par 3 not used? - CompressorONFlag, - ZoneLoad, - par6, - 1.0, - OnOffAirFlowRatio, - HXUnitOn, - // par 10 not used - AirLoopNum); - }; + auto f2 = makeLoadResidualFunc(state, + this->m_UnitarySysNum, + FirstHVACIteration, + CompressorONFlag, + ZoneLoad, + par6, + 1.0, + OnOffAirFlowRatio, + HXUnitOn, + AirLoopNum); General::SolveRoot(state, this->m_HeatConvTol, MaxIter, SolFlag, HeatPLR, f2, TempMinPLR, TempMaxPLR); this->calcUnitarySystemToLoad(state, AirLoopNum, @@ -9946,23 +9670,16 @@ namespace UnitarySystems { TempSysOutput = TempSensOutput; } // Now solve again with tighter PLR limits - auto f2 = // (AUTO_OK_LAMBDA) - [&state, this, FirstHVACIteration, CompressorONFlag, ZoneLoad, par6, OnOffAirFlowRatio, HXUnitOn, AirLoopNum]( - Real64 const PartLoadRatio) { - return UnitarySys::calcUnitarySystemLoadResidual(state, - PartLoadRatio, - this->m_UnitarySysNum, - FirstHVACIteration, - // par 3 not used? - CompressorONFlag, - ZoneLoad, - par6, - 1.0, - OnOffAirFlowRatio, - HXUnitOn, - // par 10 not used - AirLoopNum); - }; + auto f2 = makeLoadResidualFunc(state, + this->m_UnitarySysNum, + FirstHVACIteration, + CompressorONFlag, + ZoneLoad, + par6, + 1.0, + OnOffAirFlowRatio, + HXUnitOn, + AirLoopNum); General::SolveRoot(state, this->m_CoolConvTol, MaxIter, SolFlag, CoolPLR, f2, TempMinPLR, TempMaxPLR); this->calcUnitarySystemToLoad(state, AirLoopNum, @@ -9979,40 +9696,11 @@ namespace UnitarySystems { } // IF(HeatingLoad)THEN if (SolFlag == -1) { if (std::abs(ZoneLoad - TempSensOutput) > HVAC::SmallLoad) { - if (this->MaxIterIndex == 0) { - ShowWarningMessage( - state, EnergyPlus::format("Coil control failed to converge for {}:{}", this->UnitType, this->Name)); - ShowContinueError(state, " Iteration limit exceeded in calculating system sensible part-load ratio."); - ShowContinueErrorTimeStamp( - state, - EnergyPlus::format("Sensible load to be met = {:.2T} (watts), sensible output = {:.2T} " - "(watts), and the simulation continues.", - ZoneLoad, - TempSensOutput)); - } - ShowRecurringWarningErrorAtEnd(state, - this->UnitType + " \"" + this->Name + - "\" - Iteration limit exceeded in calculating sensible part-load ratio error " - "continues. Sensible load statistics:", - this->MaxIterIndex, - ZoneLoad, - ZoneLoad); + warnPLRMaxIterExceeded( + state, this->UnitType, this->Name, "sensible", "Sensible", this->MaxIterIndex, ZoneLoad, TempSensOutput); } } else if (SolFlag == -2) { - if (this->RegulaFalsiFailedIndex == 0) { - ShowWarningMessage(state, EnergyPlus::format("Coil control failed for {}:{}", this->UnitType, this->Name)); - ShowContinueError(state, " sensible part-load ratio determined to be outside the range of 0-1."); - ShowContinueErrorTimeStamp( - state, - EnergyPlus::format("Sensible load to be met = {:.2T} (watts), and the simulation continues.", ZoneLoad)); - } - ShowRecurringWarningErrorAtEnd( - state, - this->UnitType + " \"" + this->Name + - "\" - sensible part-load ratio out of range error continues. Sensible load statistics:", - this->RegulaFalsiFailedIndex, - ZoneLoad, - ZoneLoad); + warnPLROutOfRange(state, this->UnitType, this->Name, "sensible", "Sensible", this->RegulaFalsiFailedIndex, ZoneLoad); } } else if (SolFlag == -2) { if (this->m_MultiOrVarSpeedCoolCoil) { @@ -10036,20 +9724,7 @@ namespace UnitarySystems { if ((state.dataUnitarySystems->HeatingLoad && ZoneLoad > SensOutputOff) || (state.dataUnitarySystems->CoolingLoad && ZoneLoad < SensOutputOff)) { // if this is still true then print valid warnings - if (this->RegulaFalsiFailedIndex == 0) { - ShowWarningMessage(state, EnergyPlus::format("Coil control failed for {}:{}", this->UnitType, this->Name)); - ShowContinueError(state, " sensible part-load ratio determined to be outside the range of 0-1."); - ShowContinueErrorTimeStamp( - state, - EnergyPlus::format("Sensible load to be met = {:.2T} (watts), and the simulation continues.", ZoneLoad)); - } - ShowRecurringWarningErrorAtEnd( - state, - this->UnitType + " \"" + this->Name + - "\" - sensible part-load ratio out of range error continues. Sensible load statistics:", - this->RegulaFalsiFailedIndex, - ZoneLoad, - ZoneLoad); + warnPLROutOfRange(state, this->UnitType, this->Name, "sensible", "Sensible", this->RegulaFalsiFailedIndex, ZoneLoad); } } // IF (SolFlag == -1) THEN } @@ -10325,22 +10000,8 @@ namespace UnitarySystems { par7 = 0.0; } // Tolerance is fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate - auto f = [&state, this, FirstHVACIteration, CompressorONFlag, par5, par7, OnOffAirFlowRatio, HXUnitOn, AirLoopNum]( - Real64 const PartLoadRatio) { - return UnitarySys::calcUnitarySystemLoadResidual(state, - PartLoadRatio, - this->m_UnitarySysNum, - FirstHVACIteration, - // par 3 not used? - CompressorONFlag, - par5, - 1.0, - par7, - OnOffAirFlowRatio, - HXUnitOn, - // par 10 not used - AirLoopNum); - }; + auto f = makeLoadResidualFunc( + state, this->m_UnitarySysNum, FirstHVACIteration, CompressorONFlag, par5, 1.0, par7, OnOffAirFlowRatio, HXUnitOn, AirLoopNum); General::SolveRoot(state, 0.001, MaxIter, SolFlagLat, PartLoadRatio, f, 0.0, 1.0); this->m_CoolingPartLoadFrac = PartLoadRatio; this->m_HeatingPartLoadFrac = HeatPLR; @@ -10420,27 +10081,8 @@ namespace UnitarySystems { par5 = state.dataUnitarySystems->MoistureLoad; par7 = 0.0; } - // // Tolerance is fraction of load, M - auto f = [&state, this, FirstHVACIteration, CompressorONFlag, OnOffAirFlowRatio, HXUnitOn, AirLoopNum, par5, par7]( - Real64 const PartLoadRatio) { - // TODO: The actual Par array being used here may have been altered through any of the sections above, and this line is not covered by - // a unit or integration test - // TODO: So I made some assumptions about the arguments. I'm not sure if ultimately this is even accessible, so maybe it doesn't - // matter. - return UnitarySys::calcUnitarySystemLoadResidual(state, - PartLoadRatio, - this->m_UnitarySysNum, - FirstHVACIteration, - // par 3 not used? - CompressorONFlag, - par5, - 1.0, - par7, - OnOffAirFlowRatio, - HXUnitOn, - // par 10 not used - AirLoopNum); - }; + auto f = makeLoadResidualFunc( + state, this->m_UnitarySysNum, FirstHVACIteration, CompressorONFlag, par5, 1.0, par7, OnOffAirFlowRatio, HXUnitOn, AirLoopNum); General::SolveRoot(state, 0.001, MaxIter, SolFlagLat, CoolPLR, f, TempMinPLR, TempMaxPLR); this->calcUnitarySystemToLoad(state, AirLoopNum, @@ -10456,53 +10098,32 @@ namespace UnitarySystems { CompressorONFlag); if (SolFlagLat == -1) { if (std::abs(state.dataUnitarySystems->MoistureLoad - TempLatOutput) > HVAC::SmallLoad) { - if (this->warnIndex.m_LatMaxIterIndex == 0) { - ShowWarningMessage(state, EnergyPlus::format("Coil control failed to converge for {}:{}", this->UnitType, this->Name)); - ShowContinueError(state, " Iteration limit exceeded in calculating system Latent part-load ratio."); - ShowContinueErrorTimeStamp( - state, - EnergyPlus::format( - "Latent load to be met = {:.2T} (watts), Latent output = {:.2T} (watts), and the simulation continues.", - state.dataUnitarySystems->MoistureLoad, - TempLatOutput)); - } - ShowRecurringWarningErrorAtEnd( - state, - this->UnitType + " \"" + this->Name + - "\" - Iteration limit exceeded in calculating Latent part-load ratio error continues. Latent load statistics:", - this->warnIndex.m_LatMaxIterIndex, - state.dataUnitarySystems->MoistureLoad, - state.dataUnitarySystems->MoistureLoad); + warnPLRMaxIterExceeded(state, + this->UnitType, + this->Name, + "Latent", + "Latent", + this->warnIndex.m_LatMaxIterIndex, + state.dataUnitarySystems->MoistureLoad, + TempLatOutput); } } else if (SolFlagLat == -2) { - if (this->warnIndex.m_LatRegulaFalsiFailedIndex == 0) { - ShowWarningMessage(state, EnergyPlus::format("Coil control failed for {}:{}", this->UnitType, this->Name)); - ShowContinueError(state, " Latent part-load ratio determined to be outside the range of 0-1."); - ShowContinueErrorTimeStamp(state, - EnergyPlus::format("Latent load to be met = {:.2T} (watts), and the simulation continues.", - state.dataUnitarySystems->MoistureLoad)); - } - ShowRecurringWarningErrorAtEnd(state, - this->UnitType + " \"" + this->Name + - "\" - Latent part-load ratio out of range error continues. Latent load statistics:", - this->warnIndex.m_LatRegulaFalsiFailedIndex, - state.dataUnitarySystems->MoistureLoad, - state.dataUnitarySystems->MoistureLoad); + warnPLROutOfRange(state, + this->UnitType, + this->Name, + "Latent", + "Latent", + this->warnIndex.m_LatRegulaFalsiFailedIndex, + state.dataUnitarySystems->MoistureLoad); } } else if (SolFlagLat == -2) { - if (this->warnIndex.m_LatRegulaFalsiFailedIndex == 0) { - ShowWarningMessage(state, EnergyPlus::format("Coil control failed for {}:{}", this->UnitType, this->Name)); - ShowContinueError(state, " Latent part-load ratio determined to be outside the range of 0-1."); - ShowContinueErrorTimeStamp(state, - EnergyPlus::format("Latent load to be met = {:.2T} (watts), and the simulation continues.", - state.dataUnitarySystems->MoistureLoad)); - } - ShowRecurringWarningErrorAtEnd(state, - this->UnitType + " \"" + this->Name + - "\" - Latent part-load ratio out of range error continues. Latent load statistics:", - this->warnIndex.m_LatRegulaFalsiFailedIndex, - state.dataUnitarySystems->MoistureLoad, - state.dataUnitarySystems->MoistureLoad); + warnPLROutOfRange(state, + this->UnitType, + this->Name, + "Latent", + "Latent", + this->warnIndex.m_LatRegulaFalsiFailedIndex, + state.dataUnitarySystems->MoistureLoad); } FullSensibleOutput = TempSensOutput; @@ -10706,8 +10327,7 @@ namespace UnitarySystems { Real64 TotalOutputDelta = 0.0; // delta total output rate, {W} int ZoneInNode = this->m_ZoneInletNode; Real64 MassFlowRate = state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / this->ControlZoneMassFlowFrac; - if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP && - this->m_sysType != SysType::PackagedWSHP) { + if (state.afn->distribution_simulated && !this->isPackagedUnit()) { DeltaMassRate = state.dataLoopNodes->Node(this->AirOutNode).MassFlowRate - state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / this->ControlZoneMassFlowFrac; if (DeltaMassRate < 0.0) { @@ -10773,7 +10393,7 @@ namespace UnitarySystems { state.dataUnitarySystems->CoolingLoad = false; state.dataUnitarySystems->HeatingLoad = false; Real64 smallLoadTolerance = this->m_SmallLoadTolerance; - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { smallLoadTolerance = HVAC::SmallLoad; } if (QZnReq > smallLoadTolerance) { // no need to check deadband flag, QZnReq is correct. @@ -10790,7 +10410,7 @@ namespace UnitarySystems { if (this->m_FanOpMode == HVAC::FanOp::Continuous) { bool HXUnitOn = false; this->FanPartLoadRatio = 0.0; // sets fan to minimum for ASHRAE model - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { // the SpeedNum is set for PTUnits, might need to set this for all multi/var speed coils? if (state.dataUnitarySystems->CoolingLoad && this->m_MultiOrVarSpeedCoolCoil) { m_CoolingSpeedNum = 1; @@ -11119,8 +10739,7 @@ namespace UnitarySystems { } state.dataUnitarySystems->OACompOnMassFlow = this->m_HeatOutAirMassFlow; // only used for PTUnit to UnitarySystem conversion, should use all the time - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || - this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { state.dataUnitarySystems->OACompOffMassFlow = this->m_HeatOutAirMassFlow; } } @@ -11133,8 +10752,7 @@ namespace UnitarySystems { state.dataUnitarySystems->CompOffFlowRatio = this->m_MSHeatingSpeedRatio[HeatSpeedNum - 1]; } // only used for PTUnit to UnitarySystem conversion, should use all the time - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || - this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { state.dataUnitarySystems->OACompOnMassFlow = this->m_HeatOutAirMassFlow; // does this assume OA flow <= min speed flow? without this there are SolveRoot failures. if (HeatSpeedNum > 1) { @@ -11168,8 +10786,7 @@ namespace UnitarySystems { } state.dataUnitarySystems->OACompOnMassFlow = this->m_CoolOutAirMassFlow; } else { // Heating load but no moisture load - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || - this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { // this was missing for heating mode where multi speed coils are used if (this->m_MultiOrVarSpeedHeatCoil) { if (HeatSpeedNum == 0) { @@ -11365,8 +10982,7 @@ namespace UnitarySystems { } // this needs to happen regardless of system except maybe the CoilSystem objects // do this only for PTUnit for the time being to reduce diffs for the PTUnit to UnitarySystem conversion - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || - this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { if (this->m_FanOpMode == HVAC::FanOp::Continuous) { if (this->m_AirFlowControl == UseCompFlow::On) { state.dataUnitarySystems->CompOffMassFlow = this->MaxNoCoolHeatAirMassFlow; @@ -11445,8 +11061,7 @@ namespace UnitarySystems { } else { // this is a no load case, added if for PTUnit to correct this for PTUnit to UnitarySystem conversion // the else is incorrect? - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || - this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { if (this->m_FanOpMode == HVAC::FanOp::Continuous) { if (this->m_AirFlowControl == UseCompFlow::On) { state.dataUnitarySystems->CompOffMassFlow = this->MaxNoCoolHeatAirMassFlow; @@ -11507,8 +11122,7 @@ namespace UnitarySystems { } // No Heating/Cooling Load if (this->m_FanOpMode == HVAC::FanOp::Continuous) { - if (this->m_AirFlowControl == UseCompFlow::On && - (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP)) { + if (this->m_AirFlowControl == UseCompFlow::On && this->isPackagedUnit()) { if (this->m_LastMode == HeatingMode) { state.dataUnitarySystems->OACompOffMassFlow = this->m_HeatOutAirMassFlow; } else { @@ -12440,7 +12054,7 @@ namespace UnitarySystems { case HVAC::Coil_HeatingSteam: { // this same CALL is made in the steam coil calc routine mdot = min(state.dataLoopNodes->Node(this->HeatCoilFluidOutletNodeNum).MassFlowRateMaxAvail, this->MaxHeatCoilFluidFlow * PartLoadRatio); - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { // tried this to resolve the PackagedTerminalAirConditioner steam spike issue, no help, but this is the correct way to do this PlantUtilities::SetComponentFlowRate( state, mdot, this->HeatCoilFluidInletNode, this->HeatCoilFluidOutletNodeNum, this->HeatCoilPlantLoc); @@ -12462,7 +12076,7 @@ namespace UnitarySystems { HeatPLR = PartLoadRatio; } else if (this->m_HeatingSpeedNum > 1) { HeatPLR = 1.0; - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { this->m_HeatingSpeedRatio = PartLoadRatio; } } else { @@ -12702,6 +12316,189 @@ namespace UnitarySystems { } } + // Helper: wraps DXCoilVarSpeedResidual lambda + SolveRoot pattern used in controlCoolingSystemToSP. + static void solveForVarSpeedRatio(EnergyPlusData &state, + Real64 const Acc, + int const MaxIte, + int &SolFla, + Real64 &SpeedRatio, + int const CoilIndex, + Real64 const DesOutTemp, + int const SysNum, + Real64 const CycRatio, + int const SpeedNum, + HVAC::FanOp const FanOpMode, + HVAC::CompressorOp const CompOp) + { + auto f = [&state, CoilIndex, DesOutTemp, SysNum, CycRatio, SpeedNum, FanOpMode, CompOp](Real64 const SR) { + return UnitarySys::DXCoilVarSpeedResidual(state, SR, CoilIndex, DesOutTemp, SysNum, CycRatio, SpeedNum, FanOpMode, CompOp); + }; + General::SolveRoot(state, Acc, MaxIte, SolFla, SpeedRatio, f, 0.0, 1.0); + } + + // Helper: wraps DXCoilCyclingResidual lambda + SolveRoot pattern used in controlCoolingSystemToSP. + static void solveForCyclingRatio(EnergyPlusData &state, + Real64 const Acc, + int const MaxIte, + int &SolFla, + Real64 &CycRatio, + int const CoilIndex, + Real64 const DesOutTemp, + int const SysNum, + Real64 const SpeedRatio, + int const SpeedNum, + HVAC::FanOp const FanOpMode, + HVAC::CompressorOp const CompOp, + int const AirLoopNum, + bool const FirstHVACIteration) + { + auto f = [&state, CoilIndex, DesOutTemp, SysNum, SpeedRatio, SpeedNum, FanOpMode, CompOp, AirLoopNum, FirstHVACIteration](Real64 const CR) { + return UnitarySys::DXCoilCyclingResidual( + state, CR, CoilIndex, DesOutTemp, SysNum, SpeedRatio, SpeedNum, FanOpMode, CompOp, AirLoopNum, FirstHVACIteration); + }; + General::SolveRoot(state, Acc, MaxIte, SolFla, CycRatio, f, 0.0, 1.0); + } + + // Helper: wraps DXCoilVarSpeedHumRatResidual lambda + SolveRoot pattern. + static void solveForVarSpeedHumRat(EnergyPlusData &state, + Real64 const Acc, + int const MaxIte, + int &SolFla, + Real64 &SpeedRatio, + int const CoilIndex, + Real64 const DesOutHumRat, + int const SysNum, + Real64 const CycRatio, + int const SpeedNum, + HVAC::FanOp const FanOpMode, + HVAC::CompressorOp const CompOp) + { + auto f = [&state, CoilIndex, DesOutHumRat, SysNum, CycRatio, SpeedNum, FanOpMode, CompOp](Real64 const SR) { + return UnitarySys::DXCoilVarSpeedHumRatResidual(state, SR, CoilIndex, DesOutHumRat, SysNum, CycRatio, SpeedNum, FanOpMode, CompOp); + }; + General::SolveRoot(state, Acc, MaxIte, SolFla, SpeedRatio, f, 0.0, 1.0); + } + + // Helper: wraps DXCoilCyclingHumRatResidual lambda + SolveRoot pattern. + static void solveForCyclingHumRat(EnergyPlusData &state, + Real64 const Acc, + int const MaxIte, + int &SolFla, + Real64 &CycRatio, + int const CoilIndex, + Real64 const DesOutHumRat, + int const SysNum, + Real64 const SpeedRatio, + int const SpeedNum, + HVAC::FanOp const FanOpMode, + HVAC::CompressorOp const CompOp) + { + auto f = [&state, CoilIndex, DesOutHumRat, SysNum, SpeedRatio, SpeedNum, FanOpMode, CompOp](Real64 const CR) { + return UnitarySys::DXCoilCyclingHumRatResidual(state, CR, CoilIndex, DesOutHumRat, SysNum, SpeedRatio, SpeedNum, FanOpMode, CompOp); + }; + General::SolveRoot(state, Acc, MaxIte, SolFla, CycRatio, f, 0.0, 1.0); + } + + // Helper: wraps the repeated SimHXAssistedCoolingCoil call pattern used throughout controlCoolingSystemToSP. + // All calls share the same argument list except for the part-load ratio. + static void simHXAssistedCooling(EnergyPlusData &state, + std::string const &CompName, + bool const FirstHVACIteration, + Real64 const PartLoadFrac, + int &CoolingCoilIndex, + HVAC::FanOp const fanOp, + bool const HXUnitOn, + HVAC::CoilMode const DehumidificationMode) + { + HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state, + CompName, + FirstHVACIteration, + HVAC::CompressorOp::On, + PartLoadFrac, + CoolingCoilIndex, + fanOp, + HXUnitOn, + _, + state.dataUnitarySystems->economizerFlag, + _, + DehumidificationMode, + 0.0); + } + + // Helper: handles the humidity control logic for DX MultiSpeed coils (TwoSpeed and MultiSpeed). + // After the sensible solve, if the outlet humidity ratio exceeds the setpoint, + // this routine re-simulates at low and high speeds and solves for the speed/cycling + // ratios that meet the humidity ratio setpoint. + static void dxMultiSpeedHumRatControl(EnergyPlusData &state, + std::string const &CompName, + int coilIndex, + Real64 DesOutHumRat, + Real64 &SpeedRatio, + Real64 &CycRatio, + Real64 &PartLoadFrac, + int unitarySysNum, + Real64 cycSolSpeedRatio, + int cycSolSpeedNum, + HVAC::FanOp cycSolFanOp, + bool updatePartLoadFrac) + { + int constexpr MaxIte(500); + Real64 constexpr HumRatAcc(1.e-6); + int SolFla = 0; + + Real64 OutletHumRatDXCoil = state.dataDXCoils->DXCoilOutletHumRat(coilIndex); + if (OutletHumRatDXCoil <= DesOutHumRat) { + return; + } + + CycRatio = 0.0; + SpeedRatio = 0.0; + + DXCoils::SimDXCoilMultiSpeed(state, CompName, 0.0, 1.0, coilIndex); + Real64 OutletHumRatLS = state.dataDXCoils->DXCoilOutletHumRat(coilIndex); + if (OutletHumRatLS > DesOutHumRat) { + CycRatio = 1.0; + DXCoils::SimDXCoilMultiSpeed(state, CompName, 1.0, 1.0, coilIndex); + Real64 OutletHumRatHS = state.dataDXCoils->DXCoilOutletHumRat(coilIndex); + if (OutletHumRatHS < DesOutHumRat) { + solveForVarSpeedHumRat(state, + HumRatAcc, + MaxIte, + SolFla, + SpeedRatio, + coilIndex, + DesOutHumRat, + unitarySysNum, + 0.0, + 0, + HVAC::FanOp::Invalid, + HVAC::CompressorOp::On); + } else { + SpeedRatio = 1.0; + } + if (updatePartLoadFrac) { + PartLoadFrac = SpeedRatio; + } + } else { + SpeedRatio = 0.0; + solveForCyclingHumRat(state, + HumRatAcc, + MaxIte, + SolFla, + CycRatio, + coilIndex, + DesOutHumRat, + unitarySysNum, + cycSolSpeedRatio, + cycSolSpeedNum, + cycSolFanOp, + HVAC::CompressorOp::On); + if (updatePartLoadFrac) { + PartLoadFrac = CycRatio; + } + } + } + void UnitarySys::controlCoolingSystemToSP(EnergyPlusData &state, int const AirLoopNum, // index to air loop bool const FirstHVACIteration, // First HVAC iteration flag @@ -12748,8 +12545,7 @@ namespace UnitarySystems { Real64 DesOutHumRat = this->m_DesiredOutletHumRat; int CoilType_Num = this->m_CoolingCoilType_Num; Real64 LoopDXCoilMaxRTFSave = 0.0; - if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP && - this->m_sysType != SysType::PackagedWSHP) { + if (state.afn->distribution_simulated && !this->isPackagedUnit()) { LoopDXCoilMaxRTFSave = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF; state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF = 0.0; } @@ -12991,19 +12787,8 @@ namespace UnitarySystems { state.dataLoopNodes->Node(this->CoolCoilFluidInletNode).MassFlowRate = 0.0; } - HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state, - CompName, - FirstHVACIteration, - HVAC::CompressorOp::On, - PartLoadFrac, - this->m_CoolingCoilIndex, - fanOp, - HXUnitOn, - _, - state.dataUnitarySystems->economizerFlag, - _, - this->m_DehumidificationMode, - 0.0); // this->CoilSHR); + simHXAssistedCooling( + state, CompName, FirstHVACIteration, PartLoadFrac, this->m_CoolingCoilIndex, fanOp, HXUnitOn, this->m_DehumidificationMode); if (CoilType_Num == HVAC::CoilDX_CoolingHXAssisted) { this->m_CompPartLoadRatio = PartLoadFrac; } @@ -13149,19 +12934,14 @@ namespace UnitarySystems { if (this->CoolCoilFluidInletNode > 0) { state.dataLoopNodes->Node(this->CoolCoilFluidInletNode).MassFlowRate = max(0.0, this->MaxCoolCoilFluidFlow); } - HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state, - CompName, - FirstHVACIteration, - HVAC::CompressorOp::On, - PartLoadFrac, - this->m_CoolingCoilIndex, - fanOp, - HXUnitOn, - _, - state.dataUnitarySystems->economizerFlag, - _, - this->m_DehumidificationMode, - 0.0); // this->CoilSHR); + simHXAssistedCooling(state, + CompName, + FirstHVACIteration, + PartLoadFrac, + this->m_CoolingCoilIndex, + fanOp, + HXUnitOn, + this->m_DehumidificationMode); if (CoilType_Num == HVAC::CoilDX_CoolingHXAssisted) { this->m_CompPartLoadRatio = PartLoadFrac; @@ -13424,19 +13204,14 @@ namespace UnitarySystems { while ((TempOutletTempDXCoil - DesOutTemp) > 0.0 && TempMaxPLR <= 1.0) { // find upper limit of PLR TempMaxPLR += 0.1; - HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state, - CompName, - FirstHVACIteration, - HVAC::CompressorOp::On, - TempMaxPLR, - this->m_CoolingCoilIndex, - fanOp, - HXUnitOn, - _, - state.dataUnitarySystems->economizerFlag, - _, - this->m_DehumidificationMode, - 0.0); // this->CoilSHR); + simHXAssistedCooling(state, + CompName, + FirstHVACIteration, + TempMaxPLR, + this->m_CoolingCoilIndex, + fanOp, + HXUnitOn, + this->m_DehumidificationMode); TempOutletTempDXCoil = state.dataHVACAssistedCC->HXAssistedCoilOutletTemp(this->m_CoolingCoilIndex); } TempMinPLR = TempMaxPLR; @@ -13445,19 +13220,14 @@ namespace UnitarySystems { TempMaxPLR = TempMinPLR; // find minimum limit of PLR TempMinPLR -= 0.01; - HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state, - CompName, - FirstHVACIteration, - HVAC::CompressorOp::On, - TempMinPLR, - this->m_CoolingCoilIndex, - fanOp, - HXUnitOn, - _, - state.dataUnitarySystems->economizerFlag, - _, - this->m_DehumidificationMode, - 0.0); // this->CoilSHR); + simHXAssistedCooling(state, + CompName, + FirstHVACIteration, + TempMinPLR, + this->m_CoolingCoilIndex, + fanOp, + HXUnitOn, + this->m_DehumidificationMode); TempOutletTempDXCoil = state.dataHVACAssistedCC->HXAssistedCoilOutletTemp(this->m_CoolingCoilIndex); } // Relax boundary slightly to assure a solution can be found using RegulaFalsi (i.e. one boundary may @@ -13547,76 +13317,70 @@ namespace UnitarySystems { } else if (CoilType_Num == HVAC::CoilDX_CoolingTwoSpeed) { this->m_CoolingSpeedRatio = SpeedRatio; if (SpeedRatio == 1.0) { - auto f = [&state, this, DesOutTemp](Real64 const SpeedRatio) { - int par1 = this->m_CoolingCoilIndex; - Real64 par2 = DesOutTemp; - int par3 = this->m_UnitarySysNum; - // 4-7 are not used for TwoSpeed coils, so these shouldn't matter at all - Real64 par4_CycRatio = 0.0; - int par5_SpeedNum = 0.0; - HVAC::FanOp par6_FanOpMode = HVAC::FanOp::Invalid; - HVAC::CompressorOp par7_CompressorOp = HVAC::CompressorOp::On; - return UnitarySys::DXCoilVarSpeedResidual( - state, SpeedRatio, par1, par2, par3, par4_CycRatio, par5_SpeedNum, par6_FanOpMode, par7_CompressorOp); - }; - General::SolveRoot(state, Acc, MaxIte, SolFla, SpeedRatio, f, 0.0, 1.0); + solveForVarSpeedRatio(state, + Acc, + MaxIte, + SolFla, + SpeedRatio, + this->m_CoolingCoilIndex, + DesOutTemp, + this->m_UnitarySysNum, + 0.0, + 0, + HVAC::FanOp::Invalid, + HVAC::CompressorOp::On); PartLoadFrac = SpeedRatio; } else { - auto f = [&state, this, DesOutTemp, AirLoopNum, FirstHVACIteration](Real64 const CycRatio) { - // several pars are not used in two speed coils, so these are just dummy values - Real64 par4_SpeedRatio = 0.0; - int par5_SpeedNum = 0.0; - HVAC::FanOp par6_FanOpMode = HVAC::FanOp::Invalid; - HVAC::CompressorOp par7_compressorOp = HVAC::CompressorOp::On; - return UnitarySys::DXCoilCyclingResidual(state, - CycRatio, - this->m_CoolingCoilIndex, - DesOutTemp, - this->m_UnitarySysNum, - par4_SpeedRatio, - par5_SpeedNum, - par6_FanOpMode, - par7_compressorOp, - AirLoopNum, - FirstHVACIteration); - }; - General::SolveRoot(state, Acc, MaxIte, SolFla, CycRatio, f, 0.0, 1.0); + solveForCyclingRatio(state, + Acc, + MaxIte, + SolFla, + CycRatio, + this->m_CoolingCoilIndex, + DesOutTemp, + this->m_UnitarySysNum, + 0.0, + 0, + HVAC::FanOp::Invalid, + HVAC::CompressorOp::On, + AirLoopNum, + FirstHVACIteration); PartLoadFrac = CycRatio; } } else if (CoilType_Num == HVAC::CoilDX_MultiSpeedCooling) { if (this->m_CoolingSpeedNum > 1.0) { - auto f = [&state, this, DesOutTemp, CycRatio](Real64 const SpeedRatio) { - int par1 = this->m_CoolingCoilIndex; - Real64 par2 = DesOutTemp; - int par3 = this->m_UnitarySysNum; - Real64 par4_CycRatio = CycRatio; - int par5_SpeedNum = this->m_CoolingSpeedNum; - HVAC::FanOp par6_FanOpMode = HVAC::FanOp::Cycling; - HVAC::CompressorOp par7_CompressorOp = HVAC::CompressorOp::On; - return UnitarySys::DXCoilVarSpeedResidual( - state, SpeedRatio, par1, par2, par3, par4_CycRatio, par5_SpeedNum, par6_FanOpMode, par7_CompressorOp); - }; - General::SolveRoot(state, Acc, MaxIte, SolFla, SpeedRatio, f, 0.0, 1.0); + solveForVarSpeedRatio(state, + Acc, + MaxIte, + SolFla, + SpeedRatio, + this->m_CoolingCoilIndex, + DesOutTemp, + this->m_UnitarySysNum, + CycRatio, + this->m_CoolingSpeedNum, + HVAC::FanOp::Cycling, + HVAC::CompressorOp::On); PartLoadFrac = SpeedRatio; } else { SpeedRatio = 0.0; this->m_CoolingSpeedRatio = SpeedRatio; - auto f = [&state, this, DesOutTemp, SpeedRatio, AirLoopNum, FirstHVACIteration](Real64 const CycRatio) { - return UnitarySys::DXCoilCyclingResidual(state, - CycRatio, - this->m_CoolingCoilIndex, - DesOutTemp, - this->m_UnitarySysNum, - SpeedRatio, - this->m_CoolingSpeedNum, - HVAC::FanOp::Cycling, - HVAC::CompressorOp::On, - AirLoopNum, - FirstHVACIteration); - }; - General::SolveRoot(state, Acc, MaxIte, SolFla, CycRatio, f, 0.0, 1.0); + solveForCyclingRatio(state, + Acc, + MaxIte, + SolFla, + CycRatio, + this->m_CoolingCoilIndex, + DesOutTemp, + this->m_UnitarySysNum, + SpeedRatio, + this->m_CoolingSpeedNum, + HVAC::FanOp::Cycling, + HVAC::CompressorOp::On, + AirLoopNum, + FirstHVACIteration); PartLoadFrac = CycRatio; } @@ -13627,38 +13391,38 @@ namespace UnitarySystems { SpeedRatio = 1.0; if (this->m_CoolingSpeedNum > 1.0) { - auto f = [&state, this, DesOutTemp, CycRatio](Real64 const SpeedRatio) { - int par1 = this->m_CoolingCoilIndex; - Real64 par2 = DesOutTemp; - int par3 = this->m_UnitarySysNum; - Real64 par4_CycRatio = CycRatio; - int par5_SpeedNum = this->m_CoolingSpeedNum; - HVAC::FanOp par6_FanOpMode = this->m_FanOpMode; - HVAC::CompressorOp par7_CompressorOp = HVAC::CompressorOp::On; - return UnitarySys::DXCoilVarSpeedResidual( - state, SpeedRatio, par1, par2, par3, par4_CycRatio, par5_SpeedNum, par6_FanOpMode, par7_CompressorOp); - }; - General::SolveRoot(state, Acc, MaxIte, SolFla, SpeedRatio, f, 0.0, 1.0); + solveForVarSpeedRatio(state, + Acc, + MaxIte, + SolFla, + SpeedRatio, + this->m_CoolingCoilIndex, + DesOutTemp, + this->m_UnitarySysNum, + CycRatio, + this->m_CoolingSpeedNum, + this->m_FanOpMode, + HVAC::CompressorOp::On); this->m_CoolingCycRatio = CycRatio; this->m_CoolingSpeedRatio = SpeedRatio; this->m_CoolingPartLoadFrac = SpeedRatio; PartLoadFrac = SpeedRatio; } else { this->m_CoolingSpeedRatio = SpeedRatio; - auto f = [&state, this, DesOutTemp, SpeedRatio, AirLoopNum, FirstHVACIteration](Real64 const CycRatio) { - return UnitarySys::DXCoilCyclingResidual(state, - CycRatio, - this->m_CoolingCoilIndex, - DesOutTemp, - this->m_UnitarySysNum, - SpeedRatio, - this->m_CoolingSpeedNum, - this->m_FanOpMode, - HVAC::CompressorOp::On, - AirLoopNum, - FirstHVACIteration); - }; - General::SolveRoot(state, Acc, MaxIte, SolFla, CycRatio, f, 0.0, 1.0); + solveForCyclingRatio(state, + Acc, + MaxIte, + SolFla, + CycRatio, + this->m_CoolingCoilIndex, + DesOutTemp, + this->m_UnitarySysNum, + SpeedRatio, + this->m_CoolingSpeedNum, + this->m_FanOpMode, + HVAC::CompressorOp::On, + AirLoopNum, + FirstHVACIteration); SpeedRatio = 0.0; this->m_CoolingCycRatio = CycRatio; this->m_CoolingPartLoadFrac = CycRatio; @@ -13765,19 +13529,8 @@ namespace UnitarySystems { // Determine required part load when heat exchanger is ON HXUnitOn = true; PartLoadFrac = 1.0; - HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state, - CompName, - FirstHVACIteration, - HVAC::CompressorOp::On, - PartLoadFrac, - this->m_CoolingCoilIndex, - fanOp, - HXUnitOn, - _, - state.dataUnitarySystems->economizerFlag, - _, - this->m_DehumidificationMode, - 0.0); // this->CoilSHR); + simHXAssistedCooling( + state, CompName, FirstHVACIteration, PartLoadFrac, this->m_CoolingCoilIndex, fanOp, HXUnitOn, this->m_DehumidificationMode); OutletTempDXCoil = state.dataHVACAssistedCC->HXAssistedCoilOutletTemp(this->m_CoolingCoilIndex); @@ -13993,19 +13746,14 @@ namespace UnitarySystems { while ((OutletHumRatDXCoil - DesOutHumRat) >= 0.0 && TempMaxPLR <= 1.0) { // find upper limit of LatentPLR TempMaxPLR += 0.1; - HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state, - CompName, - FirstHVACIteration, - HVAC::CompressorOp::On, - TempMaxPLR, - this->m_CoolingCoilIndex, - fanOp, - HXUnitOn, - _, - state.dataUnitarySystems->economizerFlag, - _, - this->m_DehumidificationMode, - 0.0); // this->CoilSHR); + simHXAssistedCooling(state, + CompName, + FirstHVACIteration, + TempMaxPLR, + this->m_CoolingCoilIndex, + fanOp, + HXUnitOn, + this->m_DehumidificationMode); OutletHumRatDXCoil = state.dataHVACAssistedCC->HXAssistedCoilOutletHumRat(this->m_CoolingCoilIndex); } TempMaxPLR = min(1.0, TempMaxPLR + 0.1); @@ -14015,19 +13763,14 @@ namespace UnitarySystems { // exceeds SystemMoisuterLoad) // find minimum limit of Latent PLR TempMinPLR -= 0.02; - HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state, - CompName, - FirstHVACIteration, - HVAC::CompressorOp::On, - TempMinPLR, - this->m_CoolingCoilIndex, - fanOp, - HXUnitOn, - _, - state.dataUnitarySystems->economizerFlag, - _, - this->m_DehumidificationMode, - 0.0); // this->CoilSHR); + simHXAssistedCooling(state, + CompName, + FirstHVACIteration, + TempMinPLR, + this->m_CoolingCoilIndex, + fanOp, + HXUnitOn, + this->m_DehumidificationMode); OutletHumRatDXCoil = state.dataHVACAssistedCC->HXAssistedCoilOutletHumRat(this->m_CoolingCoilIndex); } TempMinPLR = max(0.0, TempMinPLR - 0.1); @@ -14119,109 +13862,39 @@ namespace UnitarySystems { // Simulate MultiSpeed DX coil at sensible result DXCoils::SimDXCoilMultiSpeed(state, CompName, SpeedRatio, CycRatio, this->m_CoolingCoilIndex); - OutletHumRatDXCoil = state.dataDXCoils->DXCoilOutletHumRat(this->m_CoolingCoilIndex); // IF humidity setpoint is not satisfied and humidity control type is CoolReheat, // then overcool to meet moisture load - - if (OutletHumRatDXCoil > DesOutHumRat) { - - CycRatio = 0.0; - SpeedRatio = 0.0; - - DXCoils::SimDXCoilMultiSpeed(state, CompName, 0.0, 1.0, this->m_CoolingCoilIndex); - OutletHumRatLS = state.dataDXCoils->DXCoilOutletHumRat(this->m_CoolingCoilIndex); - if (OutletHumRatLS > DesOutHumRat) { - CycRatio = 1.0; - DXCoils::SimDXCoilMultiSpeed(state, CompName, 1.0, 1.0, this->m_CoolingCoilIndex); - OutletHumRatHS = state.dataDXCoils->DXCoilOutletHumRat(this->m_CoolingCoilIndex); - if (OutletHumRatHS < DesOutHumRat) { - auto f = [&state, this, DesOutHumRat](Real64 const SpeedRatio) { - return UnitarySys::DXCoilVarSpeedHumRatResidual(state, - SpeedRatio, - this->m_CoolingCoilIndex, - DesOutHumRat, - this->m_UnitarySysNum, // int UnitarySysNum, - 0.0, // Real64 CycRatio, - 0, // int SpeedNum, - HVAC::FanOp::Invalid, // int FanOpMode, - HVAC::CompressorOp::On); - }; - General::SolveRoot(state, HumRatAcc, MaxIte, SolFla, SpeedRatio, f, 0.0, 1.0); - } else { - SpeedRatio = 1.0; - } - PartLoadFrac = SpeedRatio; - } else { - SpeedRatio = 0.0; - auto f = [&state, this, DesOutHumRat](Real64 const CycRatio) { - return UnitarySys::DXCoilCyclingHumRatResidual( - state, - CycRatio, // compressor cycling ratio (1.0 is continuous, 0.0 is off) - this->m_CoolingCoilIndex, - DesOutHumRat, - this->m_UnitarySysNum, // int UnitarySysNum, - 1.0, // Real64 CycRatio, - this->m_CoolingSpeedNum, - this->m_FanOpMode, // int FanOpMode, - HVAC::CompressorOp::On); - }; - General::SolveRoot(state, HumRatAcc, MaxIte, SolFla, CycRatio, f, 0.0, 1.0); - PartLoadFrac = CycRatio; - } - } + dxMultiSpeedHumRatControl(state, + CompName, + this->m_CoolingCoilIndex, + DesOutHumRat, + SpeedRatio, + CycRatio, + PartLoadFrac, + this->m_UnitarySysNum, + 1.0, + this->m_CoolingSpeedNum, + this->m_FanOpMode, + true); } else if (CoilType_Num == HVAC::CoilDX_MultiSpeedCooling) { DXCoils::SimDXCoilMultiSpeed(state, CompName, SpeedRatio, CycRatio, this->m_CoolingCoilIndex); - OutletHumRatDXCoil = state.dataDXCoils->DXCoilOutletHumRat(this->m_CoolingCoilIndex); // IF humidity setpoint is not satisfied and humidity control type is CoolReheat, // then overcool to meet moisture load - - if (OutletHumRatDXCoil > DesOutHumRat) { - - CycRatio = 0.0; - SpeedRatio = 0.0; - - DXCoils::SimDXCoilMultiSpeed(state, CompName, 0.0, 1.0, this->m_CoolingCoilIndex); - OutletHumRatLS = state.dataDXCoils->DXCoilOutletHumRat(this->m_CoolingCoilIndex); - if (OutletHumRatLS > DesOutHumRat) { - CycRatio = 1.0; - DXCoils::SimDXCoilMultiSpeed(state, CompName, 1.0, 1.0, this->m_CoolingCoilIndex); - OutletHumRatHS = state.dataDXCoils->DXCoilOutletHumRat(this->m_CoolingCoilIndex); - if (OutletHumRatHS < DesOutHumRat) { - auto f = [&state, this, DesOutHumRat](Real64 const SpeedRatio) { - return UnitarySys::DXCoilVarSpeedHumRatResidual(state, - SpeedRatio, - this->m_CoolingCoilIndex, - DesOutHumRat, - this->m_UnitarySysNum, // int UnitarySysNum, - 0.0, // Real64 CycRatio, - 0, // int SpeedNum, - HVAC::FanOp::Invalid, // int FanOpMode, - HVAC::CompressorOp::On); - }; - General::SolveRoot(state, HumRatAcc, MaxIte, SolFla, SpeedRatio, f, 0.0, 1.0); - } else { - SpeedRatio = 1.0; - } - } else { - SpeedRatio = 0.0; - auto f = [&state, this, DesOutHumRat](Real64 const CycRatio) { - return UnitarySys::DXCoilCyclingHumRatResidual( - state, - CycRatio, // compressor cycling ratio (1.0 is continuous, 0.0 is off) - this->m_CoolingCoilIndex, - DesOutHumRat, - this->m_UnitarySysNum, // int UnitarySysNum, - 0.0, // Real64 CycRatio, - 0, - HVAC::FanOp::Invalid, // int FanOpMode, - HVAC::CompressorOp::On); - }; - General::SolveRoot(state, HumRatAcc, MaxIte, SolFla, CycRatio, f, 0.0, 1.0); - } - } + dxMultiSpeedHumRatControl(state, + CompName, + this->m_CoolingCoilIndex, + DesOutHumRat, + SpeedRatio, + CycRatio, + PartLoadFrac, + this->m_UnitarySysNum, + 0.0, + 0, + HVAC::FanOp::Invalid, + false); } else if ((CoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) || (CoilType_Num == HVAC::Coil_CoolingWaterToAirHPVSEquationFit)) { VariableSpeedCoils::SimVariableSpeedCoils(state, @@ -14262,32 +13935,31 @@ namespace UnitarySystems { if (OutletHumRatHS < DesOutHumRat) { if (this->m_CoolingSpeedNum == 1) { - auto f = [&state, this, DesOutHumRat](Real64 const CycRatio) { - return UnitarySys::DXCoilCyclingHumRatResidual( - state, - CycRatio, // compressor cycling ratio (1.0 is continuous, 0.0 is off) - this->m_CoolingCoilIndex, - DesOutHumRat, - this->m_UnitarySysNum, // int UnitarySysNum, - 1.0, // Real64 CycRatio, - this->m_CoolingSpeedNum, - this->m_FanOpMode, // int FanOpMode, - HVAC::CompressorOp::On); - }; - General::SolveRoot(state, HumRatAcc, MaxIte, SolFla, CycRatio, f, 0.0, 1.0); + solveForCyclingHumRat(state, + HumRatAcc, + MaxIte, + SolFla, + CycRatio, + this->m_CoolingCoilIndex, + DesOutHumRat, + this->m_UnitarySysNum, + 1.0, + this->m_CoolingSpeedNum, + this->m_FanOpMode, + HVAC::CompressorOp::On); } else { - auto f = [&state, this, DesOutHumRat](Real64 const SpeedRatio) { - return UnitarySys::DXCoilVarSpeedHumRatResidual(state, - SpeedRatio, - this->m_CoolingCoilIndex, - DesOutHumRat, - this->m_UnitarySysNum, // int UnitarySysNum, - 1.0, // Real64 CycRatio, - this->m_CoolingSpeedNum, - this->m_FanOpMode, // int FanOpMode, - HVAC::CompressorOp::On); - }; - General::SolveRoot(state, HumRatAcc, MaxIte, SolFla, SpeedRatio, f, 0.0, 1.0); + solveForVarSpeedHumRat(state, + HumRatAcc, + MaxIte, + SolFla, + SpeedRatio, + this->m_CoolingCoilIndex, + DesOutHumRat, + this->m_UnitarySysNum, + 1.0, + this->m_CoolingSpeedNum, + this->m_FanOpMode, + HVAC::CompressorOp::On); } PartLoadFrac = SpeedRatio; } else { @@ -14299,18 +13971,18 @@ namespace UnitarySystems { } } else { SpeedRatio = 0.0; - auto f = [&state, this, DesOutHumRat](Real64 const SpeedRatio) { - return UnitarySys::DXCoilVarSpeedHumRatResidual(state, - SpeedRatio, - this->m_CoolingCoilIndex, - DesOutHumRat, - this->m_UnitarySysNum, // int UnitarySysNum, - 0.0, // Real64 CycRatio, - 0, // int SpeedNum - HVAC::FanOp::Invalid, // int FanOpMode, - HVAC::CompressorOp::On); - }; - General::SolveRoot(state, HumRatAcc, MaxIte, SolFla, CycRatio, f, 0.0, 1.0); + solveForVarSpeedHumRat(state, + HumRatAcc, + MaxIte, + SolFla, + CycRatio, + this->m_CoolingCoilIndex, + DesOutHumRat, + this->m_UnitarySysNum, + 0.0, + 0, + HVAC::FanOp::Invalid, + HVAC::CompressorOp::On); } } else if (CoilType_Num == HVAC::CoilDX_CoolingTwoStageWHumControl) { auto f = [&state, this, DesOutHumRat, DehumidMode, fanOp](Real64 const PartLoadRatio) { @@ -14544,8 +14216,7 @@ namespace UnitarySystems { this->m_CoolingCycRatio = CycRatio; this->m_DehumidificationMode = DehumidMode; - if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP && - this->m_sysType != SysType::PackagedWSHP) { + if (state.afn->distribution_simulated && !this->isPackagedUnit()) { state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF = max(state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF, LoopDXCoilMaxRTFSave); } @@ -14600,8 +14271,7 @@ namespace UnitarySystems { Real64 LoopHeatingCoilMaxRTFSave = 0.0; Real64 LoopDXCoilMaxRTFSave = 0.0; - if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP && - this->m_sysType != SysType::PackagedWSHP) { + if (state.afn->distribution_simulated && !this->isPackagedUnit()) { LoopHeatingCoilMaxRTFSave = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopHeatingCoilMaxRTF; state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopHeatingCoilMaxRTF = 0.0; LoopDXCoilMaxRTFSave = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF; @@ -15233,8 +14903,7 @@ namespace UnitarySystems { this->m_HeatingCycRatio = CycRatio; HeatCoilLoad = ReqOutput; - if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP && - this->m_sysType != SysType::PackagedWSHP) { + if (state.afn->distribution_simulated && !this->isPackagedUnit()) { state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopHeatingCoilMaxRTF = max(state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopHeatingCoilMaxRTF, LoopHeatingCoilMaxRTFSave); state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF = @@ -15285,8 +14954,7 @@ namespace UnitarySystems { Real64 LoopHeatingCoilMaxRTFSave = 0.0; Real64 LoopDXCoilMaxRTFSave = 0.0; - if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP && - this->m_sysType != SysType::PackagedWSHP) { + if (state.afn->distribution_simulated && !this->isPackagedUnit()) { auto &afnInfo = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum); LoopHeatingCoilMaxRTFSave = afnInfo.AFNLoopHeatingCoilMaxRTF; afnInfo.AFNLoopHeatingCoilMaxRTF = 0.0; @@ -15647,8 +15315,7 @@ namespace UnitarySystems { } // IF((GetCurrentScheduleValue(state, UnitarySystem(UnitarySysNum)%m_SysAvailSchedPtr) > 0.0d0) .AND. & // LoopHeatingCoilMaxRTF used for AirflowNetwork gets set in child components (gas and fuel) - if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP && - this->m_sysType != SysType::PackagedWSHP) { + if (state.afn->distribution_simulated && !this->isPackagedUnit()) { auto &afnInfo = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum); afnInfo.AFNLoopHeatingCoilMaxRTF = max(afnInfo.AFNLoopHeatingCoilMaxRTF, LoopHeatingCoilMaxRTFSave); afnInfo.AFNLoopDXCoilRTF = max(afnInfo.AFNLoopDXCoilRTF, LoopDXCoilMaxRTFSave); @@ -15739,8 +15406,11 @@ namespace UnitarySystems { state.dataCoilCoolingDX->coilCoolingDXs[this->m_CoolingCoilIndex].simulate( state, coilMode, this->m_CoolingSpeedNum, PartLoadFrac, this->m_FanOpMode, singleMode, this->CoilSHR); - } else if (CoilTypeNum == HVAC::Coil_CoolingAirToAirVariableSpeed) { + } else if (CoilTypeNum == HVAC::Coil_CoolingAirToAirVariableSpeed || CoilTypeNum == HVAC::Coil_HeatingAirToAirVariableSpeed || + CoilTypeNum == HVAC::Coil_CoolingWaterToAirHPVSEquationFit || CoilTypeNum == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) { + // Variable-speed coils all use the same call; only the speed ratio differs between cooling and heating. + Real64 speedRatio = (CoilType == CoolingCoil) ? this->m_CoolingSpeedRatio : this->m_HeatingSpeedRatio; VariableSpeedCoils::SimVariableSpeedCoils(state, CompName, CompIndex, @@ -15748,49 +15418,7 @@ namespace UnitarySystems { CompressorOn, PartLoadFrac, SpeedNumber, - this->m_CoolingSpeedRatio, - SensLoad, - dummy, - OnOffAirFlowRatio); - - } else if (CoilTypeNum == HVAC::Coil_HeatingAirToAirVariableSpeed) { - - VariableSpeedCoils::SimVariableSpeedCoils(state, - CompName, - CompIndex, - this->m_FanOpMode, - CompressorOn, - PartLoadFrac, - SpeedNumber, - this->m_HeatingSpeedRatio, - SensLoad, - dummy, - OnOffAirFlowRatio); - - } else if (CoilTypeNum == HVAC::Coil_CoolingWaterToAirHPVSEquationFit) { - - VariableSpeedCoils::SimVariableSpeedCoils(state, - CompName, - CompIndex, - this->m_FanOpMode, - CompressorOn, - PartLoadFrac, - SpeedNumber, - this->m_CoolingSpeedRatio, - SensLoad, - dummy, - OnOffAirFlowRatio); - - } else if (CoilTypeNum == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) { - - VariableSpeedCoils::SimVariableSpeedCoils(state, - CompName, - CompIndex, - this->m_FanOpMode, - CompressorOn, - PartLoadFrac, - SpeedNumber, - this->m_HeatingSpeedRatio, + speedRatio, SensLoad, dummy, OnOffAirFlowRatio); @@ -15902,6 +15530,39 @@ namespace UnitarySystems { } } + bool UnitarySys::isPackagedUnit() const + { + return (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP); + } + + // Helper: update the merged speed variables (CycRatio, SpeedRatio, SpeedNum) to + // the max of the cooling and heating values. Called from reportUnitarySystem. + void UnitarySys::setMergedSpeedVars() + { + this->m_CycRatio = max(this->m_CoolingCycRatio, this->m_HeatingCycRatio); + this->m_SpeedRatio = max(this->m_CoolingSpeedRatio, this->m_HeatingSpeedRatio); + this->m_SpeedNum = max(this->m_CoolingSpeedNum, this->m_HeatingSpeedNum); + } + + // Helper: compute ancillary electric power and accumulate ancillary electric + // consumption for one coil during reporting. The pattern is identical for + // cooling and heating coils -- only the load-fraction variable differs. + // isLoading -- true when the corresponding load (cooling or heating) is active + // lastModeMatch -- true when the system was last in this mode (Cooling / Heating) + // loadFrac -- the load-fraction variable (CycRatio, CompPartLoadRatio, or PartLoadFrac) + // auxConsumption -- reference to either m_CoolingAuxElecConsumption or m_HeatingAuxElecConsumption + // reportingConst -- TimeStepSysSec + void UnitarySys::calcAuxElecPower(bool isLoading, bool lastModeMatch, Real64 loadFrac, Real64 &auxConsumption, Real64 reportingConst) + { + if (isLoading) { + this->m_TotalAuxElecPower = this->m_AncillaryOnPower * loadFrac + this->m_AncillaryOffPower * (1.0 - loadFrac); + auxConsumption = this->m_AncillaryOnPower * loadFrac * reportingConst; + } + if (lastModeMatch) { + auxConsumption += this->m_AncillaryOffPower * (1.0 - loadFrac) * reportingConst; + } + } + void UnitarySys::reportUnitarySystem(EnergyPlusData &state, int const AirLoopNum) { @@ -15953,7 +15614,7 @@ namespace UnitarySystems { if (this->AirOutNode > 0 && this->NodeNumOfControlledZone > 0) { // PTUnit uses old style method of calculating delivered capacity. // Also PTUnit always uses inlet node data, which is good when inlet is connected to zone return node - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP) { + if (this->isPackagedUnit()) { Real64 SpecHumOut = state.dataLoopNodes->Node(this->AirOutNode).HumRat; Real64 SpecHumIn = state.dataLoopNodes->Node(this->AirInNode).HumRat; LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate, kg/s (dehumid = negative) @@ -15986,7 +15647,8 @@ namespace UnitarySystems { this->m_CompPartLoadRatio = max(this->m_CoolCompPartLoadRatio, this->m_HeatCompPartLoadRatio); // logic difference in PTUnit *Rate reporting vs UnitarySystem. Use PTUnit more compact method for 9093. - if (this->m_sysType == SysType::PackagedAC || this->m_sysType == SysType::PackagedHP || this->m_sysType == SysType::PackagedWSHP) { + bool const isPTUnit = this->isPackagedUnit(); + if (isPTUnit) { // Issue 9093. // PTHP reports these differently, seems this is correct. Can't change this now, need an issue to resolve this->m_TotCoolEnergyRate = std::abs(min(0.0, QTotUnitOut)); @@ -15996,38 +15658,22 @@ namespace UnitarySystems { this->m_LatCoolEnergyRate = std::abs(min(0.0, (QTotUnitOut - QSensUnitOut))); this->m_LatHeatEnergyRate = std::abs(max(0.0, (QTotUnitOut - QSensUnitOut))); } else { - if (state.dataUnitarySystems->HeatingLoad) { - if (QTotUnitOut > 0.0) { // heating - this->m_TotCoolEnergyRate = 0.0; - this->m_SensCoolEnergyRate = 0.0; - this->m_LatCoolEnergyRate = 0.0; - this->m_TotHeatEnergyRate = QTotUnitOut; - this->m_SensHeatEnergyRate = std::abs(max(0.0, QSensUnitOut)); - this->m_LatHeatEnergyRate = std::abs(max(0.0, (QTotUnitOut - QSensUnitOut))); - } else { - this->m_TotCoolEnergyRate = std::abs(QTotUnitOut); - this->m_SensCoolEnergyRate = std::abs(min(0.0, QSensUnitOut)); - this->m_LatCoolEnergyRate = std::abs(min(0.0, (QTotUnitOut - QSensUnitOut))); - this->m_TotHeatEnergyRate = 0.0; - this->m_SensHeatEnergyRate = 0.0; - this->m_LatHeatEnergyRate = 0.0; - } + // When QTotUnitOut > 0, report as heating output; when <= 0, report as cooling output. + bool const isHeatingOutput = (QTotUnitOut > 0.0); + if (isHeatingOutput) { + this->m_TotCoolEnergyRate = 0.0; + this->m_SensCoolEnergyRate = 0.0; + this->m_LatCoolEnergyRate = 0.0; + this->m_TotHeatEnergyRate = QTotUnitOut; + this->m_SensHeatEnergyRate = std::abs(max(0.0, QSensUnitOut)); + this->m_LatHeatEnergyRate = std::abs(max(0.0, (QTotUnitOut - QSensUnitOut))); } else { - if (QTotUnitOut <= 0.0) { // cooling - this->m_TotCoolEnergyRate = std::abs(min(0.0, QTotUnitOut)); - this->m_SensCoolEnergyRate = std::abs(min(0.0, QSensUnitOut)); - this->m_LatCoolEnergyRate = std::abs(min(0.0, (QTotUnitOut - QSensUnitOut))); - this->m_TotHeatEnergyRate = 0.0; - this->m_SensHeatEnergyRate = 0.0; - this->m_LatHeatEnergyRate = 0.0; - } else { - this->m_TotCoolEnergyRate = 0.0; - this->m_SensCoolEnergyRate = 0.0; - this->m_LatCoolEnergyRate = 0.0; - this->m_TotHeatEnergyRate = QTotUnitOut; - this->m_SensHeatEnergyRate = std::abs(max(0.0, QSensUnitOut)); - this->m_LatHeatEnergyRate = std::abs(max(0.0, (QTotUnitOut - QSensUnitOut))); - } + this->m_TotCoolEnergyRate = std::abs(min(0.0, QTotUnitOut)); + this->m_SensCoolEnergyRate = std::abs(min(0.0, QSensUnitOut)); + this->m_LatCoolEnergyRate = std::abs(min(0.0, (QTotUnitOut - QSensUnitOut))); + this->m_TotHeatEnergyRate = 0.0; + this->m_SensHeatEnergyRate = 0.0; + this->m_LatHeatEnergyRate = 0.0; } } @@ -16058,155 +15704,74 @@ namespace UnitarySystems { Real64 suppHeatingPower = 0.0; Real64 defrostElecPower = 0.0; + bool const isCooling = state.dataUnitarySystems->CoolingLoad; + bool const isHeating = state.dataUnitarySystems->HeatingLoad; + bool const lastCooling = (this->m_LastMode == CoolingMode); + bool const lastHeating = (this->m_LastMode == HeatingMode); + switch (this->m_CoolingCoilType_Num) { case HVAC::CoilDX_CoolingTwoSpeed: { // need to make sure these are 0 for non-variable speed coils (or not report these variables) - this->m_CycRatio = max(this->m_CoolingCycRatio, this->m_HeatingCycRatio); - this->m_SpeedRatio = max(this->m_CoolingSpeedRatio, this->m_HeatingSpeedRatio); - this->m_SpeedNum = max(this->m_CoolingSpeedNum, this->m_HeatingSpeedNum); + this->setMergedSpeedVars(); // see :setSpeedVariables - if (state.dataUnitarySystems->CoolingLoad && this->m_SpeedNum <= 1) { - this->m_TotalAuxElecPower = this->m_AncillaryOnPower * this->m_CycRatio + this->m_AncillaryOffPower * (1.0 - this->m_CycRatio); - this->m_CoolingAuxElecConsumption = this->m_AncillaryOnPower * this->m_CycRatio * ReportingConstant; - } - if (this->m_LastMode == CoolingMode) { - this->m_CoolingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - this->m_CycRatio) * ReportingConstant; - } + this->calcAuxElecPower( + isCooling && this->m_SpeedNum <= 1, lastCooling, this->m_CycRatio, this->m_CoolingAuxElecConsumption, ReportingConstant); elecCoolingPower = state.dataHVACGlobal->DXElecCoolingPower; } break; case HVAC::CoilDX_MultiSpeedCooling: { - this->m_CycRatio = max(this->m_CoolingCycRatio, this->m_HeatingCycRatio); - this->m_SpeedRatio = max(this->m_CoolingSpeedRatio, this->m_HeatingSpeedRatio); - this->m_SpeedNum = max(this->m_CoolingSpeedNum, this->m_HeatingSpeedNum); - - Real64 CompPartLoadFrac = this->m_CompPartLoadRatio; - if (state.dataUnitarySystems->CoolingLoad) { - this->m_TotalAuxElecPower = this->m_AncillaryOnPower * CompPartLoadFrac + this->m_AncillaryOffPower * (1.0 - CompPartLoadFrac); - this->m_CoolingAuxElecConsumption = this->m_AncillaryOnPower * CompPartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == CoolingMode) { - this->m_CoolingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - CompPartLoadFrac) * ReportingConstant; - } + this->setMergedSpeedVars(); + this->calcAuxElecPower(isCooling, lastCooling, this->m_CompPartLoadRatio, this->m_CoolingAuxElecConsumption, ReportingConstant); elecCoolingPower = state.dataHVACGlobal->DXElecCoolingPower; } break; case HVAC::Coil_CoolingWater: case HVAC::Coil_CoolingWaterDetailed: { if (this->m_DiscreteSpeedCoolingCoil) { - this->m_CycRatio = max(this->m_CoolingCycRatio, this->m_HeatingCycRatio); - this->m_SpeedRatio = max(this->m_CoolingSpeedRatio, this->m_HeatingSpeedRatio); - this->m_SpeedNum = max(this->m_CoolingSpeedNum, this->m_HeatingSpeedNum); - if (state.dataUnitarySystems->CoolingLoad) { - // if discrete, the coil cycles on and off - this->m_TotalAuxElecPower = this->m_AncillaryOnPower * this->m_CycRatio + this->m_AncillaryOffPower * (1.0 - this->m_CycRatio); - this->m_CoolingAuxElecConsumption = this->m_AncillaryOnPower * this->m_CycRatio * ReportingConstant; - } - if (this->m_LastMode == CoolingMode) { - this->m_CoolingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - this->m_CycRatio) * ReportingConstant; - } + this->setMergedSpeedVars(); + this->calcAuxElecPower(isCooling, lastCooling, this->m_CycRatio, this->m_CoolingAuxElecConsumption, ReportingConstant); } else { - if (state.dataUnitarySystems->CoolingLoad) { - // if not discrete, the coil runs the entire time step. - this->m_TotalAuxElecPower = - this->m_AncillaryOnPower * this->m_PartLoadFrac + this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac); - this->m_CoolingAuxElecConsumption = this->m_AncillaryOnPower * this->m_PartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == CoolingMode) { - this->m_CoolingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac) * ReportingConstant; - } + this->calcAuxElecPower(isCooling, lastCooling, this->m_PartLoadFrac, this->m_CoolingAuxElecConsumption, ReportingConstant); } this->m_ElecPower = locFanElecPower; this->m_ElecPowerConsumption = this->m_ElecPower * ReportingConstant; } break; - // May not need case HVAC::Coil_CoolingWaterToAirHPSimple: { if (this->m_NumOfSpeedCooling > 1) { - this->m_CycRatio = max(this->m_CoolingCycRatio, this->m_HeatingCycRatio); - this->m_SpeedRatio = max(this->m_CoolingSpeedRatio, this->m_HeatingSpeedRatio); - this->m_SpeedNum = max(this->m_CoolingSpeedNum, this->m_HeatingSpeedNum); - } - if (state.dataUnitarySystems->CoolingLoad) { - this->m_TotalAuxElecPower = - this->m_AncillaryOnPower * this->m_PartLoadFrac + this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac); - this->m_CoolingAuxElecConsumption = this->m_AncillaryOnPower * this->m_PartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == CoolingMode) { - this->m_CoolingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac) * ReportingConstant; + this->setMergedSpeedVars(); } + this->calcAuxElecPower(isCooling, lastCooling, this->m_PartLoadFrac, this->m_CoolingAuxElecConsumption, ReportingConstant); elecCoolingPower = state.dataHVACGlobal->DXElecCoolingPower; } break; case HVAC::CoilDX_Cooling: { if (this->m_NumOfSpeedCooling > 1) { - this->m_CycRatio = max(this->m_CoolingCycRatio, this->m_HeatingCycRatio); - this->m_SpeedRatio = max(this->m_CoolingSpeedRatio, this->m_HeatingSpeedRatio); - this->m_SpeedNum = max(this->m_CoolingSpeedNum, this->m_HeatingSpeedNum); - - Real64 CompPartLoadFrac = this->m_CompPartLoadRatio; - if (state.dataUnitarySystems->CoolingLoad) { - this->m_TotalAuxElecPower = this->m_AncillaryOnPower * CompPartLoadFrac + this->m_AncillaryOffPower * (1.0 - CompPartLoadFrac); - this->m_CoolingAuxElecConsumption = this->m_AncillaryOnPower * CompPartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == CoolingMode) { - this->m_CoolingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - CompPartLoadFrac) * ReportingConstant; - } - elecCoolingPower = state.dataHVACGlobal->DXElecCoolingPower; + this->setMergedSpeedVars(); + this->calcAuxElecPower(isCooling, lastCooling, this->m_CompPartLoadRatio, this->m_CoolingAuxElecConsumption, ReportingConstant); } else { if (state.dataCoilCoolingDX->coilCoolingDXs[this->m_CoolingCoilIndex].subcoolReheatFlag) { - if (state.dataUnitarySystems->CoolingLoad && this->LoadSHR == 0.0) { + if (isCooling && this->LoadSHR == 0.0) { this->LoadSHR = 1.0; this->CoilSHR = state.dataCoilCoolingDX->coilCoolingDXs[this->m_CoolingCoilIndex].performance->NormalSHR; } } - Real64 CompPartLoadFrac = this->m_CompPartLoadRatio; - if (state.dataUnitarySystems->CoolingLoad) { - this->m_TotalAuxElecPower = this->m_AncillaryOnPower * CompPartLoadFrac + this->m_AncillaryOffPower * (1.0 - CompPartLoadFrac); - this->m_CoolingAuxElecConsumption = this->m_AncillaryOnPower * CompPartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == CoolingMode) { - this->m_CoolingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - CompPartLoadFrac) * ReportingConstant; - } - elecCoolingPower = state.dataHVACGlobal->DXElecCoolingPower; + this->calcAuxElecPower(isCooling, lastCooling, this->m_CompPartLoadRatio, this->m_CoolingAuxElecConsumption, ReportingConstant); } + elecCoolingPower = state.dataHVACGlobal->DXElecCoolingPower; } break; case HVAC::Coil_UserDefined: case HVAC::CoilWater_CoolingHXAssisted: case HVAC::CoilDX_PackagedThermalStorageCooling: { - if (state.dataUnitarySystems->CoolingLoad) { - this->m_TotalAuxElecPower = - this->m_AncillaryOnPower * this->m_PartLoadFrac + this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac); - this->m_CoolingAuxElecConsumption = this->m_AncillaryOnPower * this->m_PartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == CoolingMode) { - this->m_CoolingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac) * ReportingConstant; - } + this->calcAuxElecPower(isCooling, lastCooling, this->m_PartLoadFrac, this->m_CoolingAuxElecConsumption, ReportingConstant); // these coil types do not consume electricity or report electricity at the plant } break; default: { // all other DX cooling coils - Real64 CompPartLoadFrac = this->m_CompPartLoadRatio; - if (state.dataUnitarySystems->CoolingLoad) { - this->m_TotalAuxElecPower = this->m_AncillaryOnPower * CompPartLoadFrac + this->m_AncillaryOffPower * (1.0 - CompPartLoadFrac); - this->m_CoolingAuxElecConsumption = this->m_AncillaryOnPower * CompPartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == CoolingMode) { - this->m_CoolingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - CompPartLoadFrac) * ReportingConstant; - } + this->calcAuxElecPower(isCooling, lastCooling, this->m_CompPartLoadRatio, this->m_CoolingAuxElecConsumption, ReportingConstant); elecCoolingPower = state.dataHVACGlobal->DXElecCoolingPower; } break; } switch (this->m_HeatingCoilType_Num) { case HVAC::CoilDX_MultiSpeedHeating: { - this->m_CycRatio = max(this->m_CoolingCycRatio, this->m_HeatingCycRatio); - this->m_SpeedRatio = max(this->m_CoolingSpeedRatio, this->m_HeatingSpeedRatio); - this->m_SpeedNum = max(this->m_CoolingSpeedNum, this->m_HeatingSpeedNum); - - Real64 CompPartLoadFrac = this->m_CompPartLoadRatio; - if (state.dataUnitarySystems->HeatingLoad) { - this->m_TotalAuxElecPower = this->m_AncillaryOnPower * CompPartLoadFrac + this->m_AncillaryOffPower * (1.0 - CompPartLoadFrac); - this->m_HeatingAuxElecConsumption = this->m_AncillaryOnPower * CompPartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == HeatingMode) { - this->m_HeatingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - CompPartLoadFrac) * ReportingConstant; - } + this->setMergedSpeedVars(); + this->calcAuxElecPower(isHeating, lastHeating, this->m_CompPartLoadRatio, this->m_HeatingAuxElecConsumption, ReportingConstant); elecHeatingPower = state.dataHVACGlobal->DXElecHeatingPower; defrostElecPower = state.dataHVACGlobal->DefrostElecPower; } break; @@ -16214,16 +15779,7 @@ namespace UnitarySystems { case HVAC::Coil_HeatingElectric_MultiStage: { this->m_CycRatio = max(this->m_CoolingCycRatio, this->m_HeatingCycRatio); this->m_SpeedRatio = max(this->m_CoolingSpeedRatio, this->m_HeatingSpeedRatio); - - if (state.dataUnitarySystems->HeatingLoad) { - this->m_TotalAuxElecPower = - this->m_AncillaryOnPower * this->m_PartLoadFrac + this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac); - this->m_HeatingAuxElecConsumption = this->m_AncillaryOnPower * this->m_PartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == HeatingMode) { - this->m_HeatingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac) * ReportingConstant; - } - + this->calcAuxElecPower(isHeating, lastHeating, this->m_PartLoadFrac, this->m_HeatingAuxElecConsumption, ReportingConstant); elecHeatingPower = state.dataHVACGlobal->ElecHeatingCoilPower; } break; case HVAC::CoilDX_HeatingEmpirical: @@ -16231,31 +15787,14 @@ namespace UnitarySystems { case HVAC::Coil_HeatingWaterToAirHPSimple: case HVAC::Coil_HeatingWaterToAirHPVSEquationFit: { if (this->m_NumOfSpeedHeating > 1) { - this->m_CycRatio = max(this->m_CoolingCycRatio, this->m_HeatingCycRatio); - this->m_SpeedRatio = max(this->m_CoolingSpeedRatio, this->m_HeatingSpeedRatio); - this->m_SpeedNum = max(this->m_CoolingSpeedNum, this->m_HeatingSpeedNum); - } - if (state.dataUnitarySystems->HeatingLoad) { - this->m_TotalAuxElecPower = - this->m_AncillaryOnPower * this->m_PartLoadFrac + this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac); - this->m_HeatingAuxElecConsumption = this->m_AncillaryOnPower * this->m_PartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == HeatingMode) { - this->m_HeatingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac) * ReportingConstant; + this->setMergedSpeedVars(); } + this->calcAuxElecPower(isHeating, lastHeating, this->m_PartLoadFrac, this->m_HeatingAuxElecConsumption, ReportingConstant); elecHeatingPower = state.dataHVACGlobal->DXElecHeatingPower; defrostElecPower = state.dataHVACGlobal->DefrostElecPower; } break; case HVAC::Coil_HeatingAirToAirVariableSpeed: { - if (state.dataUnitarySystems->HeatingLoad) { - this->m_TotalAuxElecPower = - this->m_AncillaryOnPower * this->m_PartLoadFrac + this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac); - this->m_HeatingAuxElecConsumption = this->m_AncillaryOnPower * this->m_PartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == HeatingMode) { - this->m_HeatingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac) * ReportingConstant; - } - + this->calcAuxElecPower(isHeating, lastHeating, this->m_PartLoadFrac, this->m_HeatingAuxElecConsumption, ReportingConstant); elecHeatingPower = state.dataHVACGlobal->DXElecHeatingPower; defrostElecPower = state.dataHVACGlobal->DefrostElecPower; } break; @@ -16263,32 +15802,17 @@ namespace UnitarySystems { case HVAC::Coil_HeatingWater: case HVAC::Coil_HeatingSteam: case HVAC::Coil_HeatingDesuperheater: { - if (state.dataUnitarySystems->HeatingLoad) { - this->m_TotalAuxElecPower = - this->m_AncillaryOnPower * this->m_PartLoadFrac + this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac); - this->m_HeatingAuxElecConsumption = this->m_AncillaryOnPower * this->m_PartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == HeatingMode) { - this->m_HeatingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac) * ReportingConstant; - } + this->calcAuxElecPower(isHeating, lastHeating, this->m_PartLoadFrac, this->m_HeatingAuxElecConsumption, ReportingConstant); } break; default: { if (this->m_HeatCoilExists) { - if (state.dataUnitarySystems->HeatingLoad) { - // if discrete, the coil cycles on and off - this->m_TotalAuxElecPower = - this->m_AncillaryOnPower * this->m_PartLoadFrac + this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac); - this->m_HeatingAuxElecConsumption = this->m_AncillaryOnPower * this->m_PartLoadFrac * ReportingConstant; - } - if (this->m_LastMode == HeatingMode) { - this->m_HeatingAuxElecConsumption += this->m_AncillaryOffPower * (1.0 - this->m_PartLoadFrac) * ReportingConstant; - } + this->calcAuxElecPower(isHeating, lastHeating, this->m_PartLoadFrac, this->m_HeatingAuxElecConsumption, ReportingConstant); elecHeatingPower = state.dataHVACGlobal->ElecHeatingCoilPower; } } break; } - if (!state.dataUnitarySystems->HeatingLoad && !state.dataUnitarySystems->CoolingLoad) { + if (!isHeating && !isCooling) { this->m_TotalAuxElecPower = this->m_AncillaryOffPower; } @@ -16301,8 +15825,7 @@ namespace UnitarySystems { this->m_ElecPower = locFanElecPower + elecCoolingPower + elecHeatingPower + suppHeatingPower + defrostElecPower + this->m_TotalAuxElecPower; this->m_ElecPowerConsumption = this->m_ElecPower * ReportingConstant; - if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP && - this->m_sysType != SysType::PackagedWSHP) { + if (state.afn->distribution_simulated && !this->isPackagedUnit()) { state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOnMassFlowrate = state.dataUnitarySystems->CompOnMassFlow; state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOffMassFlowrate = state.dataUnitarySystems->CompOffMassFlow; state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopFanOperationMode = this->m_FanOpMode; @@ -17397,8 +16920,7 @@ namespace UnitarySystems { noUnitarySysOutdoorAir = true; } - if (unitarySys.m_sysType == UnitarySys::SysType::PackagedWSHP || unitarySys.m_sysType == UnitarySys::SysType::PackagedAC || - unitarySys.m_sysType == UnitarySys::SysType::PackagedHP) { + if (unitarySys.isPackagedUnit()) { if ((noUnitarySysOutdoorAir && (nodeNumber == FanInletNodeIndex || nodeNumber == FanOutletNodeIndex || nodeNumber == unitarySys.AirInNode || nodeNumber == unitarySys.m_OAMixerNodes[0] || nodeNumber == unitarySys.m_OAMixerNodes[1] || nodeNumber == unitarySys.m_OAMixerNodes[2])) || @@ -17419,7 +16941,7 @@ namespace UnitarySystems { if (numAllSystemTypes == state.dataUnitarySystems->numUnitarySystems) { for (int sysNum = 0; sysNum < state.dataUnitarySystems->numUnitarySystems; ++sysNum) { switch (state.dataUnitarySystems->unitarySys[sysNum].m_sysType) { - case UnitarySys::SysType::Unitary: + case UnitarySys::SysType::Unitary: { // Setup Report variables for the Unitary System that are not reported in the components themselves SetupOutputVariable(state, "Unitary System Part Load Ratio", @@ -17674,33 +17196,40 @@ namespace UnitarySystems { break; } - if (state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::CoilDX_MultiSpeedCooling || - state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::CoilDX_CoolingTwoSpeed || - state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::CoilDX_Cooling || - state.dataUnitarySystems->unitarySys[sysNum].m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || - state.dataUnitarySystems->unitarySys[sysNum].m_HeatingCoilType_Num == HVAC::Coil_HeatingElectric_MultiStage || - state.dataUnitarySystems->unitarySys[sysNum].m_HeatingCoilType_Num == HVAC::Coil_HeatingGas_MultiStage) { + // Helper to set up the coil speed triplet (cycling ratio, speed ratio, speed level). + // Used for both DX coil and water coil multi-speed configurations. + auto setupCoilSpeedVars = [&](std::string_view coilKind) { + auto &sys = state.dataUnitarySystems->unitarySys[sysNum]; SetupOutputVariable(state, - "Unitary System DX Coil Cycling Ratio", + EnergyPlus::format("Unitary System {} Cycling Ratio", coilKind), Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_CycRatio, + sys.m_CycRatio, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + sys.Name); SetupOutputVariable(state, - "Unitary System DX Coil Speed Ratio", + EnergyPlus::format("Unitary System {} Speed Ratio", coilKind), Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_SpeedRatio, + sys.m_SpeedRatio, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + sys.Name); SetupOutputVariable(state, - "Unitary System DX Coil Speed Level", + EnergyPlus::format("Unitary System {} Speed Level", coilKind), Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_SpeedNum, + sys.m_SpeedNum, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + sys.Name); + }; + + if (state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::CoilDX_MultiSpeedCooling || + state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::CoilDX_CoolingTwoSpeed || + state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::CoilDX_Cooling || + state.dataUnitarySystems->unitarySys[sysNum].m_HeatingCoilType_Num == HVAC::CoilDX_MultiSpeedHeating || + state.dataUnitarySystems->unitarySys[sysNum].m_HeatingCoilType_Num == HVAC::Coil_HeatingElectric_MultiStage || + state.dataUnitarySystems->unitarySys[sysNum].m_HeatingCoilType_Num == HVAC::Coil_HeatingGas_MultiStage) { + setupCoilSpeedVars("DX Coil"); } if (((state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::Coil_CoolingWater || @@ -17708,27 +17237,7 @@ namespace UnitarySystems { state.dataUnitarySystems->unitarySys[sysNum].m_DiscreteSpeedCoolingCoil) || (state.dataUnitarySystems->unitarySys[sysNum].m_HeatingCoilType_Num == HVAC::Coil_HeatingWater && state.dataUnitarySystems->unitarySys[sysNum].m_MultiSpeedHeatingCoil)) { - SetupOutputVariable(state, - "Unitary System Water Coil Cycling Ratio", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_CycRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Unitary System Water Coil Speed Ratio", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_SpeedRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Unitary System Water Coil Speed Level", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_SpeedNum, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + setupCoilSpeedVars("Water Coil"); } if (state.dataGlobal->AnyEnergyManagementSystemInModel) { @@ -17810,10 +17319,11 @@ namespace UnitarySystems { } bool anyEMSRan; EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::ComponentGetInput, anyEMSRan, ObjexxFCL::Optional_int_const()); - break; + } break; case UnitarySys::SysType::CoilCoolingDX: // Setup Report variables for the DXCoolingSystem that is not reported in the components themselves - if (state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::CoilDX_CoolingTwoSpeed) { + if (state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::CoilDX_CoolingTwoSpeed || + state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) { SetupOutputVariable(state, "Coil System Cycling Ratio", Constant::Units::None, @@ -17828,28 +17338,15 @@ namespace UnitarySystems { OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, state.dataUnitarySystems->unitarySys[sysNum].Name); - } else if (state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) { - SetupOutputVariable(state, - "Coil System Cycling Ratio", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCycRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Coil System Compressor Speed Ratio", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_CoolingSpeedRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Coil System Compressor Speed Number", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_CoolingSpeedNum, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + if (state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) { + SetupOutputVariable(state, + "Coil System Compressor Speed Number", + Constant::Units::None, + state.dataUnitarySystems->unitarySys[sysNum].m_CoolingSpeedNum, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + state.dataUnitarySystems->unitarySys[sysNum].Name); + } } else { SetupOutputVariable(state, "Coil System Part Load Ratio", @@ -17909,399 +17406,176 @@ namespace UnitarySystems { } break; case UnitarySys::SysType::PackagedAC: - // CurrentModuleObject = 'ZoneHVAC:PackagedTerminalAirConditioner' - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Total Heating Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_TotHeatEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Total Heating Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_TotHeatEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Total Cooling Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_TotCoolEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Total Cooling Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_TotCoolEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Sensible Heating Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_SensHeatEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Sensible Heating Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_SensHeatEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Sensible Cooling Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_SensCoolEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Sensible Cooling Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_SensCoolEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Latent Heating Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_LatHeatEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Latent Heating Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_LatHeatEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Latent Cooling Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_LatCoolEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Latent Cooling Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_LatCoolEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Electricity Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_ElecPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Electricity Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_ElecPowerConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Fan Part Load Ratio", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].FanPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Compressor Part Load Ratio", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_CompPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Air Conditioner Fan Availability Status", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_AvailStatus, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - break; case UnitarySys::SysType::PackagedHP: - // CurrentModuleObject = 'ZoneHVAC:PackagedTerminalHeatPump' - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Total Heating Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_TotHeatEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Total Heating Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_TotHeatEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Total Cooling Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_TotCoolEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Total Cooling Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_TotCoolEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Sensible Heating Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_SensHeatEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Sensible Heating Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_SensHeatEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Sensible Cooling Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_SensCoolEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Sensible Cooling Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_SensCoolEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Latent Heating Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_LatHeatEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Latent Heating Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_LatHeatEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); + case UnitarySys::SysType::PackagedWSHP: { + // Common output variables for all packaged terminal unit types. + // Only the prefix string differs between PackagedAC, PackagedHP, and PackagedWSHP. + std::string_view prefix; + switch (state.dataUnitarySystems->unitarySys[sysNum].m_sysType) { + case UnitarySys::SysType::PackagedAC: + prefix = "Zone Packaged Terminal Air Conditioner"; + break; + case UnitarySys::SysType::PackagedHP: + prefix = "Zone Packaged Terminal Heat Pump"; + break; + case UnitarySys::SysType::PackagedWSHP: + prefix = "Zone Water to Air Heat Pump"; + break; + default: + break; + } + auto &thisSys = state.dataUnitarySystems->unitarySys[sysNum]; SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Latent Cooling Rate", + EnergyPlus::format("{} Total Heating Rate", prefix), Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_LatCoolEnergyRate, + thisSys.m_TotHeatEnergyRate, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Latent Cooling Energy", + EnergyPlus::format("{} Total Heating Energy", prefix), Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_LatCoolEnergy, + thisSys.m_TotHeatEnergy, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Electricity Rate", + EnergyPlus::format("{} Total Cooling Rate", prefix), Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_ElecPower, + thisSys.m_TotCoolEnergyRate, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Electricity Energy", + EnergyPlus::format("{} Total Cooling Energy", prefix), Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_ElecPowerConsumption, + thisSys.m_TotCoolEnergy, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Fan Part Load Ratio", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].FanPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Compressor Part Load Ratio", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_CompPartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Packaged Terminal Heat Pump Fan Availability Status", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_AvailStatus, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - break; - case UnitarySys::SysType::PackagedWSHP: - // CurrentModuleObject = 'ZoneHVAC:WaterToAirHeatPump' + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Total Heating Rate", + EnergyPlus::format("{} Sensible Heating Rate", prefix), Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_TotHeatEnergyRate, + thisSys.m_SensHeatEnergyRate, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Total Heating Energy", + EnergyPlus::format("{} Sensible Heating Energy", prefix), Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_TotHeatEnergy, + thisSys.m_SensHeatEnergy, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Total Cooling Rate", + EnergyPlus::format("{} Sensible Cooling Rate", prefix), Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_TotCoolEnergyRate, + thisSys.m_SensCoolEnergyRate, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Total Cooling Energy", + EnergyPlus::format("{} Sensible Cooling Energy", prefix), Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_TotCoolEnergy, + thisSys.m_SensCoolEnergy, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Sensible Heating Rate", + EnergyPlus::format("{} Latent Heating Rate", prefix), Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_SensHeatEnergyRate, + thisSys.m_LatHeatEnergyRate, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Sensible Heating Energy", + EnergyPlus::format("{} Latent Heating Energy", prefix), Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_SensHeatEnergy, + thisSys.m_LatHeatEnergy, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Sensible Cooling Rate", + EnergyPlus::format("{} Latent Cooling Rate", prefix), Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_SensCoolEnergyRate, + thisSys.m_LatCoolEnergyRate, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Sensible Cooling Energy", + EnergyPlus::format("{} Latent Cooling Energy", prefix), Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_SensCoolEnergy, + thisSys.m_LatCoolEnergy, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Latent Heating Rate", + EnergyPlus::format("{} Electricity Rate", prefix), Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_LatHeatEnergyRate, + thisSys.m_ElecPower, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Latent Heating Energy", + EnergyPlus::format("{} Electricity Energy", prefix), Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_LatHeatEnergy, + thisSys.m_ElecPowerConsumption, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Latent Cooling Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_LatCoolEnergyRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Water to Air Heat Pump Latent Cooling Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_LatCoolEnergy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Water to Air Heat Pump Electricity Rate", - Constant::Units::W, - state.dataUnitarySystems->unitarySys[sysNum].m_ElecPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Water to Air Heat Pump Electricity Energy", - Constant::Units::J, - state.dataUnitarySystems->unitarySys[sysNum].m_ElecPowerConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Zone Water to Air Heat Pump Fan Part Load Ratio", + EnergyPlus::format("{} Fan Part Load Ratio", prefix), Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].FanPartLoadRatio, + thisSys.FanPartLoadRatio, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Compressor Part Load Ratio", + EnergyPlus::format("{} Compressor Part Load Ratio", prefix), Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_CompPartLoadRatio, + thisSys.m_CompPartLoadRatio, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); SetupOutputVariable(state, - "Zone Water to Air Heat Pump Fan Availability Status", + EnergyPlus::format("{} Fan Availability Status", prefix), Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_AvailStatus, + thisSys.m_AvailStatus, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - if (((state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPSimple || - state.dataUnitarySystems->unitarySys[sysNum].m_CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPVSEquationFit) && - state.dataUnitarySystems->unitarySys[sysNum].m_NumOfSpeedCooling > 1) || - ((state.dataUnitarySystems->unitarySys[sysNum].m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple || - state.dataUnitarySystems->unitarySys[sysNum].m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) && - state.dataUnitarySystems->unitarySys[sysNum].m_NumOfSpeedHeating > 1)) { - SetupOutputVariable(state, - "Unitary System Water Coil Multispeed Fan Cycling Ratio", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_CycRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Unitary System Water Coil Multispeed Fan Speed Ratio", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_SpeedRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); - SetupOutputVariable(state, - "Unitary System Water Coil Multispeed Fan Speed Level", - Constant::Units::None, - state.dataUnitarySystems->unitarySys[sysNum].m_SpeedNum, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - state.dataUnitarySystems->unitarySys[sysNum].Name); + thisSys.Name); + // PackagedWSHP-specific: multispeed water coil variables + if (state.dataUnitarySystems->unitarySys[sysNum].m_sysType == UnitarySys::SysType::PackagedWSHP) { + if (((thisSys.m_CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPSimple || + thisSys.m_CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPVSEquationFit) && + thisSys.m_NumOfSpeedCooling > 1) || + ((thisSys.m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple || + thisSys.m_HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) && + thisSys.m_NumOfSpeedHeating > 1)) { + SetupOutputVariable(state, + "Unitary System Water Coil Multispeed Fan Cycling Ratio", + Constant::Units::None, + thisSys.m_CycRatio, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisSys.Name); + SetupOutputVariable(state, + "Unitary System Water Coil Multispeed Fan Speed Ratio", + Constant::Units::None, + thisSys.m_SpeedRatio, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisSys.Name); + SetupOutputVariable(state, + "Unitary System Water Coil Multispeed Fan Speed Level", + Constant::Units::None, + thisSys.m_SpeedNum, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + thisSys.Name); + } } - break; + } break; default: ShowFatalError(state, "setupAllOutputVar: Developer error. All report variables must be set up here after all systems are read in."); diff --git a/src/EnergyPlus/UnitarySystem.hh b/src/EnergyPlus/UnitarySystem.hh index 545b84ec014..9cb26fcd25f 100644 --- a/src/EnergyPlus/UnitarySystem.hh +++ b/src/EnergyPlus/UnitarySystem.hh @@ -713,6 +713,13 @@ namespace UnitarySystems { int const ControlMode // temperature or humidity control mode ); + // Returns true for PackagedAC, PackagedHP, or PackagedWSHP system types. + bool isPackagedUnit() const; + + void setMergedSpeedVars(); + + void calcAuxElecPower(bool isLoading, bool lastModeMatch, Real64 loadFrac, Real64 &auxConsumption, Real64 reportingConst); + void reportUnitarySystem(EnergyPlusData &state, int const AirLoopNum); void unitarySystemHeatRecovery(EnergyPlusData &state); diff --git a/src/EnergyPlus/VariableSpeedCoils.cc b/src/EnergyPlus/VariableSpeedCoils.cc index 81eaabb93c0..3159398e556 100644 --- a/src/EnergyPlus/VariableSpeedCoils.cc +++ b/src/EnergyPlus/VariableSpeedCoils.cc @@ -205,6 +205,56 @@ namespace VariableSpeedCoils { } } + // Look up a per-speed performance curve by field name, validate dimensions, + // and optionally check that its value is near 1.0 at rated conditions. + // Returns true if an error was found. + static bool getAndCheckSpeedCurve(EnergyPlusData &state, + ErrorObjectHeader const &eoh, + InputProcessor *ip, + nlohmann::json const &fields, + nlohmann::json const &schemaProps, + int speedNum, + std::string_view fieldSuffix, // e.g. "_total_cooling_capacity_function_of_temperature_curve_name" + std::string_view displaySuffix, // e.g. " Total Cooling Capacity Function of Temperature Curve Name" + int &curveIndexOut, + std::initializer_list validDims, + std::string_view routineName, + std::string const ¤tModuleObject, + std::string const &coilName, + Real64 ratedVal1, + Real64 ratedVal2 = -999.0, // omit for 1-D curves + bool useInvalidBool = false) // use ShowSevereInvalidBool instead of ShowSevereItemNotFound + { + bool errFound = false; + std::string const fieldKey = EnergyPlus::format("speed_{}{}", speedNum, fieldSuffix); + std::string const fieldDisplay = EnergyPlus::format("Speed_{}{}", speedNum, displaySuffix); + std::string const curveName = ip->getAlphaFieldValue(fields, schemaProps, fieldKey); + + if (curveName.empty()) { + ShowWarningEmptyField(state, eoh, fieldDisplay, "Required field is blank."); + errFound = true; + } else if ((curveIndexOut = Curve::GetCurveIndex(state, curveName)) == 0) { + if (useInvalidBool) { + ShowSevereInvalidBool(state, eoh, fieldDisplay, curveName); + } else { + ShowSevereItemNotFound(state, eoh, fieldDisplay, curveName); + } + errFound = true; + } else { + errFound = Curve::CheckCurveDims(state, curveIndexOut, validDims, routineName, currentModuleObject, coilName, fieldDisplay); + if (!errFound) { + Real64 curveVal = (ratedVal2 == -999.0) ? Curve::CurveValue(state, curveIndexOut, ratedVal1) + : Curve::CurveValue(state, curveIndexOut, ratedVal1, ratedVal2); + if (curveVal > 1.10 || curveVal < 0.90) { + ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", curve values", routineName, currentModuleObject, coilName)); + ShowContinueError(state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", fieldDisplay)); + ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", curveVal)); + } + } + } + return errFound; + } + void GetVarSpeedCoilInput(EnergyPlusData &state) { @@ -225,13 +275,224 @@ namespace VariableSpeedCoils { // SUBROUTINE LOCAL VARIABLE DECLARATIONS: bool ErrorsFound(false); // If errors detected in input - Real64 CurveVal; // Used to verify modifier curves equal 1 at rated conditions Real64 WHInletAirTemp; // Used to pass proper inlet air temp to HPWH DX coil performance curves Real64 WHInletWaterTemp; // Used to pass proper inlet water temp to HPWH DX coil performance curves std::string CurrentModuleObject; // for ease in getting objects auto &s_ip = state.dataInputProcessing->inputProcessor; + // Helper: validate NumOfSpeeds >= 1 and NormSpedLevel in range, clamping NormSpedLevel if needed + auto validateNumSpeedsAndNormLevel = [&](VariableSpeedCoilData &coil, std::string_view modObj) { + if (coil.NumOfSpeeds < 1) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, modObj, coil.Name)); + ShowContinueError(state, EnergyPlus::format("...Number of Speeds must be >= 1. entered number is {:.0T}", coil.NumOfSpeeds)); + ErrorsFound = true; + } + if (coil.NormSpedLevel > coil.NumOfSpeeds) { + coil.NormSpedLevel = coil.NumOfSpeeds; + } + if ((coil.NormSpedLevel > coil.NumOfSpeeds) || (coil.NormSpedLevel <= 0)) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, modObj, coil.Name)); + ShowContinueError( + state, EnergyPlus::format("...Nominal Speed Level must be valid speed level entered number is {:.0T}", coil.NormSpedLevel)); + ErrorsFound = true; + } + }; + + // Helper: look up a PLF curve by JSON field name, validate it, and assign to varSpeedCoil.PLFFPLR + auto validatePLFCurve = [&](VariableSpeedCoilData &coil, + const ErrorObjectHeader &eoh, + std::string_view displayFieldName, + const std::string &jsonFieldName, + const nlohmann::json &fields, + const nlohmann::json &schemaProps, + std::string_view modObj) { + std::string const curveName = s_ip->getAlphaFieldValue(fields, schemaProps, jsonFieldName); + if (curveName.empty()) { + ShowWarningEmptyField(state, eoh, displayFieldName, "Required field is blank."); + ErrorsFound = true; + } else if ((coil.PLFFPLR = Curve::GetCurveIndex(state, curveName)) == 0) { + ShowSevereItemNotFound(state, eoh, displayFieldName, curveName); + ErrorsFound = true; + } else { + Real64 cv = Curve::CurveValue(state, coil.PLFFPLR, 1.0); + if (cv > 1.10 || cv < 0.90) { + ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, modObj, coil.Name)); + ShowContinueError(state, + EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", displayFieldName)); + ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", cv)); + } + } + }; + + // Helper: look up the optional crankcase heater capacity curve and validate dimensions + auto lookupCrankcaseHeaterCurve = [&](VariableSpeedCoilData &coil, + const ErrorObjectHeader &eoh, + const nlohmann::json &fields, + const nlohmann::json &schemaProps, + std::string_view modObj) { + std::string_view displayField = "Crankcase Heater Capacity Function of Temperature Curve Name"; + std::string curveName = s_ip->getAlphaFieldValue(fields, schemaProps, "crankcase_heater_capacity_function_of_temperature_curve_name"); + if (!curveName.empty()) { + coil.CrankcaseHeaterCapacityCurveIndex = Curve::GetCurveIndex(state, curveName); + if (coil.CrankcaseHeaterCapacityCurveIndex == 0) { + ShowSevereItemNotFound(state, eoh, displayField, curveName); + ErrorsFound = true; + } else { + ErrorsFound |= + Curve::CheckCurveDims(state, coil.CrankcaseHeaterCapacityCurveIndex, {1}, RoutineName, modObj, coil.Name, displayField); + } + } + }; + + // Helper: register the common energy output variables for cooling or heating coils + // (Electricity Energy, Total Cooling/Heating Energy, and for cooling: Sensible + Latent Energy) + auto setupEnergyOutputVars = [&state](VariableSpeedCoilData &c, bool isCooling) { + std::string_view prefix = isCooling ? "Cooling Coil" : "Heating Coil"; + auto endUseCat = isCooling ? OutputProcessor::EndUseCat::Cooling : OutputProcessor::EndUseCat::Heating; + auto coilsEndUseCat = isCooling ? OutputProcessor::EndUseCat::CoolingCoils : OutputProcessor::EndUseCat::HeatingCoils; + SetupOutputVariable(state, + EnergyPlus::format("{} Electricity Energy", prefix), + Constant::Units::J, + c.Energy, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + c.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::HVAC, + endUseCat); + std::string totalName = isCooling ? "Cooling Coil Total Cooling Energy" : "Heating Coil Heating Energy"; + SetupOutputVariable(state, + totalName, + Constant::Units::J, + c.EnergyLoadTotal, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + c.Name, + Constant::eResource::EnergyTransfer, + OutputProcessor::Group::HVAC, + coilsEndUseCat); + if (isCooling) { + SetupOutputVariable(state, + "Cooling Coil Sensible Cooling Energy", + Constant::Units::J, + c.EnergySensible, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Latent Cooling Energy", + Constant::Units::J, + c.EnergyLatent, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + c.Name); + } + }; + + // Helper: read and validate the availability schedule + auto readAvailSchedule = + [&](VariableSpeedCoilData &coil, const ErrorObjectHeader &eoh, const nlohmann::json &fields, const nlohmann::json &schemaProps) { + std::string const schedName = s_ip->getAlphaFieldValue(fields, schemaProps, "availability_schedule_name"); + if (schedName.empty()) { + coil.availSched = Sched::GetScheduleAlwaysOn(state); + } else if ((coil.availSched = Sched::GetSchedule(state, schedName)) == nullptr) { + ShowSevereItemNotFound(state, eoh, "Availability Schedule Name", schedName); + ErrorsFound = true; + } + }; + + // Helper: compute per-speed scale values (percent total capacity, air/water/evapCond volume flow per rated total cap, etc.) + auto computeScaleValues = [](VariableSpeedCoilData &coil, bool hasWater, bool hasEvapCond, bool hasPumpPower) { + Real64 maxCap = coil.MSRatedTotCap(coil.NumOfSpeeds); + for (int I = 1; I <= coil.NumOfSpeeds; ++I) { + Real64 capI = coil.MSRatedTotCap(I); + coil.MSRatedPercentTotCap(I) = capI / maxCap; + coil.MSRatedAirVolFlowPerRatedTotCap(I) = coil.MSRatedAirVolFlowRate(I) / capI; + if (hasWater) { + coil.MSRatedWaterVolFlowPerRatedTotCap(I) = coil.MSRatedWaterVolFlowRate(I) / capI; + } + if (hasEvapCond) { + coil.MSRatedEvapCondVolFlowPerRatedTotCap(I) = coil.EvapCondAirFlow(I) / capI; + } + if (hasPumpPower) { + coil.MSWHPumpPowerPerRatedTotCap(I) = coil.MSWHPumpPower(I) / capI; + } + } + }; + + // Helper: read crankcase heater capacity, validate >= 0, set ErrorsFound if invalid + auto readCrankcaseHeaterCapacity = + [&](VariableSpeedCoilData &coil, const nlohmann::json &fields, const nlohmann::json &schemaProps, std::string_view modObj) { + coil.CrankcaseHeaterCapacity = s_ip->getRealFieldValue(fields, schemaProps, "crankcase_heater_capacity"); + if (coil.CrankcaseHeaterCapacity < 0.0) { + ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, modObj, coil.Name)); + ShowContinueError(state, "...Crankcase Heater Capacity cannot be < 0.0."); + ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", coil.CrankcaseHeaterCapacity)); + ErrorsFound = true; + } + }; + + // Helper: register air inlet/outlet nodes, call TestCompSet, and return the node names + auto registerAirNodes = [&](VariableSpeedCoilData &coil, + Node::ConnectionObjectType connType, + const nlohmann::json &fields, + const nlohmann::json &schemaProps, + std::string const &inletField, + std::string const &outletField) { + std::string inName = s_ip->getAlphaFieldValue(fields, schemaProps, inletField); + std::string outName = s_ip->getAlphaFieldValue(fields, schemaProps, outletField); + coil.AirInletNodeNum = GetOnlySingleNode(state, + inName, + ErrorsFound, + connType, + coil.Name, + Node::FluidType::Air, + Node::ConnectionType::Inlet, + Node::CompFluidStream::Primary, + Node::ObjectIsNotParent); + coil.AirOutletNodeNum = GetOnlySingleNode(state, + outName, + ErrorsFound, + connType, + coil.Name, + Node::FluidType::Air, + Node::ConnectionType::Outlet, + Node::CompFluidStream::Primary, + Node::ObjectIsNotParent); + Node::TestCompSet(state, CurrentModuleObject, coil.Name, inName, outName, "Air Nodes"); + }; + + // Helper: register water inlet/outlet nodes and call TestCompSet + auto registerWaterNodes = [&](VariableSpeedCoilData &coil, + Node::ConnectionObjectType connType, + const nlohmann::json &fields, + const nlohmann::json &schemaProps, + std::string const &inletField, + std::string const &outletField) { + std::string inName = s_ip->getAlphaFieldValue(fields, schemaProps, inletField); + std::string outName = s_ip->getAlphaFieldValue(fields, schemaProps, outletField); + coil.WaterInletNodeNum = GetOnlySingleNode(state, + inName, + ErrorsFound, + connType, + coil.Name, + Node::FluidType::Water, + Node::ConnectionType::Inlet, + Node::CompFluidStream::Secondary, + Node::ObjectIsNotParent); + coil.WaterOutletNodeNum = GetOnlySingleNode(state, + outName, + ErrorsFound, + connType, + coil.Name, + Node::FluidType::Water, + Node::ConnectionType::Outlet, + Node::CompFluidStream::Secondary, + Node::ObjectIsNotParent); + Node::TestCompSet(state, CurrentModuleObject, coil.Name, inName, outName, "Water Nodes"); + }; + int NumCool = s_ip->getNumObjectsFound(state, "COIL:COOLING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT"); int NumHeat = s_ip->getNumObjectsFound(state, "COIL:HEATING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT"); int NumCoolAS = s_ip->getNumObjectsFound(state, "COIL:COOLING:DX:VARIABLESPEED"); @@ -279,13 +540,7 @@ namespace VariableSpeedCoils { state.dataHeatBal->HeatReclaimVS_Coil(DXCoilNum).SourceType = CurrentModuleObject; varSpeedCoil.VSCoilType = HVAC::Coil_CoolingWaterToAirHPVSEquationFit; varSpeedCoil.VarSpeedCoilType = HVAC::cAllCoilTypes(varSpeedCoil.VSCoilType); - std::string const availSchedName = s_ip->getAlphaFieldValue(fields, schemaProps, "availability_schedule_name"); - if (availSchedName.empty()) { - varSpeedCoil.availSched = Sched::GetScheduleAlwaysOn(state); - } else if ((varSpeedCoil.availSched = Sched::GetSchedule(state, availSchedName)) == nullptr) { - ShowSevereItemNotFound(state, eoh, "Availability Schedule Name", availSchedName); - ErrorsFound = true; - } + readAvailSchedule(varSpeedCoil, eoh, fields, schemaProps); varSpeedCoil.NumOfSpeeds = s_ip->getIntFieldValue(fields, schemaProps, "number_of_speeds"); varSpeedCoil.NormSpedLevel = s_ip->getIntFieldValue(fields, schemaProps, "nominal_speed_level"); varSpeedCoil.RatedCapCoolTotal = @@ -302,89 +557,29 @@ namespace VariableSpeedCoils { varSpeedCoil.FanDelayTime = s_ip->getRealFieldValue(fields, schemaProps, "fan_delay_time"); varSpeedCoil.HOTGASREHEATFLG = s_ip->getIntFieldValue(fields, schemaProps, "flag_for_using_hot_gas_reheat_0_or_1"); varSpeedCoil.CondenserType = DataHeatBalance::RefrigCondenserType::Water; - std::string waterInletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "water_to_refrigerant_hx_water_inlet_node_name"); - std::string waterOutletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "water_to_refrigerant_hx_water_outlet_node_name"); - std::string airInletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "indoor_air_inlet_node_name"); - std::string airOutletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "indoor_air_outlet_node_name"); - - varSpeedCoil.WaterInletNodeNum = GetOnlySingleNode(state, - waterInletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilCoolingWaterToAirHeatPumpVariableSpeedEquationFit, - varSpeedCoil.Name, - Node::FluidType::Water, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Secondary, - Node::ObjectIsNotParent); - varSpeedCoil.WaterOutletNodeNum = GetOnlySingleNode(state, - waterOutletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilCoolingWaterToAirHeatPumpVariableSpeedEquationFit, - varSpeedCoil.Name, - Node::FluidType::Water, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Secondary, - Node::ObjectIsNotParent); - varSpeedCoil.AirInletNodeNum = GetOnlySingleNode(state, - airInletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilCoolingWaterToAirHeatPumpVariableSpeedEquationFit, - varSpeedCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - varSpeedCoil.AirOutletNodeNum = GetOnlySingleNode(state, - airOutletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilCoolingWaterToAirHeatPumpVariableSpeedEquationFit, - varSpeedCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - - Node::TestCompSet(state, CurrentModuleObject, varSpeedCoil.Name, waterInletNodeName, waterOutletNodeName, "Water Nodes"); - Node::TestCompSet(state, CurrentModuleObject, varSpeedCoil.Name, airInletNodeName, airOutletNodeName, "Air Nodes"); - - cFieldName = "Number of Speeds"; - if (varSpeedCoil.NumOfSpeeds < 1) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{} must be >= 1. entered number is {:.0T}", cFieldName, varSpeedCoil.NumOfSpeeds)); - ErrorsFound = true; - } - - if (varSpeedCoil.NormSpedLevel > varSpeedCoil.NumOfSpeeds) { - varSpeedCoil.NormSpedLevel = varSpeedCoil.NumOfSpeeds; - } - cFieldName = "Nominal Speed Level"; - if ((varSpeedCoil.NormSpedLevel > varSpeedCoil.NumOfSpeeds) || (varSpeedCoil.NormSpedLevel <= 0)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} must be valid speed level entered number is {:.0T}", cFieldName, varSpeedCoil.NormSpedLevel)); - ErrorsFound = true; - } + registerWaterNodes(varSpeedCoil, + Node::ConnectionObjectType::CoilCoolingWaterToAirHeatPumpVariableSpeedEquationFit, + fields, + schemaProps, + "water_to_refrigerant_hx_water_inlet_node_name", + "water_to_refrigerant_hx_water_outlet_node_name"); + registerAirNodes(varSpeedCoil, + Node::ConnectionObjectType::CoilCoolingWaterToAirHeatPumpVariableSpeedEquationFit, + fields, + schemaProps, + "indoor_air_inlet_node_name", + "indoor_air_outlet_node_name"); + + validateNumSpeedsAndNormLevel(varSpeedCoil, CurrentModuleObject); // part load curve - cFieldName = "Energy Part Load Fraction Curve Name"; // cAlphaFields(6) - std::string const coolPLFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, "energy_part_load_fraction_curve_name"); - if (coolPLFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.PLFFPLR = Curve::GetCurveIndex(state, coolPLFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, coolPLFCurveName); - ErrorsFound = true; - } else { - CurveVal = Curve::CurveValue(state, varSpeedCoil.PLFFPLR, 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } + validatePLFCurve(varSpeedCoil, + eoh, + "Energy Part Load Fraction Curve Name", + "energy_part_load_fraction_curve_name", + fields, + schemaProps, + CurrentModuleObject); for (int I = 1; I <= varSpeedCoil.NumOfSpeeds; ++I) { std::string fieldName; @@ -402,282 +597,120 @@ namespace VariableSpeedCoils { EnergyPlus::format("speed_{}{}", std::to_string(I), "_reference_unit_waste_heat_fraction_of_input_power_at_rated_conditions"); varSpeedCoil.MSWasteHeatFrac(I) = s_ip->getRealFieldValue(fields, schemaProps, fieldName); - std::string fieldValue = - EnergyPlus::format("speed_{}{}", std::to_string(I), "_total_cooling_capacity_function_of_temperature_curve_name"); - std::string cFieldName_curve = - EnergyPlus::format("Speed_{}{}", std::to_string(I), " Total Cooling Capacity Function of Temperature Curve Name"); - std::string const coolCapFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (coolCapFTCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName_curve, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapFTemp(I) = Curve::GetCurveIndex(state, coolCapFTCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName_curve, coolCapFTCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName_curve); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapFTemp(I), RatedInletWetBulbTemp, RatedInletWaterTemp); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName_curve)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - fieldValue = - EnergyPlus::format("speed_{}{}", std::to_string(I), "_total_cooling_capacity_function_of_air_flow_fraction_curve_name"); - cFieldName_curve = - EnergyPlus::format("Speed_{}{}", std::to_string(I), " Total Cooling Capacity Function of Air Flow Fraction Curve Name"); - std::string const coolCapFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (coolCapFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName_curve, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapAirFFlow(I) = Curve::GetCurveIndex(state, coolCapFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName_curve, coolCapFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapAirFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName_curve); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapAirFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName_curve)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - fieldValue = - EnergyPlus::format("speed_{}{}", std::to_string(I), "_total_cooling_capacity_function_of_water_flow_fraction_curve_name"); - cFieldName_curve = - EnergyPlus::format("Speed_{}{}", std::to_string(I), " Total Cooling Capacity Function of Water Flow Fraction Curve Name"); - std::string const coolCapWFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (coolCapWFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName_curve, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapWaterFFlow(I) = Curve::GetCurveIndex(state, coolCapWFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName_curve, coolCapWFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapWaterFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName_curve); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapWaterFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName_curve)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_energy_input_ratio_function_of_temperature_curve_name"); - cFieldName_curve = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Energy Input Ratio Function of Temperature Curve Name"); - std::string const coolEIRFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (coolEIRFTCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName_curve, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRFTemp(I) = Curve::GetCurveIndex(state, coolEIRFTCurveName)) == 0) { - ShowSevereInvalidBool(state, eoh, cFieldName_curve, coolEIRFTCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName_curve); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRFTemp(I), RatedInletWetBulbTemp, RatedInletWaterTemp); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName_curve)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_energy_input_ratio_function_of_air_flow_fraction_curve_name"); - cFieldName_curve = - EnergyPlus::format("Speed_{}{}", std::to_string(I), " Energy Input Ratio Function of Air Flow Fraction Curve Name"); - std::string const coolEIRFFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (coolEIRFFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName_curve, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRAirFFlow(I) = Curve::GetCurveIndex(state, coolEIRFFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName_curve, coolEIRFFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRAirFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName_curve); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRAirFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName_curve)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - fieldValue = - EnergyPlus::format("speed_{}{}", std::to_string(I), "_energy_input_ratio_function_of_water_flow_fraction_curve_name"); - cFieldName_curve = - EnergyPlus::format("Speed_{}{}", std::to_string(I), " Energy Input Ratio Function of Water Flow Fraction Curve Name"); - std::string const coolEIRWFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (coolEIRWFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName_curve, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRWaterFFlow(I) = Curve::GetCurveIndex(state, coolEIRWFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName_curve, coolEIRWFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRWaterFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName_curve); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRWaterFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName_curve)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - // Read waste heat modifier curve name - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_waste_heat_function_of_temperature_curve_name"); - cFieldName_curve = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Waste Heat Function of Temperature Curve Name"); - std::string const wasteHFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (wasteHFTCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName_curve, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSWasteHeat(I) = Curve::GetCurveIndex(state, wasteHFTCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName_curve, wasteHFTCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal types are BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSWasteHeat(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName_curve); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSWasteHeat(I), RatedInletWaterTemp, RatedInletAirTemp); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName_curve)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_total_cooling_capacity_function_of_temperature_curve_name", + " Total Cooling Capacity Function of Temperature Curve Name", + varSpeedCoil.MSCCapFTemp(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + RatedInletWetBulbTemp, + RatedInletWaterTemp); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_total_cooling_capacity_function_of_air_flow_fraction_curve_name", + " Total Cooling Capacity Function of Air Flow Fraction Curve Name", + varSpeedCoil.MSCCapAirFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_total_cooling_capacity_function_of_water_flow_fraction_curve_name", + " Total Cooling Capacity Function of Water Flow Fraction Curve Name", + varSpeedCoil.MSCCapWaterFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_energy_input_ratio_function_of_temperature_curve_name", + " Energy Input Ratio Function of Temperature Curve Name", + varSpeedCoil.MSEIRFTemp(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + RatedInletWetBulbTemp, + RatedInletWaterTemp, + true); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_energy_input_ratio_function_of_air_flow_fraction_curve_name", + " Energy Input Ratio Function of Air Flow Fraction Curve Name", + varSpeedCoil.MSEIRAirFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_energy_input_ratio_function_of_water_flow_fraction_curve_name", + " Energy Input Ratio Function of Water Flow Fraction Curve Name", + varSpeedCoil.MSEIRWaterFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_waste_heat_function_of_temperature_curve_name", + " Waste Heat Function of Temperature Curve Name", + varSpeedCoil.MSWasteHeat(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + RatedInletWaterTemp, + RatedInletAirTemp); } - for (int I = 1; I <= varSpeedCoil.NumOfSpeeds; ++I) { - varSpeedCoil.MSRatedPercentTotCap(I) = varSpeedCoil.MSRatedTotCap(I) / varSpeedCoil.MSRatedTotCap(varSpeedCoil.NumOfSpeeds); - varSpeedCoil.MSRatedAirVolFlowPerRatedTotCap(I) = varSpeedCoil.MSRatedAirVolFlowRate(I) / varSpeedCoil.MSRatedTotCap(I); - varSpeedCoil.MSRatedWaterVolFlowPerRatedTotCap(I) = varSpeedCoil.MSRatedWaterVolFlowRate(I) / varSpeedCoil.MSRatedTotCap(I); - } + computeScaleValues(varSpeedCoil, true, false, false); // CurrentModuleObject = "Coil:Cooling:WaterToAirHeatPump:VariableSpeedEquationFit" - SetupOutputVariable(state, - "Cooling Coil Electricity Energy", - Constant::Units::J, - varSpeedCoil.Energy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - SetupOutputVariable(state, - "Cooling Coil Total Cooling Energy", - Constant::Units::J, - varSpeedCoil.EnergyLoadTotal, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::CoolingCoils); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Energy", - Constant::Units::J, - varSpeedCoil.EnergySensible, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Energy", - Constant::Units::J, - varSpeedCoil.EnergyLatent, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name); + setupEnergyOutputVars(varSpeedCoil, true); SetupOutputVariable(state, "Cooling Coil Source Side Heat Transfer Energy", Constant::Units::J, @@ -722,13 +755,7 @@ namespace VariableSpeedCoils { varSpeedCoil.CoolHeatType = "COOLING"; varSpeedCoil.VSCoilType = HVAC::Coil_CoolingAirToAirVariableSpeed; varSpeedCoil.VarSpeedCoilType = HVAC::cAllCoilTypes(varSpeedCoil.VSCoilType); - std::string const availSchedName = s_ip->getAlphaFieldValue(fields, schemaProps, "availability_schedule_name"); - if (availSchedName.empty()) { - varSpeedCoil.availSched = Sched::GetScheduleAlwaysOn(state); - } else if ((varSpeedCoil.availSched = Sched::GetSchedule(state, availSchedName)) == nullptr) { - ShowSevereItemNotFound(state, eoh, "Availability Schedule Name", availSchedName); - ErrorsFound = true; - } + readAvailSchedule(varSpeedCoil, eoh, fields, schemaProps); varSpeedCoil.NumOfSpeeds = s_ip->getIntFieldValue(fields, schemaProps, "number_of_speeds"); varSpeedCoil.NormSpedLevel = s_ip->getIntFieldValue(fields, schemaProps, "nominal_speed_level"); if (fields.find("gross_rated_total_cooling_capacity_at_selected_nominal_speed_level") != fields.end()) { @@ -745,66 +772,23 @@ namespace VariableSpeedCoils { varSpeedCoil.MaxONOFFCyclesperHour = s_ip->getRealFieldValue(fields, schemaProps, "maximum_cycling_rate"); varSpeedCoil.LatentCapacityTimeConstant = s_ip->getRealFieldValue(fields, schemaProps, "latent_capacity_time_constant"); varSpeedCoil.FanDelayTime = s_ip->getRealFieldValue(fields, schemaProps, "fan_delay_time"); - std::string airInletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "indoor_air_inlet_node_name"); - std::string airOutletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "indoor_air_outlet_node_name"); - varSpeedCoil.AirInletNodeNum = GetOnlySingleNode(state, - airInletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilCoolingDXVariableSpeed, - varSpeedCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - varSpeedCoil.AirOutletNodeNum = GetOnlySingleNode(state, - airOutletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilCoolingDXVariableSpeed, - varSpeedCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - - Node::TestCompSet(state, CurrentModuleObject, varSpeedCoil.Name, airInletNodeName, airOutletNodeName, "Air Nodes"); - - cFieldName = "Number of Speeds"; - if (varSpeedCoil.NumOfSpeeds < 1) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{} must be >= 1. entered number is {:.0T}", cFieldName, varSpeedCoil.NumOfSpeeds)); - ErrorsFound = true; - } - if (varSpeedCoil.NormSpedLevel > varSpeedCoil.NumOfSpeeds) { - varSpeedCoil.NormSpedLevel = varSpeedCoil.NumOfSpeeds; - } - cFieldName = "Nominal Speed Level"; - if ((varSpeedCoil.NormSpedLevel > varSpeedCoil.NumOfSpeeds) || (varSpeedCoil.NormSpedLevel <= 0)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} must be valid speed level entered number is {:.0T}", cFieldName, varSpeedCoil.NormSpedLevel)); - ErrorsFound = true; - } + registerAirNodes(varSpeedCoil, + Node::ConnectionObjectType::CoilCoolingDXVariableSpeed, + fields, + schemaProps, + "indoor_air_inlet_node_name", + "indoor_air_outlet_node_name"); + + validateNumSpeedsAndNormLevel(varSpeedCoil, CurrentModuleObject); // part load curve - cFieldName = "Energy Part Load Fraction Curve Name"; // cAlphaFields(4) - std::string const coolPLFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, "energy_part_load_fraction_curve_name"); - if (coolPLFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.PLFFPLR = Curve::GetCurveIndex(state, coolPLFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, coolPLFCurveName); - ErrorsFound = true; - } else { - CurveVal = Curve::CurveValue(state, varSpeedCoil.PLFFPLR, 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } + validatePLFCurve(varSpeedCoil, + eoh, + "Energy Part Load Fraction Curve Name", + "energy_part_load_fraction_curve_name", + fields, + schemaProps, + CurrentModuleObject); cFieldName = "Condenser Air Inlet Node Name"; // cAlphaFields(10) std::string condenserAirInletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "condenser_air_inlet_node_name"); @@ -867,14 +851,7 @@ namespace VariableSpeedCoils { } // Set crankcase heater capacity - cFieldName = "Crankcase Heater Capacity"; // cNumericFields(11) - varSpeedCoil.CrankcaseHeaterCapacity = s_ip->getRealFieldValue(fields, schemaProps, "crankcase_heater_capacity"); // NumArray(11); - if (varSpeedCoil.CrankcaseHeaterCapacity < 0.0) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} cannot be < 0.0.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", varSpeedCoil.CrankcaseHeaterCapacity)); - ErrorsFound = true; - } + readCrankcaseHeaterCapacity(varSpeedCoil, fields, schemaProps, CurrentModuleObject); // Set crankcase heater cutout temperature varSpeedCoil.MaxOATCrankcaseHeater = @@ -882,28 +859,7 @@ namespace VariableSpeedCoils { // Set compressor cutout temperature varSpeedCoil.MinOATCompressor = s_ip->getRealFieldValue(fields, schemaProps, "minimum_outdoor_dry_bulb_temperature_for_compressor_operation"); - // A7; \field Crankcase Heater Capacity Function of Outdoor Temperature Curve Name - cFieldName = "Crankcase Heater Capacity Function of Temperature Curve Name"; // cAlphaFields(7) - std::string crankcaseHeaterCapCurveName = - s_ip->getAlphaFieldValue(fields, schemaProps, "crankcase_heater_capacity_function_of_temperature_curve_name"); - if (!crankcaseHeaterCapCurveName.empty()) { - varSpeedCoil.CrankcaseHeaterCapacityCurveIndex = Curve::GetCurveIndex(state, crankcaseHeaterCapCurveName); - if (varSpeedCoil.CrankcaseHeaterCapacityCurveIndex == 0) { // can't find the curve - ShowSevereError( - state, - EnergyPlus::format( - "{} = {}: {} not found = {}", CurrentModuleObject, varSpeedCoil.Name, cFieldName, crankcaseHeaterCapCurveName)); - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.CrankcaseHeaterCapacityCurveIndex, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - } - } + lookupCrankcaseHeaterCurve(varSpeedCoil, eoh, fields, schemaProps, CurrentModuleObject); // Get Water System tank connections // A8, \field Name of Water Storage Tank for Supply @@ -997,188 +953,81 @@ namespace VariableSpeedCoils { ErrorsFound = true; } - std::string fieldValue = - EnergyPlus::format("speed_{}{}", std::to_string(I), "_total_cooling_capacity_function_of_temperature_curve_name"); - std::string cFieldName_curve = - EnergyPlus::format("Speed_{}{}", std::to_string(I), " Total Cooling Capacity Function of Temperature Curve Name"); - std::string const cCapFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (cCapFTCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName_curve, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapFTemp(I) = Curve::GetCurveIndex(state, cCapFTCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName_curve, cCapFTCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName_curve); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapFTemp(I), RatedInletWetBulbTemp, RatedAmbAirTemp); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName_curve)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_total_cooling_capacity_function_of_temperature_curve_name", + " Total Cooling Capacity Function of Temperature Curve Name", + varSpeedCoil.MSCCapFTemp(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + RatedInletWetBulbTemp, + RatedAmbAirTemp); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_total_cooling_capacity_function_of_air_flow_fraction_curve_name", + " Total Cooling Capacity Function of Air Flow Fraction Curve Name", + varSpeedCoil.MSCCapAirFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_energy_input_ratio_function_of_temperature_curve_name", + " Energy Input Ratio Function of Temperature Curve Name", + varSpeedCoil.MSEIRFTemp(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + RatedInletWetBulbTemp, + RatedAmbAirTemp, + true); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_energy_input_ratio_function_of_air_flow_fraction_curve_name", + " Energy Input Ratio Function of Air Flow Fraction Curve Name", + varSpeedCoil.MSEIRAirFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + } - fieldValue = - EnergyPlus::format("speed_{}{}", std::to_string(I), "_total_cooling_capacity_function_of_air_flow_fraction_curve_name"); - cFieldName_curve = - EnergyPlus::format("Speed_{}{}", std::to_string(I), " Total Cooling Capacity Function of Air Flow Fraction Curve Name"); - std::string const cCapFFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (cCapFFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName_curve, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapAirFFlow(I) = Curve::GetCurveIndex(state, cCapFFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName_curve, cCapFFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapAirFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName_curve); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapAirFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName_curve)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } + computeScaleValues(varSpeedCoil, false, true, false); - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_energy_input_ratio_function_of_temperature_curve_name"); - cFieldName_curve = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Energy Input Ratio Function of Temperature Curve Name"); - std::string const cEIRFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (cEIRFTCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName_curve, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRFTemp(I) = Curve::GetCurveIndex(state, cEIRFTCurveName)) == 0) { - ShowSevereInvalidBool(state, eoh, cFieldName_curve, cEIRFTCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName_curve); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRFTemp(I), RatedInletWetBulbTemp, RatedAmbAirTemp); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName_curve)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_energy_input_ratio_function_of_air_flow_fraction_curve_name"); - cFieldName_curve = - EnergyPlus::format("Speed_{}{}", std::to_string(I), " Energy Input Ratio Function of Air Flow Fraction Curve Name"); - std::string const cEIRFFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (cEIRFFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName_curve, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRAirFFlow(I) = Curve::GetCurveIndex(state, cEIRFFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName_curve, cEIRFFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRAirFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName_curve); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRAirFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName_curve)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - } - - for (int I = 1; I <= varSpeedCoil.NumOfSpeeds; ++I) { - varSpeedCoil.MSRatedPercentTotCap(I) = varSpeedCoil.MSRatedTotCap(I) / varSpeedCoil.MSRatedTotCap(varSpeedCoil.NumOfSpeeds); - varSpeedCoil.MSRatedAirVolFlowPerRatedTotCap(I) = varSpeedCoil.MSRatedAirVolFlowRate(I) / varSpeedCoil.MSRatedTotCap(I); - varSpeedCoil.MSRatedEvapCondVolFlowPerRatedTotCap(I) = varSpeedCoil.EvapCondAirFlow(I) / varSpeedCoil.MSRatedTotCap(I); - } - - // CurrentModuleObject = "Coil:Cooling:DX:VariableSpeed" - SetupOutputVariable(state, - "Cooling Coil Electricity Energy", - Constant::Units::J, - varSpeedCoil.Energy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - SetupOutputVariable(state, - "Cooling Coil Total Cooling Energy", - Constant::Units::J, - varSpeedCoil.EnergyLoadTotal, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::CoolingCoils); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Energy", - Constant::Units::J, - varSpeedCoil.EnergySensible, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Energy", - Constant::Units::J, - varSpeedCoil.EnergyLatent, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Source Side Heat Transfer Energy", - Constant::Units::J, - varSpeedCoil.EnergySource, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name); + // CurrentModuleObject = "Coil:Cooling:DX:VariableSpeed" + setupEnergyOutputVars(varSpeedCoil, true); + SetupOutputVariable(state, + "Cooling Coil Source Side Heat Transfer Energy", + Constant::Units::J, + varSpeedCoil.EnergySource, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + varSpeedCoil.Name); varSpeedCoil.RatedCapCoolSens = DataSizing::AutoSize; // always auto-sized, to be determined in the sizing calculation } @@ -1209,13 +1058,7 @@ namespace VariableSpeedCoils { varSpeedCoil.VSCoilType = HVAC::Coil_HeatingWaterToAirHPVSEquationFit; varSpeedCoil.VarSpeedCoilType = HVAC::cAllCoilTypes(varSpeedCoil.VSCoilType); varSpeedCoil.CondenserType = DataHeatBalance::RefrigCondenserType::Water; - std::string const availSchedName = s_ip->getAlphaFieldValue(fields, schemaProps, "availability_schedule_name"); - if (availSchedName.empty()) { - varSpeedCoil.availSched = Sched::GetScheduleAlwaysOn(state); - } else if ((varSpeedCoil.availSched = Sched::GetSchedule(state, availSchedName)) == nullptr) { - ShowSevereItemNotFound(state, eoh, "Availability Schedule Name", availSchedName); - ErrorsFound = true; - } + readAvailSchedule(varSpeedCoil, eoh, fields, schemaProps); varSpeedCoil.NumOfSpeeds = s_ip->getIntFieldValue(fields, schemaProps, "number_of_speeds"); varSpeedCoil.NormSpedLevel = s_ip->getIntFieldValue(fields, schemaProps, "nominal_speed_level"); varSpeedCoil.RatedCapHeat = s_ip->getRealFieldValue(fields, schemaProps, "rated_heating_capacity_at_selected_nominal_speed_level"); @@ -1228,89 +1071,28 @@ namespace VariableSpeedCoils { varSpeedCoil.LatentCapacityTimeConstant = 0.; varSpeedCoil.FanDelayTime = 0.; - std::string waterInletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "water_to_refrigerant_hx_water_inlet_node_name"); - std::string waterOutletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "water_to_refrigerant_hx_water_outlet_node_name"); - std::string airInletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "indoor_air_inlet_node_name"); - std::string airOutletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "indoor_air_outlet_node_name"); - - varSpeedCoil.WaterInletNodeNum = GetOnlySingleNode(state, - waterInletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilHeatingWaterToAirHeatPumpVariableSpeedEquationFit, - varSpeedCoil.Name, - Node::FluidType::Water, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Secondary, - Node::ObjectIsNotParent); - varSpeedCoil.WaterOutletNodeNum = GetOnlySingleNode(state, - waterOutletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilHeatingWaterToAirHeatPumpVariableSpeedEquationFit, - varSpeedCoil.Name, - Node::FluidType::Water, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Secondary, - Node::ObjectIsNotParent); - varSpeedCoil.AirInletNodeNum = GetOnlySingleNode(state, - airInletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilHeatingWaterToAirHeatPumpVariableSpeedEquationFit, - varSpeedCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - varSpeedCoil.AirOutletNodeNum = GetOnlySingleNode(state, - airOutletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilHeatingWaterToAirHeatPumpVariableSpeedEquationFit, - varSpeedCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - - Node::TestCompSet(state, CurrentModuleObject, varSpeedCoil.Name, waterInletNodeName, waterOutletNodeName, "Water Nodes"); - Node::TestCompSet(state, CurrentModuleObject, varSpeedCoil.Name, airInletNodeName, airOutletNodeName, "Air Nodes"); - - cFieldName = "Number of Speeds"; - // If (VarSpeedCoil(DXCoilNum)%NumOfSpeeds .LT. 2) Then - if (varSpeedCoil.NumOfSpeeds < 1) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{} must be >= 1. entered number is {:.0T}", cFieldName, varSpeedCoil.NumOfSpeeds)); - ErrorsFound = true; - } - - if (varSpeedCoil.NormSpedLevel > varSpeedCoil.NumOfSpeeds) { - varSpeedCoil.NormSpedLevel = varSpeedCoil.NumOfSpeeds; - } - cFieldName = "Nominal Speed Level"; - if ((varSpeedCoil.NormSpedLevel > varSpeedCoil.NumOfSpeeds) || (varSpeedCoil.NormSpedLevel <= 0)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} must be valid speed level entered number is {:.0T}", cFieldName, varSpeedCoil.NormSpedLevel)); - ErrorsFound = true; - } + registerWaterNodes(varSpeedCoil, + Node::ConnectionObjectType::CoilHeatingWaterToAirHeatPumpVariableSpeedEquationFit, + fields, + schemaProps, + "water_to_refrigerant_hx_water_inlet_node_name", + "water_to_refrigerant_hx_water_outlet_node_name"); + registerAirNodes(varSpeedCoil, + Node::ConnectionObjectType::CoilHeatingWaterToAirHeatPumpVariableSpeedEquationFit, + fields, + schemaProps, + "indoor_air_inlet_node_name", + "indoor_air_outlet_node_name"); + + validateNumSpeedsAndNormLevel(varSpeedCoil, CurrentModuleObject); // part load curve - cFieldName = "Energy Part Load Fraction Curve Name"; // cAlphaFields(6) - std::string const heatPLFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, "energy_part_load_fraction_curve_name"); - if (heatPLFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.PLFFPLR = Curve::GetCurveIndex(state, heatPLFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, heatPLFCurveName); - ErrorsFound = true; - } else { - CurveVal = Curve::CurveValue(state, varSpeedCoil.PLFFPLR, 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } + validatePLFCurve(varSpeedCoil, + eoh, + "Energy Part Load Fraction Curve Name", + "energy_part_load_fraction_curve_name", + fields, + schemaProps, + CurrentModuleObject); for (int I = 1; I <= varSpeedCoil.NumOfSpeeds; ++I) { std::string fieldName; @@ -1327,256 +1109,120 @@ namespace VariableSpeedCoils { EnergyPlus::format("speed_{}{}", std::to_string(I), "_reference_unit_waste_heat_fraction_of_input_power_at_rated_conditions"); varSpeedCoil.MSWasteHeatFrac(I) = s_ip->getRealFieldValue(fields, schemaProps, fieldName); - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_heating_capacity_function_of_temperature_curve_name"); - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Heating Capacity Function of Temperature Curve Name"); - std::string const heatCapFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (heatCapFTCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapFTemp(I) = Curve::GetCurveIndex(state, heatCapFTCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, heatCapFTCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapFTemp(I), RatedInletAirTempHeat, RatedInletWaterTempHeat); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - fieldValue = - EnergyPlus::format("speed_{}{}", std::to_string(I), "_total_heating_capacity_function_of_air_flow_fraction_curve_name"); - cFieldName = - EnergyPlus::format("Speed_{}{}", std::to_string(I), " Total Heating Capacity Function of Air Flow Fraction Curve Name"); - std::string const heatCapFFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (heatCapFFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapAirFFlow(I) = Curve::GetCurveIndex(state, heatCapFFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, heatCapFFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapAirFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapAirFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_heating_capacity_function_of_water_flow_fraction_curve_name"); - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Heating Capacity Function of Water Flow Fraction Curve Name"); - std::string const heatCapWFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (heatCapWFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapWaterFFlow(I) = Curve::GetCurveIndex(state, heatCapWFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, heatCapWFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapWaterFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapWaterFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_energy_input_ratio_function_of_temperature_curve_name"); - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Energy Input Ratio Function of Temperature Curve Name"); - std::string const heatEIRFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (heatEIRFTCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRFTemp(I) = Curve::GetCurveIndex(state, heatEIRFTCurveName)) == 0) { - ShowSevereInvalidBool(state, eoh, cFieldName, heatEIRFTCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRFTemp(I), RatedInletAirTempHeat, RatedInletWaterTempHeat); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_energy_input_ratio_function_of_air_flow_fraction_curve_name"); - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Energy Input Ratio Function of Air Flow Fraction Curve Name"); - std::string const heatEIRFFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (heatEIRFFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRAirFFlow(I) = Curve::GetCurveIndex(state, heatEIRFFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, heatEIRFFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRAirFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRAirFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - fieldValue = - EnergyPlus::format("speed_{}{}", std::to_string(I), "_energy_input_ratio_function_of_water_flow_fraction_curve_name"); - cFieldName = - EnergyPlus::format("Speed_{}{}", std::to_string(I), " Energy Input Ratio Function of Water Flow Fraction Curve Name"); - std::string const heatEIRWFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (heatEIRWFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRWaterFFlow(I) = Curve::GetCurveIndex(state, heatEIRWFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, heatEIRWFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRWaterFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRWaterFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - // Read waste heat modifier curve name - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_waste_heat_function_of_temperature_curve_name"); - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Waste Heat Function of Temperature Curve Name"); - std::string const heatWHFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (heatWHFTCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSWasteHeat(I) = Curve::GetCurveIndex(state, heatWHFTCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, heatWHFTCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal types are BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSWasteHeat(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSWasteHeat(I), RatedInletWaterTemp, RatedInletAirTemp); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_heating_capacity_function_of_temperature_curve_name", + " Heating Capacity Function of Temperature Curve Name", + varSpeedCoil.MSCCapFTemp(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + RatedInletAirTempHeat, + RatedInletWaterTempHeat); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_total_heating_capacity_function_of_air_flow_fraction_curve_name", + " Total Heating Capacity Function of Air Flow Fraction Curve Name", + varSpeedCoil.MSCCapAirFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_heating_capacity_function_of_water_flow_fraction_curve_name", + " Heating Capacity Function of Water Flow Fraction Curve Name", + varSpeedCoil.MSCCapWaterFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_energy_input_ratio_function_of_temperature_curve_name", + " Energy Input Ratio Function of Temperature Curve Name", + varSpeedCoil.MSEIRFTemp(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + RatedInletAirTempHeat, + RatedInletWaterTempHeat, + true); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_energy_input_ratio_function_of_air_flow_fraction_curve_name", + " Energy Input Ratio Function of Air Flow Fraction Curve Name", + varSpeedCoil.MSEIRAirFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_energy_input_ratio_function_of_water_flow_fraction_curve_name", + " Energy Input Ratio Function of Water Flow Fraction Curve Name", + varSpeedCoil.MSEIRWaterFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_waste_heat_function_of_temperature_curve_name", + " Waste Heat Function of Temperature Curve Name", + varSpeedCoil.MSWasteHeat(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + RatedInletWaterTemp, + RatedInletAirTemp); } - for (int I = 1; I <= varSpeedCoil.NumOfSpeeds; ++I) { - varSpeedCoil.MSRatedPercentTotCap(I) = varSpeedCoil.MSRatedTotCap(I) / varSpeedCoil.MSRatedTotCap(varSpeedCoil.NumOfSpeeds); - varSpeedCoil.MSRatedAirVolFlowPerRatedTotCap(I) = varSpeedCoil.MSRatedAirVolFlowRate(I) / varSpeedCoil.MSRatedTotCap(I); - varSpeedCoil.MSRatedWaterVolFlowPerRatedTotCap(I) = varSpeedCoil.MSRatedWaterVolFlowRate(I) / varSpeedCoil.MSRatedTotCap(I); - } + computeScaleValues(varSpeedCoil, true, false, false); // CurrentModuleObject = "Coil:Heating:WaterToAirHeatPump:VariableSpeedEquationFit" - SetupOutputVariable(state, - "Heating Coil Electricity Energy", - Constant::Units::J, - varSpeedCoil.Energy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Heating Energy", - Constant::Units::J, - varSpeedCoil.EnergyLoadTotal, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::HeatingCoils); + setupEnergyOutputVars(varSpeedCoil, false); SetupOutputVariable(state, "Heating Coil Source Side Heat Transfer Energy", Constant::Units::J, @@ -1622,13 +1268,7 @@ namespace VariableSpeedCoils { varSpeedCoil.CoolHeatType = "HEATING"; varSpeedCoil.VSCoilType = HVAC::Coil_HeatingAirToAirVariableSpeed; varSpeedCoil.VarSpeedCoilType = HVAC::cAllCoilTypes(HVAC::Coil_HeatingAirToAirVariableSpeed); - std::string const availSchedName = s_ip->getAlphaFieldValue(fields, schemaProps, "availability_schedule_name"); - if (availSchedName.empty()) { - varSpeedCoil.availSched = Sched::GetScheduleAlwaysOn(state); - } else if ((varSpeedCoil.availSched = Sched::GetSchedule(state, availSchedName)) == nullptr) { - ShowSevereItemNotFound(state, eoh, "Availability Schedule Name", availSchedName); - ErrorsFound = true; - } + readAvailSchedule(varSpeedCoil, eoh, fields, schemaProps); varSpeedCoil.NumOfSpeeds = s_ip->getIntFieldValue(fields, schemaProps, "number_of_speeds"); varSpeedCoil.NormSpedLevel = s_ip->getIntFieldValue(fields, schemaProps, "nominal_speed_level"); @@ -1645,94 +1285,29 @@ namespace VariableSpeedCoils { varSpeedCoil.RatedAirVolFlowRate = s_ip->getRealFieldValue(fields, schemaProps, "rated_air_flow_rate_at_selected_nominal_speed_level"); } - std::string airInletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "indoor_air_inlet_node_name"); - std::string airOutletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "indoor_air_outlet_node_name"); - varSpeedCoil.AirInletNodeNum = GetOnlySingleNode(state, - airInletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilHeatingDXVariableSpeed, - varSpeedCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - varSpeedCoil.AirOutletNodeNum = GetOnlySingleNode(state, - airOutletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilHeatingDXVariableSpeed, - varSpeedCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - - Node::TestCompSet(state, CurrentModuleObject, varSpeedCoil.Name, airInletNodeName, airOutletNodeName, "Air Nodes"); - cFieldName = "Number of Speeds"; - if (varSpeedCoil.NumOfSpeeds < 1) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{} must be >= 1. entered number is {:.0T}", cFieldName, varSpeedCoil.NumOfSpeeds)); - ErrorsFound = true; - } - - if (varSpeedCoil.NormSpedLevel > varSpeedCoil.NumOfSpeeds) { - varSpeedCoil.NormSpedLevel = varSpeedCoil.NumOfSpeeds; - } - cFieldName = "Nominal Speed Level"; - if ((varSpeedCoil.NormSpedLevel > varSpeedCoil.NumOfSpeeds) || (varSpeedCoil.NormSpedLevel <= 0)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} must be valid speed level entered number is {:.0T}", cFieldName, varSpeedCoil.NormSpedLevel)); - ErrorsFound = true; - } + registerAirNodes(varSpeedCoil, + Node::ConnectionObjectType::CoilHeatingDXVariableSpeed, + fields, + schemaProps, + "indoor_air_inlet_node_name", + "indoor_air_outlet_node_name"); + validateNumSpeedsAndNormLevel(varSpeedCoil, CurrentModuleObject); // part load curve - cFieldName = "Energy Part Load Fraction Curve Name"; // cAlphaFields(4) - std::string const heatPLFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, "energy_part_load_fraction_curve_name"); - if (heatPLFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.PLFFPLR = Curve::GetCurveIndex(state, heatPLFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, heatPLFCurveName); - ErrorsFound = true; - } else { - CurveVal = Curve::CurveValue(state, varSpeedCoil.PLFFPLR, 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } + validatePLFCurve(varSpeedCoil, + eoh, + "Energy Part Load Fraction Curve Name", + "energy_part_load_fraction_curve_name", + fields, + schemaProps, + CurrentModuleObject); std::string const defrostEIRFTFieldName = "Defrost Energy Input Ratio Function of Temperature Curve Name"; // AlphArray(5) std::string defrostEIRFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, "defrost_energy_input_ratio_function_of_temperature_curve_name"); varSpeedCoil.DefrostEIRFT = Curve::GetCurveIndex(state, defrostEIRFTCurveName); // convert curve name to number - // A6; \field Crankcase Heater Capacity Function of Outdoor Temperature Curve Name - cFieldName = "Crankcase Heater Capacity Function of Temperature Curve Name"; // cAlphaFields(6) - std::string crankcaseHeaterCapCurveName = - s_ip->getAlphaFieldValue(fields, schemaProps, "crankcase_heater_capacity_function_of_temperature_curve_name"); - if (!crankcaseHeaterCapCurveName.empty()) { - varSpeedCoil.CrankcaseHeaterCapacityCurveIndex = Curve::GetCurveIndex(state, crankcaseHeaterCapCurveName); - if (varSpeedCoil.CrankcaseHeaterCapacityCurveIndex == 0) { // can't find the curve - ShowSevereError( - state, - EnergyPlus::format( - "{} = {}: {} not found = {}", CurrentModuleObject, varSpeedCoil.Name, cFieldName, crankcaseHeaterCapCurveName)); - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.CrankcaseHeaterCapacityCurveIndex, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - } - } + lookupCrankcaseHeaterCurve(varSpeedCoil, eoh, fields, schemaProps, CurrentModuleObject); cFieldName = "Defrost Strategy"; // cAlphaFields(7) std::string defrostStrategy = s_ip->getAlphaFieldValue(fields, schemaProps, "defrost_strategy"); @@ -1784,14 +1359,7 @@ namespace VariableSpeedCoils { varSpeedCoil.MaxOATDefrost = s_ip->getRealFieldValue(fields, schemaProps, "maximum_outdoor_dry_bulb_temperature_for_defrost_operation"); // Set crankcase heater capacity - cFieldName = "Crankcase Heater Capacity"; // cNumericFields(8) - varSpeedCoil.CrankcaseHeaterCapacity = s_ip->getRealFieldValue(fields, schemaProps, "crankcase_heater_capacity"); - if (varSpeedCoil.CrankcaseHeaterCapacity < 0.0) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, EnergyPlus::format("...{} cannot be < 0.0.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...entered value=[{:.2T}].", varSpeedCoil.CrankcaseHeaterCapacity)); - ErrorsFound = true; - } + readCrankcaseHeaterCapacity(varSpeedCoil, fields, schemaProps, CurrentModuleObject); // Set crankcase heater cutout temperature varSpeedCoil.MaxOATCrankcaseHeater = s_ip->getRealFieldValue(fields, schemaProps, "maximum_outdoor_dry_bulb_temperature_for_crankcase_heater_operation"); @@ -1838,167 +1406,78 @@ namespace VariableSpeedCoils { fieldName = EnergyPlus::format("2023_speed_{}{}", std::to_string(I), "_rated_supply_air_fan_power_per_volume_flow_rate"); varSpeedCoil.MSRatedEvaporatorFanPowerPerVolumeFlowRate2023(I) = s_ip->getRealFieldValue(fields, schemaProps, fieldName); - // Speed 1 Reference Unit Gross Rated Total Cooling Capacity - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_heating_capacity_function_of_temperature_curve_name"); - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Heating Capacity Function of Temperature Curve Name"); - std::string const hCapFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (hCapFTCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapFTemp(I) = Curve::GetCurveIndex(state, hCapFTCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, hCapFTCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapFTemp(I), RatedInletAirTempHeat, RatedAmbAirTempHeat); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - // Speed 1 Total Heating Capacity Function of Air Flow Fraction Curve Name - fieldValue = - EnergyPlus::format("speed_{}{}", std::to_string(I), "_total_heating_capacity_function_of_air_flow_fraction_curve_name"); - cFieldName = - EnergyPlus::format("Speed_{}{}", std::to_string(I), " Total Heating Capacity Function of Air Flow Fraction Curve Name"); - std::string const hCapFFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (hCapFFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapAirFFlow(I) = Curve::GetCurveIndex(state, hCapFFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, hCapFFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapAirFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapAirFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - // Speed 1 Energy Input Ratio Function of Temperature Curve Name - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_energy_input_ratio_function_of_temperature_curve_name"); - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Energy Input Ratio Function of Temperature Curve Name"); - std::string const hEIRFTCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (hEIRFTCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRFTemp(I) = Curve::GetCurveIndex(state, hEIRFTCurveName)) == 0) { - ShowSevereInvalidBool(state, eoh, cFieldName, hEIRFTCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRFTemp(I), RatedInletAirTempHeat, RatedAmbAirTempHeat); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - // Speed 1 Energy Input Ratio Function of Air Flow Fraction Curve Name - fieldValue = EnergyPlus::format("speed_{}{}", std::to_string(I), "_energy_input_ratio_function_of_air_flow_fraction_curve_name"); - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Energy Input Ratio Function of Air Flow Fraction Curve Name"); - std::string const hEIRFFFCurveName = s_ip->getAlphaFieldValue(fields, schemaProps, fieldValue); - if (hEIRFFFCurveName.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRAirFFlow(I) = Curve::GetCurveIndex(state, hEIRFFFCurveName)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, hEIRFFFCurveName); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRAirFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRAirFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_heating_capacity_function_of_temperature_curve_name", + " Heating Capacity Function of Temperature Curve Name", + varSpeedCoil.MSCCapFTemp(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + RatedInletAirTempHeat, + RatedAmbAirTempHeat); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_total_heating_capacity_function_of_air_flow_fraction_curve_name", + " Total Heating Capacity Function of Air Flow Fraction Curve Name", + varSpeedCoil.MSCCapAirFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_energy_input_ratio_function_of_temperature_curve_name", + " Energy Input Ratio Function of Temperature Curve Name", + varSpeedCoil.MSEIRFTemp(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + RatedInletAirTempHeat, + RatedAmbAirTempHeat, + true); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_energy_input_ratio_function_of_air_flow_fraction_curve_name", + " Energy Input Ratio Function of Air Flow Fraction Curve Name", + varSpeedCoil.MSEIRAirFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); } if (ErrorsFound) { continue; } - for (int I = 1; I <= varSpeedCoil.NumOfSpeeds; ++I) { - varSpeedCoil.MSRatedPercentTotCap(I) = varSpeedCoil.MSRatedTotCap(I) / varSpeedCoil.MSRatedTotCap(varSpeedCoil.NumOfSpeeds); - varSpeedCoil.MSRatedAirVolFlowPerRatedTotCap(I) = varSpeedCoil.MSRatedAirVolFlowRate(I) / varSpeedCoil.MSRatedTotCap(I); - } + computeScaleValues(varSpeedCoil, false, false, false); // CurrentModuleObject = "Coil:Heating:DX:Variablespeed " - SetupOutputVariable(state, - "Heating Coil Electricity Energy", - Constant::Units::J, - varSpeedCoil.Energy, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Heating Energy", - Constant::Units::J, - varSpeedCoil.EnergyLoadTotal, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name, - Constant::eResource::EnergyTransfer, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::HeatingCoils); + setupEnergyOutputVars(varSpeedCoil, false); SetupOutputVariable(state, "Heating Coil Source Side Heat Transfer Energy", Constant::Units::J, @@ -2042,33 +1521,10 @@ namespace VariableSpeedCoils { // ErrorsFound will be set to True if problem was found, left untouched otherwise GlobalNames::VerifyUniqueCoilName(state, CurrentModuleObject, varSpeedCoil.Name, ErrorsFound, CurrentModuleObject + " Name"); - std::string const availSchedName = s_ip->getAlphaFieldValue(fields, schemaProps, "availability_schedule_name"); - if (availSchedName.empty()) { - varSpeedCoil.availSched = Sched::GetScheduleAlwaysOn(state); - } else if ((varSpeedCoil.availSched = Sched::GetSchedule(state, availSchedName)) == nullptr) { - ShowSevereItemNotFound(state, eoh, "Availability Schedule Name", availSchedName); - ErrorsFound = true; - } + readAvailSchedule(varSpeedCoil, eoh, fields, schemaProps); varSpeedCoil.NumOfSpeeds = s_ip->getIntFieldValue(fields, schemaProps, "number_of_speeds"); varSpeedCoil.NormSpedLevel = s_ip->getIntFieldValue(fields, schemaProps, "nominal_speed_level"); - cFieldName = "Number of Speeds"; - if (varSpeedCoil.NumOfSpeeds < 1) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{} must be >= 1. entered number is {:.0T}", cFieldName, varSpeedCoil.NumOfSpeeds)); - ErrorsFound = true; - } - if (varSpeedCoil.NormSpedLevel > varSpeedCoil.NumOfSpeeds) { - varSpeedCoil.NormSpedLevel = varSpeedCoil.NumOfSpeeds; - } - cFieldName = "Nominal Speed Level"; - if ((varSpeedCoil.NormSpedLevel > varSpeedCoil.NumOfSpeeds) || (varSpeedCoil.NormSpedLevel <= 0)) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, - EnergyPlus::format("...{} must be valid speed level entered number is {:.0T}", cFieldName, varSpeedCoil.NormSpedLevel)); - ErrorsFound = true; - } + validateNumSpeedsAndNormLevel(varSpeedCoil, CurrentModuleObject); cFieldName = "Rated Water Heating Capacity"; varSpeedCoil.RatedCapWH = s_ip->getRealFieldValue(fields, schemaProps, "rated_water_heating_capacity"); // NumArray(3); if (varSpeedCoil.RatedCapWH <= 0.0) { @@ -2148,68 +1604,24 @@ namespace VariableSpeedCoils { varSpeedCoil.HPWHCondPumpFracToWater = 0.0; } - std::string evapAirInletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "evaporator_air_inlet_node_name"); - std::string evapAirOutletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "evaporator_air_outlet_node_name"); - - // Air nodes - varSpeedCoil.AirInletNodeNum = GetOnlySingleNode(state, - evapAirInletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilWaterHeatingAirToWaterHeatPumpVariableSpeed, - varSpeedCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - - varSpeedCoil.AirOutletNodeNum = GetOnlySingleNode(state, - evapAirOutletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilWaterHeatingAirToWaterHeatPumpVariableSpeed, - varSpeedCoil.Name, - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - - Node::TestCompSet(state, CurrentModuleObject, varSpeedCoil.Name, evapAirInletNodeName, evapAirOutletNodeName, "Air Nodes"); + registerAirNodes(varSpeedCoil, + Node::ConnectionObjectType::CoilWaterHeatingAirToWaterHeatPumpVariableSpeed, + fields, + schemaProps, + "evaporator_air_inlet_node_name", + "evaporator_air_outlet_node_name"); // Check if the air inlet node is OA node, to justify whether the coil is placed in zone or not varSpeedCoil.IsDXCoilInZone = !OutAirNodeManager::CheckOutAirNodeNumber(state, varSpeedCoil.AirInletNodeNum); - std::string condWaterInletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "condenser_water_inlet_node_name"); - std::string condWaterOutletNodeName = s_ip->getAlphaFieldValue(fields, schemaProps, "condenser_water_outlet_node_name"); - // Water nodes - varSpeedCoil.WaterInletNodeNum = GetOnlySingleNode(state, - condWaterInletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilWaterHeatingAirToWaterHeatPumpVariableSpeed, - varSpeedCoil.Name, - Node::FluidType::Water, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Secondary, - Node::ObjectIsNotParent); - - varSpeedCoil.WaterOutletNodeNum = GetOnlySingleNode(state, - condWaterOutletNodeName, - ErrorsFound, - Node::ConnectionObjectType::CoilWaterHeatingAirToWaterHeatPumpVariableSpeed, - varSpeedCoil.Name, - Node::FluidType::Water, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Secondary, - Node::ObjectIsNotParent); - - Node::TestCompSet(state, CurrentModuleObject, varSpeedCoil.Name, condWaterInletNodeName, condWaterOutletNodeName, "Water Nodes"); - - cFieldName = "Crankcase Heater Capacity"; - varSpeedCoil.CrankcaseHeaterCapacity = s_ip->getRealFieldValue(fields, schemaProps, "crankcase_heater_capacity"); // NumArray(10); - if (varSpeedCoil.CrankcaseHeaterCapacity < 0.0) { - ShowSevereError(state, EnergyPlus::format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} must be >= 0.0 entered value=[{:.1T}].", cFieldName, varSpeedCoil.CrankcaseHeaterCapacity)); - ErrorsFound = true; - } + registerWaterNodes(varSpeedCoil, + Node::ConnectionObjectType::CoilWaterHeatingAirToWaterHeatPumpVariableSpeed, + fields, + schemaProps, + "condenser_water_inlet_node_name", + "condenser_water_outlet_node_name"); + + readCrankcaseHeaterCapacity(varSpeedCoil, fields, schemaProps, CurrentModuleObject); cFieldName = "Maximum Ambient Temperature for Crankcase Heater Operation"; varSpeedCoil.MaxOATCrankcaseHeater = @@ -2222,23 +1634,7 @@ namespace VariableSpeedCoils { ErrorsFound = true; } - cFieldName = "Crankcase Heater Capacity Function of Temperature Curve Name"; - fieldValue = s_ip->getAlphaFieldValue(fields, schemaProps, "crankcase_heater_capacity_function_of_temperature_curve_name"); - if (!fieldValue.empty()) { - varSpeedCoil.CrankcaseHeaterCapacityCurveIndex = Curve::GetCurveIndex(state, fieldValue); - if (varSpeedCoil.CrankcaseHeaterCapacityCurveIndex == 0) { // can't find the curve - ShowSevereItemNotFound(state, eoh, cFieldName, fieldValue); - ErrorsFound = true; - } else { - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.CrankcaseHeaterCapacityCurveIndex, // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - } - } + lookupCrankcaseHeaterCurve(varSpeedCoil, eoh, fields, schemaProps, CurrentModuleObject); cFieldName = "Evaporator Air Temperature Type for Curve Objects"; fieldValue = s_ip->getAlphaFieldValue(fields, schemaProps, "evaporator_air_temperature_type_for_curve_objects"); @@ -2261,23 +1657,13 @@ namespace VariableSpeedCoils { WHInletWaterTemp = varSpeedCoil.WHRatedInletWaterTemp; // part load curve - cFieldName = "Part Load Fraction Correlation Curve Name"; - fieldValue = s_ip->getAlphaFieldValue(fields, schemaProps, "part_load_fraction_correlation_curve_name"); - if (fieldValue.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.PLFFPLR = Curve::GetCurveIndex(state, fieldValue)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, fieldValue); - ErrorsFound = true; - } else { - CurveVal = Curve::CurveValue(state, varSpeedCoil.PLFFPLR, 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError(state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } + validatePLFCurve(varSpeedCoil, + eoh, + "Part Load Fraction Correlation Curve Name", + "part_load_fraction_correlation_curve_name", + fields, + schemaProps, + CurrentModuleObject); for (int I = 1; I <= varSpeedCoil.NumOfSpeeds; ++I) { std::string jfieldName; @@ -2294,200 +1680,101 @@ namespace VariableSpeedCoils { jfieldName = EnergyPlus::format("speed_{}{}", std::to_string(I), "_reference_unit_water_pump_input_power_at_rated_conditions"); varSpeedCoil.MSWHPumpPower(I) = s_ip->getRealFieldValue(fields, schemaProps, jfieldName); - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Total WH Capacity Function of Temperature Curve Name"); - jfieldName = EnergyPlus::format("speed_{}{}", std::to_string(I), "_total_wh_capacity_function_of_temperature_curve_name"); - fieldValue = s_ip->getAlphaFieldValue(fields, schemaProps, jfieldName); - if (fieldValue.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapFTemp(I) = Curve::GetCurveIndex(state, fieldValue)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, fieldValue); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapFTemp(I), WHInletAirTemp, WHInletWaterTemp); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Total WH Capacity Function of Air Flow Fraction Curve Name"); - jfieldName = EnergyPlus::format("speed_{}{}", std::to_string(I), "_total_wh_capacity_function_of_air_flow_fraction_curve_name"); - fieldValue = s_ip->getAlphaFieldValue(fields, schemaProps, jfieldName); - if (fieldValue.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapAirFFlow(I) = Curve::GetCurveIndex(state, fieldValue)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, fieldValue); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapAirFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapAirFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " Total WH Capacity Function of Water Flow Fraction Curve Name"); - jfieldName = EnergyPlus::format("speed_{}{}", std::to_string(I), "_total_wh_capacity_function_of_water_flow_fraction_curve_name"); - fieldValue = s_ip->getAlphaFieldValue(fields, schemaProps, jfieldName); - if (fieldValue.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSCCapWaterFFlow(I) = Curve::GetCurveIndex(state, fieldValue)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, fieldValue); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSCCapWaterFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSCCapWaterFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " COP Function of Temperature Curve Name"); - jfieldName = EnergyPlus::format("speed_{}{}", std::to_string(I), "_cop_function_of_temperature_curve_name"); - fieldValue = s_ip->getAlphaFieldValue(fields, schemaProps, jfieldName); - if (fieldValue.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRFTemp(I) = Curve::GetCurveIndex(state, fieldValue)) == 0) { - ShowSevereInvalidBool(state, eoh, cFieldName, fieldValue); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is BiQuadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRFTemp(I), // Curve index - {2}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRFTemp(I), WHInletAirTemp, WHInletWaterTemp); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " COP Function of Air Flow Fraction Curve Name"); - jfieldName = EnergyPlus::format("speed_{}{}", std::to_string(I), "_cop_function_of_air_flow_fraction_curve_name"); - fieldValue = s_ip->getAlphaFieldValue(fields, schemaProps, jfieldName); - if (fieldValue.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRAirFFlow(I) = Curve::GetCurveIndex(state, fieldValue)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, fieldValue); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRAirFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRAirFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } - - cFieldName = EnergyPlus::format("Speed_{}{}", std::to_string(I), " COP Function of Water Flow Fraction Curve Name"); - jfieldName = EnergyPlus::format("speed_{}{}", std::to_string(I), "_cop_function_of_water_flow_fraction_curve_name"); - fieldValue = s_ip->getAlphaFieldValue(fields, schemaProps, jfieldName); - if (fieldValue.empty()) { - ShowWarningEmptyField(state, eoh, cFieldName, "Required field is blank."); - ErrorsFound = true; - } else if ((varSpeedCoil.MSEIRWaterFFlow(I) = Curve::GetCurveIndex(state, fieldValue)) == 0) { - ShowSevereItemNotFound(state, eoh, cFieldName, fieldValue); - ErrorsFound = true; - } else { - // Verify Curve Object, only legal type is Quadratic - ErrorsFound |= Curve::CheckCurveDims(state, - varSpeedCoil.MSEIRWaterFFlow(I), // Curve index - {1}, // Valid dimensions - RoutineName, // Routine name - CurrentModuleObject, // Object Type - varSpeedCoil.Name, // Object Name - cFieldName); // Field Name - - if (!ErrorsFound) { - CurveVal = Curve::CurveValue(state, varSpeedCoil.MSEIRWaterFFlow(I), 1.0); - if (CurveVal > 1.10 || CurveVal < 0.90) { - ShowWarningError( - state, EnergyPlus::format("{}{}=\"{}\", curve values", RoutineName, CurrentModuleObject, varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("...{} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName)); - ShowContinueError(state, EnergyPlus::format("...Curve output at rated conditions = {:.3T}", CurveVal)); - } - } - } + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_total_wh_capacity_function_of_temperature_curve_name", + " Total WH Capacity Function of Temperature Curve Name", + varSpeedCoil.MSCCapFTemp(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + WHInletAirTemp, + WHInletWaterTemp); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_total_wh_capacity_function_of_air_flow_fraction_curve_name", + " Total WH Capacity Function of Air Flow Fraction Curve Name", + varSpeedCoil.MSCCapAirFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_total_wh_capacity_function_of_water_flow_fraction_curve_name", + " Total WH Capacity Function of Water Flow Fraction Curve Name", + varSpeedCoil.MSCCapWaterFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_cop_function_of_temperature_curve_name", + " COP Function of Temperature Curve Name", + varSpeedCoil.MSEIRFTemp(I), + {2}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + WHInletAirTemp, + WHInletWaterTemp, + true); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_cop_function_of_air_flow_fraction_curve_name", + " COP Function of Air Flow Fraction Curve Name", + varSpeedCoil.MSEIRAirFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); + + ErrorsFound |= getAndCheckSpeedCurve(state, + eoh, + s_ip.get(), + fields, + schemaProps, + I, + "_cop_function_of_water_flow_fraction_curve_name", + " COP Function of Water Flow Fraction Curve Name", + varSpeedCoil.MSEIRWaterFFlow(I), + {1}, + RoutineName, + CurrentModuleObject, + varSpeedCoil.Name, + 1.0); } - // get scale values - for (int I = 1; I <= varSpeedCoil.NumOfSpeeds; ++I) { - varSpeedCoil.MSRatedPercentTotCap(I) = varSpeedCoil.MSRatedTotCap(I) / varSpeedCoil.MSRatedTotCap(varSpeedCoil.NumOfSpeeds); - varSpeedCoil.MSRatedAirVolFlowPerRatedTotCap(I) = varSpeedCoil.MSRatedAirVolFlowRate(I) / varSpeedCoil.MSRatedTotCap(I); - varSpeedCoil.MSRatedWaterVolFlowPerRatedTotCap(I) = varSpeedCoil.MSRatedWaterVolFlowRate(I) / varSpeedCoil.MSRatedTotCap(I); - varSpeedCoil.MSWHPumpPowerPerRatedTotCap(I) = varSpeedCoil.MSWHPumpPower(I) / varSpeedCoil.MSRatedTotCap(I); - } + computeScaleValues(varSpeedCoil, true, false, true); // CurrentModuleObject = "Coil:Waterheating:Airtowaterheatpump:Variablespeed" SetupOutputVariable(state, @@ -2554,6 +1841,455 @@ namespace VariableSpeedCoils { ShowFatalError(state, EnergyPlus::format("{}Errors found getting input. Program terminates.", RoutineName)); } + // Per-coil-type output variable registration lambdas. + // Each preserves the exact original registration order to maintain RDD compatibility. + + auto setupAirSourceCoolingVars = [&state](VariableSpeedCoilData &c) { + SetupOutputVariable(state, + "Cooling Coil Air Mass Flow Rate", + Constant::Units::kg_s, + c.AirMassFlowRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Air Inlet Temperature", + Constant::Units::C, + c.InletAirDBTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Air Inlet Humidity Ratio", + Constant::Units::kgWater_kgDryAir, + c.InletAirHumRat, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Latent Cooling Rate", + Constant::Units::W, + c.QLatent, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Air Outlet Temperature", + Constant::Units::C, + c.OutletAirDBTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Air Outlet Humidity Ratio", + Constant::Units::kgWater_kgDryAir, + c.OutletAirHumRat, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Sensible Cooling Rate", + Constant::Units::W, + c.QSensible, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Total Cooling Rate", + Constant::Units::W, + c.QLoadTotal, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Part Load Ratio", + Constant::Units::None, + c.PartLoadRatio, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Electricity Rate", + Constant::Units::W, + c.Power, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Runtime Fraction", + Constant::Units::None, + c.RunFrac, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Source Side Heat Transfer Rate", + Constant::Units::W, + c.QSource, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Upper Speed Level", + Constant::Units::None, + c.SpeedNumReport, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Neighboring Speed Levels Ratio", + Constant::Units::None, + c.SpeedRatioReport, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + }; + + auto setupAirSourceHeatingVars = [&state](VariableSpeedCoilData &c) { + SetupOutputVariable(state, + "Heating Coil Air Mass Flow Rate", + Constant::Units::kg_s, + c.AirMassFlowRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Air Inlet Temperature", + Constant::Units::C, + c.InletAirDBTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Air Inlet Humidity Ratio", + Constant::Units::kgWater_kgDryAir, + c.InletAirHumRat, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Air Outlet Temperature", + Constant::Units::C, + c.OutletAirDBTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Air Outlet Humidity Ratio", + Constant::Units::kgWater_kgDryAir, + c.OutletAirHumRat, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Sensible Heating Rate", + Constant::Units::W, + c.QSensible, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Heating Rate", + Constant::Units::W, + c.QLoadTotal, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Part Load Ratio", + Constant::Units::None, + c.PartLoadRatio, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Electricity Rate", + Constant::Units::W, + c.Power, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Runtime Fraction", + Constant::Units::None, + c.RunFrac, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Source Side Heat Transfer Rate", + Constant::Units::W, + c.QSource, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Upper Speed Level", + Constant::Units::None, + c.SpeedNumReport, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Neighboring Speed Levels Ratio", + Constant::Units::None, + c.SpeedRatioReport, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + }; + + auto setupWaterSourceCoolingVars = [&state](VariableSpeedCoilData &c) { + SetupOutputVariable(state, + "Cooling Coil Electricity Rate", + Constant::Units::W, + c.Power, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Total Cooling Rate", + Constant::Units::W, + c.QLoadTotal, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Sensible Cooling Rate", + Constant::Units::W, + c.QSensible, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Latent Cooling Rate", + Constant::Units::W, + c.QLatent, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Source Side Heat Transfer Rate", + Constant::Units::W, + c.QSource, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Part Load Ratio", + Constant::Units::None, + c.PartLoadRatio, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Runtime Fraction", + Constant::Units::None, + c.RunFrac, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Air Mass Flow Rate", + Constant::Units::kg_s, + c.AirMassFlowRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Air Inlet Temperature", + Constant::Units::C, + c.InletAirDBTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Air Inlet Humidity Ratio", + Constant::Units::kgWater_kgDryAir, + c.InletAirHumRat, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Air Outlet Temperature", + Constant::Units::C, + c.OutletAirDBTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Air Outlet Humidity Ratio", + Constant::Units::kgWater_kgDryAir, + c.OutletAirHumRat, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Source Side Mass Flow Rate", + Constant::Units::kg_s, + c.WaterMassFlowRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Source Side Inlet Temperature", + Constant::Units::C, + c.InletWaterTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Source Side Outlet Temperature", + Constant::Units::C, + c.OutletWaterTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Upper Speed Level", + Constant::Units::None, + c.SpeedNumReport, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Neighboring Speed Levels Ratio", + Constant::Units::None, + c.SpeedRatioReport, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Cooling Coil Recoverable Heat Transfer Rate", + Constant::Units::W, + c.QWasteHeat, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + }; + + auto setupWaterSourceHeatingVars = [&state](VariableSpeedCoilData &c) { + SetupOutputVariable(state, + "Heating Coil Electricity Rate", + Constant::Units::W, + c.Power, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Heating Rate", + Constant::Units::W, + c.QLoadTotal, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Sensible Heating Rate", + Constant::Units::W, + c.QSensible, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Source Side Heat Transfer Rate", + Constant::Units::W, + c.QSource, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Part Load Ratio", + Constant::Units::None, + c.PartLoadRatio, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Runtime Fraction", + Constant::Units::None, + c.RunFrac, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Air Mass Flow Rate", + Constant::Units::kg_s, + c.AirMassFlowRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Air Inlet Temperature", + Constant::Units::C, + c.InletAirDBTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Air Inlet Humidity Ratio", + Constant::Units::kgWater_kgDryAir, + c.InletAirHumRat, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Air Outlet Temperature", + Constant::Units::C, + c.OutletAirDBTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Air Outlet Humidity Ratio", + Constant::Units::kgWater_kgDryAir, + c.OutletAirHumRat, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Source Side Mass Flow Rate", + Constant::Units::kg_s, + c.WaterMassFlowRate, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Source Side Inlet Temperature", + Constant::Units::C, + c.InletWaterTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Source Side Outlet Temperature", + Constant::Units::C, + c.OutletWaterTemp, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Upper Speed Level", + Constant::Units::None, + c.SpeedNumReport, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Neighboring Speed Levels Ratio", + Constant::Units::None, + c.SpeedRatioReport, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + SetupOutputVariable(state, + "Heating Coil Recoverable Heat Transfer Rate", + Constant::Units::W, + c.QWasteHeat, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + c.Name); + }; + for (DXCoilNum = 1; DXCoilNum <= state.dataVariableSpeedCoils->NumVarSpeedCoils; ++DXCoilNum) { auto &varSpeedCoil = state.dataVariableSpeedCoils->VarSpeedCoil(DXCoilNum); if ((varSpeedCoil.VSCoilType == HVAC::Coil_CoolingAirToAirVariableSpeed) || @@ -2563,104 +2299,7 @@ namespace VariableSpeedCoils { // cooling and heating coils separately if (varSpeedCoil.VSCoilType == HVAC::Coil_CoolingAirToAirVariableSpeed) { // air source cooling coils - SetupOutputVariable(state, - "Cooling Coil Air Mass Flow Rate", - Constant::Units::kg_s, - varSpeedCoil.AirMassFlowRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Air Inlet Temperature", - Constant::Units::C, - varSpeedCoil.InletAirDBTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Air Inlet Humidity Ratio", - Constant::Units::kgWater_kgDryAir, - varSpeedCoil.InletAirHumRat, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Rate", - Constant::Units::W, - varSpeedCoil.QLatent, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Air Outlet Temperature", - Constant::Units::C, - varSpeedCoil.OutletAirDBTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Air Outlet Humidity Ratio", - Constant::Units::kgWater_kgDryAir, - varSpeedCoil.OutletAirHumRat, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Rate", - Constant::Units::W, - varSpeedCoil.QSensible, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Total Cooling Rate", - Constant::Units::W, - varSpeedCoil.QLoadTotal, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Part Load Ratio", - Constant::Units::None, - varSpeedCoil.PartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Electricity Rate", - Constant::Units::W, - varSpeedCoil.Power, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Runtime Fraction", - Constant::Units::None, - varSpeedCoil.RunFrac, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Source Side Heat Transfer Rate", - Constant::Units::W, - varSpeedCoil.QSource, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Upper Speed Level", - Constant::Units::None, - varSpeedCoil.SpeedNumReport, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Neighboring Speed Levels Ratio", - Constant::Units::None, - varSpeedCoil.SpeedRatioReport, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); + setupAirSourceCoolingVars(varSpeedCoil); if (varSpeedCoil.CondensateCollectMode == CondensateToTank) { SetupOutputVariable(state, @@ -2727,432 +2366,91 @@ namespace VariableSpeedCoils { Constant::eResource::Electricity, OutputProcessor::Group::HVAC, OutputProcessor::EndUseCat::Cooling); - if (varSpeedCoil.BasinHeaterPowerFTempDiff > 0.0) { - SetupOutputVariable(state, - "Cooling Coil Basin Heater Electricity Rate", - Constant::Units::W, - varSpeedCoil.BasinHeaterPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Basin Heater Electricity Energy", - Constant::Units::J, - varSpeedCoil.BasinHeaterConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Cooling); - } - } - } else { - // air source heating coils - SetupOutputVariable(state, - "Heating Coil Air Mass Flow Rate", - Constant::Units::kg_s, - varSpeedCoil.AirMassFlowRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Air Inlet Temperature", - Constant::Units::C, - varSpeedCoil.InletAirDBTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Air Inlet Humidity Ratio", - Constant::Units::kgWater_kgDryAir, - varSpeedCoil.InletAirHumRat, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Air Outlet Temperature", - Constant::Units::C, - varSpeedCoil.OutletAirDBTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Air Outlet Humidity Ratio", - Constant::Units::kgWater_kgDryAir, - varSpeedCoil.OutletAirHumRat, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Sensible Heating Rate", - Constant::Units::W, - varSpeedCoil.QSensible, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Heating Rate", - Constant::Units::W, - varSpeedCoil.QLoadTotal, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Part Load Ratio", - Constant::Units::None, - varSpeedCoil.PartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Electricity Rate", - Constant::Units::W, - varSpeedCoil.Power, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Runtime Fraction", - Constant::Units::None, - varSpeedCoil.RunFrac, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - - SetupOutputVariable(state, - "Heating Coil Source Side Heat Transfer Rate", - Constant::Units::W, - varSpeedCoil.QSource, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Upper Speed Level", - Constant::Units::None, - varSpeedCoil.SpeedNumReport, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Neighboring Speed Levels Ratio", - Constant::Units::None, - varSpeedCoil.SpeedRatioReport, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - - SetupOutputVariable(state, - "Heating Coil Defrost Electricity Rate", - Constant::Units::W, - varSpeedCoil.DefrostPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Defrost Electricity Energy", - Constant::Units::J, - varSpeedCoil.DefrostConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Crankcase Heater Electricity Rate", - Constant::Units::W, - varSpeedCoil.CrankcaseHeaterPower, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Crankcase Heater Electricity Energy", - Constant::Units::J, - varSpeedCoil.CrankcaseHeaterConsumption, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Sum, - varSpeedCoil.Name, - Constant::eResource::Electricity, - OutputProcessor::Group::HVAC, - OutputProcessor::EndUseCat::Heating); - - if (state.dataGlobal->AnyEnergyManagementSystemInModel) { - SetupEMSActuator(state, - varSpeedCoil.VarSpeedCoilType, - varSpeedCoil.Name, - "Frost Heating Capacity Multiplier", - "[]", - varSpeedCoil.FrostHeatingCapacityMultiplierEMSOverrideOn, - varSpeedCoil.FrostHeatingCapacityMultiplierEMSOverrideValue); - - SetupEMSActuator(state, - varSpeedCoil.VarSpeedCoilType, - varSpeedCoil.Name, - "Frost Heating Input Power Multiplier", - "[]", - varSpeedCoil.FrostHeatingInputPowerMultiplierEMSOverrideOn, - varSpeedCoil.FrostHeatingInputPowerMultiplierEMSOverrideValue); - } - } - } else { - - if (varSpeedCoil.VSCoilType == HVAC::Coil_CoolingWaterToAirHPVSEquationFit) { // fix coil type - // cooling WAHP coil - // Setup Report variables for water source Heat Pump - SetupOutputVariable(state, - "Cooling Coil Electricity Rate", - Constant::Units::W, - varSpeedCoil.Power, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Total Cooling Rate", - Constant::Units::W, - varSpeedCoil.QLoadTotal, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Sensible Cooling Rate", - Constant::Units::W, - varSpeedCoil.QSensible, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Latent Cooling Rate", - Constant::Units::W, - varSpeedCoil.QLatent, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Source Side Heat Transfer Rate", - Constant::Units::W, - varSpeedCoil.QSource, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Part Load Ratio", - Constant::Units::None, - varSpeedCoil.PartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Runtime Fraction", - Constant::Units::None, - varSpeedCoil.RunFrac, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - - SetupOutputVariable(state, - "Cooling Coil Air Mass Flow Rate", - Constant::Units::kg_s, - varSpeedCoil.AirMassFlowRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Air Inlet Temperature", - Constant::Units::C, - varSpeedCoil.InletAirDBTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Air Inlet Humidity Ratio", - Constant::Units::kgWater_kgDryAir, - varSpeedCoil.InletAirHumRat, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Air Outlet Temperature", - Constant::Units::C, - varSpeedCoil.OutletAirDBTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Air Outlet Humidity Ratio", - Constant::Units::kgWater_kgDryAir, - varSpeedCoil.OutletAirHumRat, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Source Side Mass Flow Rate", - Constant::Units::kg_s, - varSpeedCoil.WaterMassFlowRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Source Side Inlet Temperature", - Constant::Units::C, - varSpeedCoil.InletWaterTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Source Side Outlet Temperature", - Constant::Units::C, - varSpeedCoil.OutletWaterTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); + if (varSpeedCoil.BasinHeaterPowerFTempDiff > 0.0) { + SetupOutputVariable(state, + "Cooling Coil Basin Heater Electricity Rate", + Constant::Units::W, + varSpeedCoil.BasinHeaterPower, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Average, + varSpeedCoil.Name); + SetupOutputVariable(state, + "Cooling Coil Basin Heater Electricity Energy", + Constant::Units::J, + varSpeedCoil.BasinHeaterConsumption, + OutputProcessor::TimeStepType::System, + OutputProcessor::StoreType::Sum, + varSpeedCoil.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Cooling); + } + } + } else { + // air source heating coils + setupAirSourceHeatingVars(varSpeedCoil); SetupOutputVariable(state, - "Cooling Coil Upper Speed Level", - Constant::Units::None, - varSpeedCoil.SpeedNumReport, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Neighboring Speed Levels Ratio", - Constant::Units::None, - varSpeedCoil.SpeedRatioReport, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Cooling Coil Recoverable Heat Transfer Rate", + "Heating Coil Defrost Electricity Rate", Constant::Units::W, - varSpeedCoil.QWasteHeat, + varSpeedCoil.DefrostPower, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, varSpeedCoil.Name); - } else if (varSpeedCoil.VSCoilType == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) { // fix coil type - // heating WAHP coil - // Setup Report variables for water source Heat Pump SetupOutputVariable(state, - "Heating Coil Electricity Rate", - Constant::Units::W, - varSpeedCoil.Power, + "Heating Coil Defrost Electricity Energy", + Constant::Units::J, + varSpeedCoil.DefrostConsumption, OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); + OutputProcessor::StoreType::Sum, + varSpeedCoil.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Heating); SetupOutputVariable(state, - "Heating Coil Heating Rate", + "Heating Coil Crankcase Heater Electricity Rate", Constant::Units::W, - varSpeedCoil.QLoadTotal, + varSpeedCoil.CrankcaseHeaterPower, OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, varSpeedCoil.Name); SetupOutputVariable(state, - "Heating Coil Sensible Heating Rate", - Constant::Units::W, - varSpeedCoil.QSensible, + "Heating Coil Crankcase Heater Electricity Energy", + Constant::Units::J, + varSpeedCoil.CrankcaseHeaterConsumption, OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); + OutputProcessor::StoreType::Sum, + varSpeedCoil.Name, + Constant::eResource::Electricity, + OutputProcessor::Group::HVAC, + OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, - "Heating Coil Source Side Heat Transfer Rate", - Constant::Units::W, - varSpeedCoil.QSource, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Part Load Ratio", - Constant::Units::None, - varSpeedCoil.PartLoadRatio, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Runtime Fraction", - Constant::Units::None, - varSpeedCoil.RunFrac, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); + if (state.dataGlobal->AnyEnergyManagementSystemInModel) { + SetupEMSActuator(state, + varSpeedCoil.VarSpeedCoilType, + varSpeedCoil.Name, + "Frost Heating Capacity Multiplier", + "[]", + varSpeedCoil.FrostHeatingCapacityMultiplierEMSOverrideOn, + varSpeedCoil.FrostHeatingCapacityMultiplierEMSOverrideValue); - SetupOutputVariable(state, - "Heating Coil Air Mass Flow Rate", - Constant::Units::kg_s, - varSpeedCoil.AirMassFlowRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Air Inlet Temperature", - Constant::Units::C, - varSpeedCoil.InletAirDBTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Air Inlet Humidity Ratio", - Constant::Units::kgWater_kgDryAir, - varSpeedCoil.InletAirHumRat, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Air Outlet Temperature", - Constant::Units::C, - varSpeedCoil.OutletAirDBTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Air Outlet Humidity Ratio", - Constant::Units::kgWater_kgDryAir, - varSpeedCoil.OutletAirHumRat, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Source Side Mass Flow Rate", - Constant::Units::kg_s, - varSpeedCoil.WaterMassFlowRate, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Source Side Inlet Temperature", - Constant::Units::C, - varSpeedCoil.InletWaterTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Source Side Outlet Temperature", - Constant::Units::C, - varSpeedCoil.OutletWaterTemp, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); + SetupEMSActuator(state, + varSpeedCoil.VarSpeedCoilType, + varSpeedCoil.Name, + "Frost Heating Input Power Multiplier", + "[]", + varSpeedCoil.FrostHeatingInputPowerMultiplierEMSOverrideOn, + varSpeedCoil.FrostHeatingInputPowerMultiplierEMSOverrideValue); + } + } + } else { - SetupOutputVariable(state, - "Heating Coil Upper Speed Level", - Constant::Units::None, - varSpeedCoil.SpeedNumReport, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Neighboring Speed Levels Ratio", - Constant::Units::None, - varSpeedCoil.SpeedRatioReport, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); - SetupOutputVariable(state, - "Heating Coil Recoverable Heat Transfer Rate", - Constant::Units::W, - varSpeedCoil.QWasteHeat, - OutputProcessor::TimeStepType::System, - OutputProcessor::StoreType::Average, - varSpeedCoil.Name); + if (varSpeedCoil.VSCoilType == HVAC::Coil_CoolingWaterToAirHPVSEquationFit) { // fix coil type + // cooling WAHP coil + setupWaterSourceCoolingVars(varSpeedCoil); + } else if (varSpeedCoil.VSCoilType == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) { // fix coil type + // heating WAHP coil + setupWaterSourceHeatingVars(varSpeedCoil); } else if (varSpeedCoil.VSCoilType == HVAC::CoilDX_HeatPumpWaterHeaterVariableSpeed) { // air source water heating coil SetupOutputVariable(state, @@ -3204,7 +2502,6 @@ namespace VariableSpeedCoils { OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, varSpeedCoil.Name); - SetupOutputVariable(state, "Cooling Coil Air Mass Flow Rate", Constant::Units::kg_s, @@ -3261,7 +2558,6 @@ namespace VariableSpeedCoils { OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, varSpeedCoil.Name); - SetupOutputVariable(state, "Cooling Coil Crankcase Heater Electricity Rate", Constant::Units::W, @@ -3279,7 +2575,6 @@ namespace VariableSpeedCoils { Constant::eResource::Electricity, OutputProcessor::Group::HVAC, OutputProcessor::EndUseCat::Heating); - SetupOutputVariable(state, "Cooling Coil Upper Speed Level", Constant::Units::None, @@ -3294,7 +2589,6 @@ namespace VariableSpeedCoils { OutputProcessor::TimeStepType::System, OutputProcessor::StoreType::Average, varSpeedCoil.Name); - SetupOutputVariable(state, "Cooling Coil Water Heating Pump Electricity Rate", Constant::Units::W, @@ -3879,6 +3173,113 @@ namespace VariableSpeedCoils { state.dataHeatBal->HeatReclaimVS_Coil(DXCoilNum).AvailCapacity = 0.0; } + // Helper: warn when user-specified sizing value differs significantly from design size + static void reportSizingMismatchWarning(EnergyPlusData &state, + std::string_view coolHeatType, + std::string_view objSubfix, + std::string_view coilName, + std::string_view userDesc, + Real64 userValue, + std::string_view desDesc, + Real64 desValue) + { + if (!state.dataGlobal->DisplayExtraWarnings) { + return; + } + if (userValue == 0.0) { + return; + } + if ((std::abs(desValue - userValue) / userValue) <= state.dataSize->AutoVsHardSizingThreshold) { + return; + } + + ShowMessage(state, EnergyPlus::format("SizeVarSpeedCoil: Potential issue with equipment sizing for {} {}", coolHeatType, objSubfix)); + ShowContinueError(state, EnergyPlus::format("Coil Name = {}", coilName)); + ShowContinueError(state, EnergyPlus::format("User-Specified {} of {:.5R}", userDesc, userValue)); + ShowContinueError(state, EnergyPlus::format("differs from Design Size {} of {:.5R}", desDesc, desValue)); + ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); + ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); + } + + // Calculate HPWH cooling capacity from rated capacity and COP, accounting for pump power. + static Real64 calcHPWHCoolCapacity(Real64 ratedTotCap, Real64 ratedCOP, Real64 pumpPower, Real64 pumpFracToWater, bool pumpPowerInCOP) + { + if (pumpPowerInCOP) { + return ratedTotCap * (1.0 - 1.0 / ratedCOP) + pumpPower - pumpPower * pumpFracToWater; + } else { + return ratedTotCap * (1.0 - 1.0 / ratedCOP) - pumpPower * pumpFracToWater; + } + } + + // Warn when rated sensible cooling capacity exceeds rated total cooling capacity. + static void warnSensibleExceedsTotal(EnergyPlusData &state, + std::string_view coolHeatType, + std::string_view coilName, + std::string_view autosizeContext, + std::string_view statsHeader, + Real64 sensCap, + Real64 totalCap, + Real64 mixWetBulb, + Real64 mixTemp, // -999 means omit dry-bulb stats + Real64 totCapTempModFac) // -999 means omit modifier stats + { + static constexpr std::string_view RoutineNameLocal("SizeVarSpeedCoil"); + ShowWarningError(state, EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT \"{}\"", coolHeatType, coilName)); + ShowContinueError(state, EnergyPlus::format("{}: Rated Sensible Cooling Capacity > Rated Total Cooling Capacity", RoutineNameLocal)); + ShowContinueError(state, std::string{autosizeContext}); + ShowContinueError(state, EnergyPlus::format("Rated Sensible Cooling Capacity = {:.2T} W", sensCap)); + ShowContinueError(state, EnergyPlus::format("Rated Total Cooling Capacity = {:.2T} W", totalCap)); + ShowContinueError(state, "See eio file for further details."); + ShowContinueError(state, "Check Total and Sensible Cooling Capacity Coefficients to ensure they are accurate."); + ShowContinueError(state, "Check Zone and System Sizing objects to verify sizing inputs."); + ShowContinueError(state, std::string{statsHeader}); + if (mixTemp > -998.0) { + ShowContinueError(state, EnergyPlus::format("Entering Air Dry-Bulb Temperature = {:.3T} C", mixTemp)); + } + ShowContinueError(state, EnergyPlus::format("Entering Air Wet-Bulb Temperature = {:.3T} C", mixWetBulb)); + ShowContinueError(state, "Entering Condenser Water Temperature used = 24.4444 C"); + ShowContinueError(state, "Used design air and water flow rates (i.e., used 1 for ratioVL and ratioVS)"); + if (mixTemp > -998.0) { + ShowContinueError(state, EnergyPlus::format("ratioTDB = {:.3T}", ((mixTemp + 283.15) / 273.15))); + } + ShowContinueError(state, EnergyPlus::format("ratioTWB = {:.3T}", ((mixWetBulb + 283.15) / 273.15))); + ShowContinueError(state, EnergyPlus::format("ratioTS = {:.3T}", ((85.0 + 283.15) / 273.15))); + ShowContinueError(state, "Rated Sensible Cooling Capacity = Rated Total Cooling Capacity * Sensible Heat Ratio"); + if (totCapTempModFac > -998.0) { + ShowContinueError(state, EnergyPlus::format("Total Cooling Capacity Modifier = {:.5T}", totCapTempModFac)); + ShowContinueError(state, "...Rated Total Cooling Capacity = Total Design Load / Total Cooling Capacity Modifier"); + } + ShowContinueError(state, "Carefully review the Load Side Total, Sensible, and Latent heat transfer rates"); + ShowContinueError(state, "... to ensure they meet the expected manufacturers performance specifications."); + } + + // Validate that speed-level rated values are monotonically non-decreasing. + // If any adjacent pair violates this, issue a warning and fatal error. + static void checkSpeedLevelMonotonicity(EnergyPlusData &state, + std::string_view coilType, + std::string_view coilName, + int numSpeeds, + Array1D const &ratedValues, + Array1D const &reportValues, + std::string_view quantityDesc, + Real64 toleranceFactor = 1.0) + { + for (int Mode = 1; Mode <= numSpeeds - 1; ++Mode) { + if (ratedValues(Mode) > ratedValues(Mode + 1) * toleranceFactor) { + ShowWarningError(state, + EnergyPlus::format("SizeDXCoil: {} {}, Speed {} {} must be less than or equal to Speed {} {}.", + coilType, + coilName, + Mode, + quantityDesc, + Mode + 1, + quantityDesc)); + ShowContinueError(state, EnergyPlus::format("Instead, {:.2R} > {:.2R}", reportValues(Mode), reportValues(Mode + 1))); + ShowFatalError(state, "Preceding conditions cause termination."); + } + } + } + void SizeVarSpeedCoil(EnergyPlusData &state, int const DXCoilNum, bool &ErrorsFound) { @@ -4319,23 +3720,14 @@ namespace VariableSpeedCoils { RatedCapCoolTotalDes, "User-Specified Rated Total Cooling Capacity [W]", RatedCapCoolTotalUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(RatedCapCoolTotalDes - RatedCapCoolTotalUser) / RatedCapCoolTotalUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVarSpeedCoil: Potential issue with equipment sizing for {} {}", - varSpeedCoil.CoolHeatType, - CurrentObjSubfix)); - ShowContinueError(state, EnergyPlus::format("Coil Name = {}", varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Rated Total Cooling Capacity of {:.2R} [W]", RatedCapCoolTotalUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Rated Total Cooling Capacity of {:.2R} [W]", RatedCapCoolTotalDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + reportSizingMismatchWarning(state, + varSpeedCoil.CoolHeatType, + CurrentObjSubfix, + varSpeedCoil.Name, + "Rated Total Cooling Capacity [W]", + RatedCapCoolTotalUser, + "Rated Total Cooling Capacity [W]", + RatedCapCoolTotalDes); } } @@ -4452,20 +3844,14 @@ namespace VariableSpeedCoils { RatedCapHeatDes, "User-Specified Nominal Heating Capacity [W]", RatedCapHeatUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(RatedCapHeatDes - RatedCapHeatUser) / RatedCapHeatUser) > state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVarSpeedCoil: Potential issue with equipment sizing for {} {}", - varSpeedCoil.CoolHeatType, - CurrentObjSubfix)); - ShowContinueError(state, EnergyPlus::format("Coil Name = {}", varSpeedCoil.Name)); - ShowContinueError(state, EnergyPlus::format("User-Specified Rated Total Heating Capacity of {:.2R} [W]", RatedCapHeatUser)); - ShowContinueError(state, - EnergyPlus::format("differs from Design Size Rated Total Heating Capacity of {:.2R} [W]", RatedCapHeatDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + reportSizingMismatchWarning(state, + varSpeedCoil.CoolHeatType, + CurrentObjSubfix, + varSpeedCoil.Name, + "Rated Total Heating Capacity [W]", + RatedCapHeatUser, + "Rated Total Heating Capacity [W]", + RatedCapHeatDes); } } @@ -4495,22 +3881,14 @@ namespace VariableSpeedCoils { RatedAirVolFlowRateDes, "User-Specified Rated Air Flow Rate [m3/s]", RatedAirVolFlowRateUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(RatedAirVolFlowRateDes - RatedAirVolFlowRateUser) / RatedAirVolFlowRateUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVarSpeedCoil: Potential issue with equipment sizing for {} {}", - varSpeedCoil.CoolHeatType, - CurrentObjSubfix)); - ShowContinueError(state, EnergyPlus::format("Coil Name = {}", varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Rated Air Flow Rate of {:.5R} [m3/s]", RatedAirVolFlowRateUser)); - ShowContinueError( - state, EnergyPlus::format("differs from Design Size Rated Air Flow Rate of {:.5R} [m3/s]", RatedAirVolFlowRateDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + reportSizingMismatchWarning(state, + varSpeedCoil.CoolHeatType, + CurrentObjSubfix, + varSpeedCoil.Name, + "Rated Air Flow Rate [m3/s]", + RatedAirVolFlowRateUser, + "Rated Air Flow Rate [m3/s]", + RatedAirVolFlowRateDes); } } state.dataRptCoilSelection->coilSelectionReportObj->setCoilAirFlow( @@ -4577,49 +3955,28 @@ namespace VariableSpeedCoils { // HPWH, the mass flow rate will be updated by a revised entering air density if (varSpeedCoil.MSHPDesignSpecIndex > -1 && !state.dataUnitarySystems->designSpecMSHP.empty()) { - if (varSpeedCoil.VSCoilType == HVAC::Coil_CoolingWaterToAirHPVSEquationFit || - varSpeedCoil.VSCoilType == HVAC::Coil_CoolingAirToAirVariableSpeed) { - if (state.dataUnitarySystems->designSpecMSHP[varSpeedCoil.MSHPDesignSpecIndex].numOfSpeedCooling != varSpeedCoil.NumOfSpeeds) { - ShowFatalError(state, - EnergyPlus::format("COIL:{} = {}{} number of speeds not equal to number of speed specified in " - "UnitarySystemPerformance:Multispeed object.", - varSpeedCoil.CoolHeatType, - CurrentObjSubfix, - varSpeedCoil.Name)); - } else { - for (Mode = varSpeedCoil.NumOfSpeeds; Mode >= 1; --Mode) { - varSpeedCoil.MSRatedAirVolFlowRate(Mode) = - varSpeedCoil.RatedAirVolFlowRate * - state.dataUnitarySystems->designSpecMSHP[varSpeedCoil.MSHPDesignSpecIndex].coolingVolFlowRatio[Mode - 1]; - varSpeedCoil.MSRatedTotCap(Mode) = - varSpeedCoil.MSRatedAirVolFlowRate(Mode) / varSpeedCoil.MSRatedAirVolFlowPerRatedTotCap(Mode); - varSpeedCoil.MSRatedAirMassFlowRate(Mode) = varSpeedCoil.MSRatedAirVolFlowRate(Mode) * rhoair; - // EVAPORATIVE PRECOOLING CONDENSER AIR FLOW RATE - varSpeedCoil.EvapCondAirFlow(Mode) = - varSpeedCoil.MSRatedTotCap(Mode) * varSpeedCoil.MSRatedEvapCondVolFlowPerRatedTotCap(Mode); - } - } - } else if (varSpeedCoil.VSCoilType == HVAC::Coil_HeatingWaterToAirHPVSEquationFit || - varSpeedCoil.VSCoilType == HVAC::Coil_HeatingAirToAirVariableSpeed) { - if (state.dataUnitarySystems->designSpecMSHP[varSpeedCoil.MSHPDesignSpecIndex].numOfSpeedHeating != varSpeedCoil.NumOfSpeeds) { - ShowFatalError(state, - EnergyPlus::format("COIL:{}{} = \"{}\" number of speeds not equal to number of speed specified in " - "UnitarySystemPerformance:Multispeed object.", - varSpeedCoil.CoolHeatType, - CurrentObjSubfix, - varSpeedCoil.Name)); - } else { - for (Mode = varSpeedCoil.NumOfSpeeds; Mode >= 1; --Mode) { - varSpeedCoil.MSRatedAirVolFlowRate(Mode) = - varSpeedCoil.RatedAirVolFlowRate * - state.dataUnitarySystems->designSpecMSHP[varSpeedCoil.MSHPDesignSpecIndex].heatingVolFlowRatio[Mode - 1]; - varSpeedCoil.MSRatedTotCap(Mode) = - varSpeedCoil.MSRatedAirVolFlowRate(Mode) / varSpeedCoil.MSRatedAirVolFlowPerRatedTotCap(Mode); - varSpeedCoil.MSRatedAirMassFlowRate(Mode) = varSpeedCoil.MSRatedAirVolFlowRate(Mode) * rhoair; - // EVAPORATIVE PRECOOLING CONDENSER AIR FLOW RATE - varSpeedCoil.EvapCondAirFlow(Mode) = - varSpeedCoil.MSRatedTotCap(Mode) * varSpeedCoil.MSRatedEvapCondVolFlowPerRatedTotCap(Mode); - } + auto const &designSpec = state.dataUnitarySystems->designSpecMSHP[varSpeedCoil.MSHPDesignSpecIndex]; + bool const isCooling = (varSpeedCoil.VSCoilType == HVAC::Coil_CoolingWaterToAirHPVSEquationFit || + varSpeedCoil.VSCoilType == HVAC::Coil_CoolingAirToAirVariableSpeed); + int const specNumSpeeds = isCooling ? designSpec.numOfSpeedCooling : designSpec.numOfSpeedHeating; + auto const &volFlowRatios = isCooling ? designSpec.coolingVolFlowRatio : designSpec.heatingVolFlowRatio; + + if (specNumSpeeds != varSpeedCoil.NumOfSpeeds) { + ShowFatalError(state, + EnergyPlus::format("COIL:{}{} = \"{}\" number of speeds not equal to number of speed specified in " + "UnitarySystemPerformance:Multispeed object.", + varSpeedCoil.CoolHeatType, + CurrentObjSubfix, + varSpeedCoil.Name)); + } else { + for (Mode = varSpeedCoil.NumOfSpeeds; Mode >= 1; --Mode) { + varSpeedCoil.MSRatedAirVolFlowRate(Mode) = varSpeedCoil.RatedAirVolFlowRate * volFlowRatios[Mode - 1]; + varSpeedCoil.MSRatedTotCap(Mode) = + varSpeedCoil.MSRatedAirVolFlowRate(Mode) / varSpeedCoil.MSRatedAirVolFlowPerRatedTotCap(Mode); + varSpeedCoil.MSRatedAirMassFlowRate(Mode) = varSpeedCoil.MSRatedAirVolFlowRate(Mode) * rhoair; + // EVAPORATIVE PRECOOLING CONDENSER AIR FLOW RATE + varSpeedCoil.EvapCondAirFlow(Mode) = + varSpeedCoil.MSRatedTotCap(Mode) * varSpeedCoil.MSRatedEvapCondVolFlowPerRatedTotCap(Mode); } } } else { @@ -4751,23 +4108,14 @@ namespace VariableSpeedCoils { RatedWaterVolFlowRateDes); // Ensure water flow rate at lower speed must be lower or // equal to the flow rate at higher speed. Otherwise, a severe error is issued. - for (Mode = 1; Mode <= varSpeedCoil.NumOfSpeeds - 1; ++Mode) { - if (varSpeedCoil.MSRatedWaterVolFlowRate(Mode) > varSpeedCoil.MSRatedWaterVolFlowRate(Mode + 1) * 1.05) { - ShowWarningError( - state, - EnergyPlus::format( - "SizeDXCoil: {} {}, Speed {} Rated Air Flow Rate must be less than or equal to Speed {} Rated Air Flow Rate.", - varSpeedCoil.VarSpeedCoilType, - varSpeedCoil.Name, - Mode, - Mode + 1)); - ShowContinueError(state, - EnergyPlus::format("Instead, {:.2R} > {:.2R}", - varSpeedCoil.MSRatedAirVolFlowRate(Mode), - varSpeedCoil.MSRatedAirVolFlowRate(Mode + 1))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - } + checkSpeedLevelMonotonicity(state, + varSpeedCoil.VarSpeedCoilType, + varSpeedCoil.Name, + varSpeedCoil.NumOfSpeeds, + varSpeedCoil.MSRatedWaterVolFlowRate, + varSpeedCoil.MSRatedAirVolFlowRate, + "Rated Air Flow Rate", + 1.05); } else { if (varSpeedCoil.RatedWaterVolFlowRate > 0.0 && RatedWaterVolFlowRateDes > 0.0) { RatedWaterVolFlowRateUser = varSpeedCoil.RatedWaterVolFlowRate; @@ -4778,22 +4126,14 @@ namespace VariableSpeedCoils { RatedWaterVolFlowRateDes, "User-Specified Rated Water Flow Rate [m3/s]", RatedWaterVolFlowRateUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(RatedWaterVolFlowRateDes - RatedWaterVolFlowRateUser) / RatedWaterVolFlowRateUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVarSpeedCoil: Potential issue with equipment sizing for {} {}", - varSpeedCoil.CoolHeatType, - CurrentObjSubfix)); - ShowContinueError(state, EnergyPlus::format("Coil Name = {}", varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Rated Water Flow Rate of {:.5R} [m3/s]", RatedWaterVolFlowRateUser)); - ShowContinueError( - state, EnergyPlus::format("differs from Design Size Rated Water Flow Rate of {:.5R} [m3/s]", RatedWaterVolFlowRateDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + reportSizingMismatchWarning(state, + varSpeedCoil.CoolHeatType, + CurrentObjSubfix, + varSpeedCoil.Name, + "Rated Water Flow Rate [m3/s]", + RatedWaterVolFlowRateUser, + "Rated Water Flow Rate [m3/s]", + RatedWaterVolFlowRateDes); } } @@ -4833,39 +4173,22 @@ namespace VariableSpeedCoils { // Ensure air flow rate at lower speed must be lower or // equal to the flow rate at higher speed. Otherwise, a severe error is issued. - for (Mode = 1; Mode <= varSpeedCoil.NumOfSpeeds - 1; ++Mode) { - if (varSpeedCoil.MSRatedAirVolFlowRate(Mode) > varSpeedCoil.MSRatedAirVolFlowRate(Mode + 1)) { - ShowWarningError( - state, - EnergyPlus::format("SizeDXCoil: {} {}, Speed {} Rated Air Flow Rate must be less than or equal to Speed {} Rated Air Flow Rate.", - varSpeedCoil.VarSpeedCoilType, - varSpeedCoil.Name, - Mode, - Mode + 1)); - ShowContinueError(state, - EnergyPlus::format("Instead, {:.2R} > {:.2R}", - varSpeedCoil.MSRatedAirVolFlowRate(Mode), - varSpeedCoil.MSRatedAirVolFlowRate(Mode + 1))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - } + checkSpeedLevelMonotonicity(state, + varSpeedCoil.VarSpeedCoilType, + varSpeedCoil.Name, + varSpeedCoil.NumOfSpeeds, + varSpeedCoil.MSRatedAirVolFlowRate, + varSpeedCoil.MSRatedAirVolFlowRate, + "Rated Air Flow Rate"); // Ensure capacity at lower speed must be lower or equal to the capacity at higher speed. - for (Mode = 1; Mode <= varSpeedCoil.NumOfSpeeds - 1; ++Mode) { - if (varSpeedCoil.MSRatedTotCap(Mode) > varSpeedCoil.MSRatedTotCap(Mode + 1)) { - ShowWarningError( - state, - EnergyPlus::format("SizeDXCoil: {} {}, Speed {} Rated Total Cooling Capacity must be less than or equal to Speed {} Rated Total " - "Cooling Capacity.", - varSpeedCoil.VarSpeedCoilType, - varSpeedCoil.Name, - Mode, - Mode + 1)); - ShowContinueError( - state, EnergyPlus::format("Instead, {:.2R} > {:.2R}", varSpeedCoil.MSRatedTotCap(Mode), varSpeedCoil.MSRatedTotCap(Mode + 1))); - ShowFatalError(state, "Preceding conditions cause termination."); - } - } + checkSpeedLevelMonotonicity(state, + varSpeedCoil.VarSpeedCoilType, + varSpeedCoil.Name, + varSpeedCoil.NumOfSpeeds, + varSpeedCoil.MSRatedTotCap, + varSpeedCoil.MSRatedTotCap, + "Rated Total Cooling Capacity"); // convert SHR to rated Bypass factor and effective air side surface area if (varSpeedCoil.VSCoilType == HVAC::Coil_CoolingWaterToAirHPVSEquationFit || @@ -4896,13 +4219,11 @@ namespace VariableSpeedCoils { for (Mode = 1; Mode <= varSpeedCoil.NumOfSpeeds; ++Mode) { // get cooling capacity, without fan power, i.e. total coil cooling - if (varSpeedCoil.CondPumpPowerInCOP) { - HPWHCoolCapacity = varSpeedCoil.MSRatedTotCap(Mode) * (1.0 - 1.0 / varSpeedCoil.MSRatedCOP(Mode)) + - varSpeedCoil.MSWHPumpPower(Mode) - varSpeedCoil.MSWHPumpPower(Mode) * varSpeedCoil.HPWHCondPumpFracToWater; - } else { - HPWHCoolCapacity = varSpeedCoil.MSRatedTotCap(Mode) * (1.0 - 1.0 / varSpeedCoil.MSRatedCOP(Mode)) - - varSpeedCoil.MSWHPumpPower(Mode) * varSpeedCoil.HPWHCondPumpFracToWater; - } + HPWHCoolCapacity = calcHPWHCoolCapacity(varSpeedCoil.MSRatedTotCap(Mode), + varSpeedCoil.MSRatedCOP(Mode), + varSpeedCoil.MSWHPumpPower(Mode), + varSpeedCoil.HPWHCondPumpFracToWater, + varSpeedCoil.CondPumpPowerInCOP); varSpeedCoil.MSRatedCBF(Mode) = DXCoils::CalcCBF(state, varSpeedCoil.VarSpeedCoilType, @@ -4922,14 +4243,11 @@ namespace VariableSpeedCoils { // update VarSpeedCoil(DXCoilNum).RatedCapCoolTotal Mode = varSpeedCoil.NormSpedLevel; - if (varSpeedCoil.CondPumpPowerInCOP) { - varSpeedCoil.RatedCapCoolTotal = varSpeedCoil.MSRatedTotCap(Mode) * (1.0 - 1.0 / varSpeedCoil.MSRatedCOP(Mode)) + - varSpeedCoil.MSWHPumpPower(Mode) - - varSpeedCoil.MSWHPumpPower(Mode) * varSpeedCoil.HPWHCondPumpFracToWater; - } else { - varSpeedCoil.RatedCapCoolTotal = varSpeedCoil.MSRatedTotCap(Mode) * (1.0 - 1.0 / varSpeedCoil.MSRatedCOP(Mode)) - - varSpeedCoil.MSWHPumpPower(Mode) * varSpeedCoil.HPWHCondPumpFracToWater; - } + varSpeedCoil.RatedCapCoolTotal = calcHPWHCoolCapacity(varSpeedCoil.MSRatedTotCap(Mode), + varSpeedCoil.MSRatedCOP(Mode), + varSpeedCoil.MSWHPumpPower(Mode), + varSpeedCoil.HPWHCondPumpFracToWater, + varSpeedCoil.CondPumpPowerInCOP); } // size rated sensible cooling capacity @@ -5068,25 +4386,14 @@ namespace VariableSpeedCoils { EvapCondPumpElecNomPowerDes, "User-Specified Evaporative Condenser Pump Rated Power Consumption [W]", EvapCondPumpElecNomPowerUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(EvapCondPumpElecNomPowerDes - EvapCondPumpElecNomPowerUser) / EvapCondPumpElecNomPowerUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVarSpeedCoil: Potential issue with equipment sizing for {} {}", - varSpeedCoil.CoolHeatType, - CurrentObjSubfix)); - ShowContinueError(state, EnergyPlus::format("Coil Name = {}", varSpeedCoil.Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Evaporative Condenser Pump Rated Power Consumption of {:.2R} [W]", - EvapCondPumpElecNomPowerUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Evaporative Condenser Pump Rated Power Consumption of {:.2R} [W]", - EvapCondPumpElecNomPowerDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + reportSizingMismatchWarning(state, + varSpeedCoil.CoolHeatType, + CurrentObjSubfix, + varSpeedCoil.Name, + "Evaporative Condenser Pump Rated Power Consumption [W]", + EvapCondPumpElecNomPowerUser, + "Evaporative Condenser Pump Rated Power Consumption [W]", + EvapCondPumpElecNomPowerDes); } } } @@ -5119,22 +4426,14 @@ namespace VariableSpeedCoils { DefrostCapacityDes, "User-Specified Resistive Defrost Heater Capacity [W]", DefrostCapacityUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(DefrostCapacityDes - DefrostCapacityUser) / DefrostCapacityUser) > state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format("SizeVarSpeedCoil: Potential issue with equipment sizing for {} {}", - varSpeedCoil.CoolHeatType, - CurrentObjSubfix)); - ShowContinueError(state, EnergyPlus::format("Coil Name = {}", varSpeedCoil.Name)); - ShowContinueError( - state, EnergyPlus::format("User-Specified Resistive Defrost Heater Capacity of {:.2R} [W]", DefrostCapacityUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Resistive Defrost Heater Capacity of {:.2R} [W]", DefrostCapacityDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + reportSizingMismatchWarning(state, + varSpeedCoil.CoolHeatType, + CurrentObjSubfix, + varSpeedCoil.Name, + "Resistive Defrost Heater Capacity [W]", + DefrostCapacityUser, + "Resistive Defrost Heater Capacity [W]", + DefrostCapacityDes); } } } @@ -5143,51 +4442,29 @@ namespace VariableSpeedCoils { // test autosized sensible and total cooling capacity for total > sensible if (RatedCapCoolSensAutoSized && RatedCapCoolTotalAutoSized) { if (varSpeedCoil.RatedCapCoolSens > varSpeedCoil.RatedCapCoolTotal) { - ShowWarningError( - state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT \"{}\"", varSpeedCoil.CoolHeatType, varSpeedCoil.Name)); - ShowContinueError(state, EnergyPlus::format("{}: Rated Sensible Cooling Capacity > Rated Total Cooling Capacity", RoutineName)); - ShowContinueError(state, "Each of these capacity inputs have been autosized."); - ShowContinueError(state, EnergyPlus::format("Rated Sensible Cooling Capacity = {:.2T} W", varSpeedCoil.RatedCapCoolSens)); - ShowContinueError(state, EnergyPlus::format("Rated Total Cooling Capacity = {:.2T} W", varSpeedCoil.RatedCapCoolTotal)); - ShowContinueError(state, "See eio file for further details."); - ShowContinueError(state, "Check Total and Sensible Cooling Capacity Coefficients to ensure they are accurate."); - ShowContinueError(state, "Check Zone and System Sizing objects to verify sizing inputs."); - ShowContinueError(state, "Sizing statistics:"); - ShowContinueError(state, EnergyPlus::format("Entering Air Dry-Bulb Temperature = {:.3T} C", MixTemp)); - ShowContinueError(state, EnergyPlus::format("Entering Air Wet-Bulb Temperature = {:.3T} C", MixWetBulb)); - ShowContinueError(state, "Entering Condenser Water Temperature used = 24.4444 C"); - ShowContinueError(state, "Used design air and water flow rates (i.e., used 1 for ratioVL and ratioVS)"); - ShowContinueError(state, EnergyPlus::format("ratioTDB = {:.3T}", ((MixTemp + 283.15) / 273.15))); - ShowContinueError(state, EnergyPlus::format("ratioTWB = {:.3T}", ((MixWetBulb + 283.15) / 273.15))); - ShowContinueError(state, EnergyPlus::format("ratioTS = {:.3T}", ((85.0 + 283.15) / 273.15))); - ShowContinueError(state, "Rated Sensible Cooling Capacity = Rated Total Cooling Capacity * Sensible Heat Ratio"); - ShowContinueError(state, EnergyPlus::format("Total Cooling Capacity Modifier = {:.5T}", TotCapTempModFac)); - ShowContinueError(state, "...Rated Total Cooling Capacity = Total Design Load / Total Cooling Capacity Modifier"); - ShowContinueError(state, "Carefully review the Load Side Total, Sensible, and Latent heat transfer rates"); - ShowContinueError(state, "... to ensure they meet the expected manufacturers performance specifications."); + warnSensibleExceedsTotal(state, + varSpeedCoil.CoolHeatType, + varSpeedCoil.Name, + "Each of these capacity inputs have been autosized.", + "Sizing statistics:", + varSpeedCoil.RatedCapCoolSens, + varSpeedCoil.RatedCapCoolTotal, + MixWetBulb, + MixTemp, + TotCapTempModFac); } } else if (RatedCapCoolTotalAutoSized) { if (varSpeedCoil.RatedCapCoolSens > varSpeedCoil.RatedCapCoolTotal) { - ShowWarningError( - state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT \"{}\"", varSpeedCoil.CoolHeatType, varSpeedCoil.Name)); - ShowContinueError(state, EnergyPlus::format("{}: Rated Sensible Cooling Capacity > Rated Total Cooling Capacity", RoutineName)); - ShowContinueError(state, "Only the rated total capacity input is autosized, consider autosizing both inputs."); - ShowContinueError(state, EnergyPlus::format("Rated Sensible Cooling Capacity = {:.2T} W", varSpeedCoil.RatedCapCoolSens)); - ShowContinueError(state, EnergyPlus::format("Rated Total Cooling Capacity = {:.2T} W", varSpeedCoil.RatedCapCoolTotal)); - ShowContinueError(state, "See eio file for further details."); - ShowContinueError(state, "Check Total and Sensible Cooling Capacity Coefficients to ensure they are accurate."); - ShowContinueError(state, "Check Zone and System Sizing objects to verify sizing inputs."); - ShowContinueError(state, "Sizing statistics for Total Cooling Capacity:"); - ShowContinueError(state, EnergyPlus::format("Entering Air Wet-Bulb Temperature = {:.3T} C", MixWetBulb)); - ShowContinueError(state, "Entering Condenser Water Temperature used = 24.4444 C"); - ShowContinueError(state, "Used design air and water flow rates (i.e., used 1 for ratioVL and ratioVS)"); - ShowContinueError(state, EnergyPlus::format("ratioTWB = {:.3T}", ((MixWetBulb + 283.15) / 273.15))); - ShowContinueError(state, EnergyPlus::format("ratioTS = {:.3T}", ((85.0 + 283.15) / 273.15))); - ShowContinueError(state, "Rated Sensible Cooling Capacity = Rated Total Cooling Capacity * Sensible Heat Ratio"); - ShowContinueError(state, "Carefully review the Load Side Total, Sensible, and Latent heat transfer rates"); - ShowContinueError(state, "... to ensure they meet the expected manufacturers performance specifications."); + warnSensibleExceedsTotal(state, + varSpeedCoil.CoolHeatType, + varSpeedCoil.Name, + "Only the rated total capacity input is autosized, consider autosizing both inputs.", + "Sizing statistics for Total Cooling Capacity:", + varSpeedCoil.RatedCapCoolSens, + varSpeedCoil.RatedCapCoolTotal, + MixWetBulb, + -999.0, + -999.0); } } diff --git a/src/EnergyPlus/VentilatedSlab.cc b/src/EnergyPlus/VentilatedSlab.cc index bdf6fc53ccb..c7208a623a8 100644 --- a/src/EnergyPlus/VentilatedSlab.cc +++ b/src/EnergyPlus/VentilatedSlab.cc @@ -671,56 +671,7 @@ namespace VentilatedSlab { // %OutsideAirNode is the outdoor air inlet to the OA mixer // For all types of ventilated slab, this is Node::NodeConnectionType::Inlet,ObjectIsNotParent, -OA MIXER - if (ventSlab.SysConfg == VentilatedSlabConfig::SlabOnly) { - - ventSlab.ReturnAirNode = Node::GetOnlySingleNode(state, - state.dataIPShortCut->cAlphaArgs(18), - ErrorsFound, - Node::ConnectionObjectType::ZoneHVACVentilatedSlab, - ventSlab.Name + "-OA MIXER", - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - ventSlab.ReturnAirNode = Node::GetOnlySingleNode(state, - state.dataIPShortCut->cAlphaArgs(18), - ErrorsFound, - Node::ConnectionObjectType::ZoneHVACVentilatedSlab, - ventSlab.Name, - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsParent); - ventSlab.RadInNode = Node::GetOnlySingleNode(state, - state.dataIPShortCut->cAlphaArgs(19), - ErrorsFound, - Node::ConnectionObjectType::ZoneHVACVentilatedSlab, - ventSlab.Name, - Node::FluidType::Air, - Node::ConnectionType::Inlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - - ventSlab.OAMixerOutNode = Node::GetOnlySingleNode(state, - state.dataIPShortCut->cAlphaArgs(23), - ErrorsFound, - Node::ConnectionObjectType::ZoneHVACVentilatedSlab, - ventSlab.Name + "-OA MIXER", - Node::FluidType::Air, - Node::ConnectionType::Outlet, - Node::CompFluidStream::Primary, - Node::ObjectIsNotParent); - ventSlab.FanOutletNode = Node::GetOnlySingleNode(state, - state.dataIPShortCut->cAlphaArgs(24), - ErrorsFound, - Node::ConnectionObjectType::ZoneHVACVentilatedSlab, - ventSlab.Name, - Node::FluidType::Air, - Node::ConnectionType::Internal, - Node::CompFluidStream::Primary, - Node::ObjectIsParent); - - } else if (ventSlab.SysConfg == VentilatedSlabConfig::SeriesSlabs) { + if (ventSlab.SysConfg == VentilatedSlabConfig::SlabOnly || ventSlab.SysConfg == VentilatedSlabConfig::SeriesSlabs) { ventSlab.ReturnAirNode = Node::GetOnlySingleNode(state, state.dataIPShortCut->cAlphaArgs(18), @@ -768,7 +719,6 @@ namespace VentilatedSlab { Node::ConnectionType::Internal, Node::CompFluidStream::Primary, Node::ObjectIsParent); - } else if (ventSlab.SysConfg == VentilatedSlabConfig::SlabAndZone) { ventSlab.ReturnAirNode = Node::GetOnlySingleNode(state, diff --git a/src/EnergyPlus/WaterToAirHeatPumpSimple.cc b/src/EnergyPlus/WaterToAirHeatPumpSimple.cc index 74b00d60ede..4ed05c7a700 100644 --- a/src/EnergyPlus/WaterToAirHeatPumpSimple.cc +++ b/src/EnergyPlus/WaterToAirHeatPumpSimple.cc @@ -1183,6 +1183,301 @@ namespace WaterToAirHeatPumpSimple { state.dataHeatBal->HeatReclaimSimple_WAHPCoil(HPNum).AvailCapacity = 0.0; } + // Helper: emit common "sizing statistics" warning lines for sensible > total capacity diagnosis. + static void showCapacitySizingStats(EnergyPlusData &state, + Real64 RatedMixWetBulb, + Real64 MixWetBulb, + Real64 RatedEntWaterTemp, + Real64 RatedratioTWB, + Real64 RatedratioTS, + Real64 ratioTWB, + Real64 ratioTS, + Real64 RatedTotCapTempModFac, + Real64 PeakTotCapTempModFac, + std::string_view sizingStatsHeader, + Real64 RatedSensCapTempModFac = -1.0, + Real64 PeakSensCapTempModFac = -1.0) + { + bool const includeSensibleModifiers = (RatedSensCapTempModFac >= 0.0); + ShowContinueError(state, "See eio file for further details."); + ShowContinueError(state, "Check Total and Sensible Cooling Capacity coefficients in curves to ensure they are accurate."); + ShowContinueError(state, "Check Zone and System Sizing objects to verify sizing inputs."); + ShowContinueError(state, std::string(sizingStatsHeader)); + ShowContinueError(state, EnergyPlus::format("Rated entering Air Wet-Bulb Temperature = {:.3T} C", RatedMixWetBulb)); + ShowContinueError(state, EnergyPlus::format("Peak entering Air Wet-Bulb Temperature = {:.3T} C", MixWetBulb)); + ShowContinueError(state, EnergyPlus::format("Entering Water Temperature used = {:.3T} C", RatedEntWaterTemp)); + ShowContinueError(state, "Design air and water flow rates = 1.0"); + ShowContinueError( + state, EnergyPlus::format("Rated ratio of load-side air wet-bulb temperature to 283.15 C (Rated ratioTWB) = {:.3T}", RatedratioTWB)); + ShowContinueError( + state, EnergyPlus::format("Rated ratio of source-side inlet water temperature to 283.15 C (Rated ratioTS) = {:.3T}", RatedratioTS)); + ShowContinueError(state, + EnergyPlus::format("Peak ratio of load-side air wet-bulb temperature to 283.15 C (Peak ratioTWB) = {:.3T}", ratioTWB)); + ShowContinueError(state, + EnergyPlus::format("Peak ratio of source-side inlet water temperature to 283.15 C (Peak ratioTS) = {:.3T}", ratioTS)); + ShowContinueError(state, EnergyPlus::format("Rated Total Cooling Capacity Modifier = {:.5T}", RatedTotCapTempModFac)); + ShowContinueError(state, EnergyPlus::format("Peak Design Total Cooling Capacity Modifier = {:.5T}", PeakTotCapTempModFac)); + if (includeSensibleModifiers) { + ShowContinueError(state, EnergyPlus::format("Rated Sensible Cooling Capacity Modifier = {:.5T}", RatedSensCapTempModFac)); + ShowContinueError(state, EnergyPlus::format("Peak Design Sensible Cooling Capacity Modifier = {:.5T}", PeakSensCapTempModFac)); + } + ShowContinueError(state, + "...Rated Total Cooling Capacity at Rated Conditions = Total Peak Design Load * Rated Total " + "Cooling Capacity Modifier / " + "Peak Design Total Cooling Capacity Modifier"); + ShowContinueError(state, + "...Rated Sensible Cooling Capacity at Rated Conditions = Peak Design Sensible Load * Rated " + "Sensible Cooling " + "Capacity Modifier / Peak Design Sensible Cooling Capacity Modifier"); + ShowContinueError(state, "Carefully review the Load Side Total, Sensible, and Latent heat transfer rates"); + ShowContinueError(state, "... to ensure they meet the expected manufacturers performance specifications."); + } + + // Helper: look up plant sizing index and compute water temperature ratio. + // Returns the plant sizing index (> 0 on success). On failure, shows errors and sets ErrorsFound. + static int getPlantSizingIndexAndRatioTS(EnergyPlusData &state, + std::string_view compType, + std::string_view compName, + int waterInletNode, + int waterOutletNode, + std::string_view capacityType, + Real64 Tref, + Real64 &ratioTS, + bool &ErrorsFound) + { + int PltSizNum = PlantUtilities::MyPlantSizingIndex(state, compType, compName, waterInletNode, waterOutletNode, ErrorsFound, false); + if (PltSizNum > 0) { + Real64 DesignEntWaterTemp = state.dataSize->PlantSizData(PltSizNum).ExitTemp; + ratioTS = (DesignEntWaterTemp + Constant::Kelvin) / Tref; + } else { + ShowSevereError(state, EnergyPlus::format("Autosizing of {} requires a loop Sizing:Plant object", capacityType)); + ShowContinueError(state, "Autosizing also requires physical connection to a plant or condenser loop."); + ShowContinueError(state, EnergyPlus::format("Occurs in {} Object={}", compType, compName)); + ratioTS = 0.0; + ErrorsFound = true; + } + return PltSizNum; + } + + // Helper: report user-specified vs design-size comparison and optional extra warnings. + // Used by SizeHVACWaterToAir to deduplicate the recurring hardsize-vs-autosize reporting pattern. + static void reportSizingComparison(EnergyPlusData &state, + std::string_view compType, + std::string_view compName, + std::string_view designLabel, + std::string_view userLabel, + Real64 designValue, + Real64 userValue) + { + if ((std::abs(designValue - userValue) / userValue) > state.dataSize->AutoVsHardSizingThreshold) { + BaseSizer::reportSizerOutput(state, compType, compName, designLabel, designValue, userLabel, userValue); + } else { + BaseSizer::reportSizerOutput(state, compType, compName, userLabel, userValue); + } + if (state.dataGlobal->DisplayExtraWarnings) { + if ((std::abs(designValue - userValue) / userValue) > state.dataSize->AutoVsHardSizingThreshold) { + ShowMessage(state, + EnergyPlus::format("SizeHVACWaterToAir: Potential issue with equipment sizing for coil {} \"{}\"", compType, compName)); + ShowContinueError(state, EnergyPlus::format("{} of {:.5R}", userLabel, userValue)); + ShowContinueError(state, EnergyPlus::format("differs from {} of {:.5R}", designLabel, designValue)); + ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); + ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); + } + } + } + + // Helper: compute rated heating capacity from peak design conditions. + // Calculates rhoair, peak heating load, fan heat adjustment, temperature ratios, + // curve modifiers, and returns the rated heating capacity. + static void calcRatedHeatCap(EnergyPlusData &state, + SimpleWatertoAirHPConditions const &coil, + std::string const &CompType, + Real64 VolFlowRate, + Real64 &HeatMixTemp, + Real64 HeatMixHumRat, + Real64 &HeatSupTemp, + HVAC::FanPlace fanPlace, + Real64 Tref, + Real64 &FanHeatLoad, + Real64 &RatedHeatMixDryBulb, + Real64 &HeatratioTDB, + Real64 &HeatratioTS, + Real64 &RatedHeatratioTDB, + Real64 &RatedHeatratioTS, + Real64 &PeakHeatCapTempModFac, + Real64 &RatedHeatCapTempModFac, + Real64 &RatedHeatPowerTempModFac, + Real64 &RatedCapHeatDes, + int &PltSizNum, + bool &ErrorsFound) + { + static constexpr std::string_view RoutineName("SizeWaterToAirCoil"); + Real64 rhoair = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, HeatMixTemp, HeatMixHumRat, RoutineName); + Real64 HeatCapAtPeak = rhoair * VolFlowRate * Psychrometrics::PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * (HeatSupTemp - HeatMixTemp); + if (state.dataSize->DataFanType != HVAC::FanType::Invalid && state.dataSize->DataFanIndex > 0) { + FanHeatLoad = state.dataFans->fans(state.dataSize->DataFanIndex)->getDesignHeatGain(state, VolFlowRate); + Real64 CpAir = Psychrometrics::PsyCpAirFnW(HeatMixHumRat); + if (fanPlace == HVAC::FanPlace::BlowThru) { + HeatMixTemp += FanHeatLoad / (CpAir * rhoair * VolFlowRate); + } else if (fanPlace == HVAC::FanPlace::DrawThru) { + HeatSupTemp -= FanHeatLoad / (CpAir * rhoair * VolFlowRate); + } + } + HeatCapAtPeak -= FanHeatLoad; + HeatCapAtPeak = max(0.0, HeatCapAtPeak); + RatedHeatMixDryBulb = coil.RatedEntAirDrybulbTemp; + HeatratioTDB = (HeatMixTemp + Constant::Kelvin) / Tref; + PltSizNum = getPlantSizingIndexAndRatioTS( + state, CompType, coil.Name, coil.WaterInletNodeNum, coil.WaterOutletNodeNum, "heating capacity", Tref, HeatratioTS, ErrorsFound); + RatedHeatratioTDB = (RatedHeatMixDryBulb + Constant::Kelvin) / Tref; + RatedHeatratioTS = (coil.RatedEntWaterTemp + Constant::Kelvin) / Tref; + PeakHeatCapTempModFac = coil.HeatCapCurve->value(state, HeatratioTDB, HeatratioTS, 1.0, 1.0); + RatedHeatCapTempModFac = coil.HeatCapCurve->value(state, RatedHeatratioTDB, RatedHeatratioTS, 1.0, 1.0); + if (coil.HeatPowCurve != nullptr) { + RatedHeatPowerTempModFac = coil.HeatPowCurve->value(state, RatedHeatratioTDB, RatedHeatratioTS, 1.0, 1.0); + } + if (RatedHeatMixDryBulb == HeatMixTemp) { + if (RatedHeatCapTempModFac > 1.02 || RatedHeatCapTempModFac < 0.98) { + ShowWarningError(state, EnergyPlus::format("{} Coil:Heating:WaterToAirHeatPump:EquationFit={}", RoutineName, coil.Name)); + ShowContinueError(state, + "Heating capacity as a function of temperature curve output is not equal to 1.0 (+ or - 2%) " + "at rated conditions."); + ShowContinueError(state, EnergyPlus::format("Curve output at rated conditions = {:.3T}", RatedHeatCapTempModFac)); + } + if (coil.HeatPowCurve != nullptr && (RatedHeatPowerTempModFac > 1.02 || RatedHeatPowerTempModFac < 0.98)) { + ShowWarningError(state, EnergyPlus::format("{} Coil:Heating:WaterToAirHeatPump:EquationFit={}", RoutineName, coil.Name)); + ShowContinueError(state, + "Heating power consumption as a function of temperature curve output is not equal to " + "1.0 (+ or - 2%) at rated conditions."); + ShowContinueError(state, EnergyPlus::format("Curve output at rated conditions = {:.3T}", RatedHeatPowerTempModFac)); + } + } + RatedCapHeatDes = (PeakHeatCapTempModFac > 0.0) ? HeatCapAtPeak / PeakHeatCapTempModFac : HeatCapAtPeak; + } + + // Helper: compute rated sensible cooling capacity from peak design conditions. + // Calculates enthalpies, fan heat adjustment, peak sensible load, curve modifiers, + // and returns the rated sensible cooling capacity. + static void calcRatedSensCoolCap(EnergyPlusData &state, + SimpleWatertoAirHPConditions const &coil, + std::string const &CompType, + Real64 VolFlowRate, + Real64 &MixTemp, + Real64 MixHumRat, + Real64 &SupTemp, + HVAC::FanPlace fanPlace, + Real64 Tref, + Real64 &FanCoolLoad, + Real64 &MixWetBulb, + Real64 &RatedMixWetBulb, + Real64 &RatedMixDryBulb, + Real64 &ratioTDB, + Real64 &ratioTWB, + Real64 &ratioTS, + Real64 &RatedratioTDB, + Real64 &RatedratioTWB, + Real64 &RatedratioTS, + Real64 &PeakSensCapTempModFac, + Real64 &RatedSensCapTempModFac, + Real64 &RatedCapCoolSensDes, + int &PltSizNum, + bool &ErrorsFound) + { + static constexpr std::string_view RoutineName("SizeWaterToAirCoil"); + Real64 rhoair = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, MixTemp, MixHumRat, RoutineName); + Real64 MixEnth = Psychrometrics::PsyHFnTdbW(MixTemp, MixHumRat); + Real64 SupEnth = Psychrometrics::PsyHFnTdbW(SupTemp, MixHumRat); + if (state.dataSize->DataFanType != HVAC::FanType::Invalid && state.dataSize->DataFanIndex > 0) { + FanCoolLoad = state.dataFans->fans(state.dataSize->DataFanIndex)->getDesignHeatGain(state, VolFlowRate); + Real64 CpAir = Psychrometrics::PsyCpAirFnW(MixHumRat); + if (fanPlace == HVAC::FanPlace::BlowThru) { + MixTemp += FanCoolLoad / (CpAir * rhoair * VolFlowRate); + } else if (fanPlace == HVAC::FanPlace::DrawThru) { + SupTemp -= FanCoolLoad / (CpAir * rhoair * VolFlowRate); + } + } + Real64 SensCapAtPeak = (rhoair * VolFlowRate * (MixEnth - SupEnth)) + FanCoolLoad; + SensCapAtPeak = max(0.0, SensCapAtPeak); + MixWetBulb = Psychrometrics::PsyTwbFnTdbWPb(state, MixTemp, MixHumRat, state.dataEnvrn->StdBaroPress, RoutineName); + RatedMixWetBulb = coil.RatedEntAirWetbulbTemp; + RatedMixDryBulb = coil.RatedEntAirDrybulbTemp; + ratioTDB = (MixTemp + Constant::Kelvin) / Tref; + ratioTWB = (MixWetBulb + Constant::Kelvin) / Tref; + PltSizNum = getPlantSizingIndexAndRatioTS( + state, CompType, coil.Name, coil.WaterInletNodeNum, coil.WaterOutletNodeNum, "sensible cooling capacity", Tref, ratioTS, ErrorsFound); + RatedratioTDB = (RatedMixDryBulb + Constant::Kelvin) / Tref; + RatedratioTWB = (RatedMixWetBulb + Constant::Kelvin) / Tref; + RatedratioTS = (coil.RatedEntWaterTemp + Constant::Kelvin) / Tref; + PeakSensCapTempModFac = coil.SensCoolCapCurve->value(state, ratioTDB, ratioTWB, ratioTS, 1.0, 1.0); + RatedSensCapTempModFac = coil.SensCoolCapCurve->value(state, RatedratioTDB, RatedratioTWB, RatedratioTS, 1.0, 1.0); + RatedCapCoolSensDes = (PeakSensCapTempModFac > 0.0) ? SensCapAtPeak / PeakSensCapTempModFac : SensCapAtPeak; + } + + // Helper: compute rated total cooling capacity from peak design conditions. + // Calculates enthalpies, fan heat adjustment, peak load, curve modifiers, + // and returns the rated total cooling capacity. Also sets reporting data. + static void calcRatedTotalCoolCap(EnergyPlusData &state, + SimpleWatertoAirHPConditions const &coil, + std::string const &CompType, + Real64 VolFlowRate, + Real64 &MixTemp, + Real64 MixHumRat, + Real64 MixTempSys, + Real64 MixHumRatSys, + Real64 &SupTemp, + Real64 SupHumRat, + HVAC::FanPlace fanPlace, + Real64 Tref, + Real64 &FanCoolLoad, + Real64 &dHratio, + Real64 &MixWetBulb, + Real64 &RatedMixWetBulb, + Real64 &ratioTWB, + Real64 &ratioTS, + Real64 &RatedratioTWB, + Real64 &RatedratioTS, + Real64 &PeakTotCapTempModFac, + Real64 &RatedTotCapTempModFac, + Real64 &RatedCoolPowerTempModFac, + Real64 &RatedCapCoolTotalDes, + int &PltSizNum, + bool &ErrorsFound) + { + static constexpr std::string_view RoutineName("SizeWaterToAirCoil"); + Real64 rhoair = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, MixTemp, MixHumRat, RoutineName); + Real64 MixEnth = Psychrometrics::PsyHFnTdbW(MixTemp, MixHumRat); + Real64 MixEnthSys = Psychrometrics::PsyHFnTdbW(MixTempSys, MixHumRatSys); + Real64 SupEnth = Psychrometrics::PsyHFnTdbW(SupTemp, SupHumRat); + dHratio = (SupEnth - MixEnthSys) / (SupEnth - MixEnth); + if (state.dataSize->DataFanType != HVAC::FanType::Invalid && state.dataSize->DataFanIndex > 0) { + FanCoolLoad = state.dataFans->fans(state.dataSize->DataFanIndex)->getDesignHeatGain(state, VolFlowRate); + Real64 CpAir = Psychrometrics::PsyCpAirFnW(MixHumRat); + if (fanPlace == HVAC::FanPlace::BlowThru) { + MixTemp += FanCoolLoad / (CpAir * rhoair * VolFlowRate); + } else if (fanPlace == HVAC::FanPlace::DrawThru) { + SupTemp -= FanCoolLoad / (CpAir * rhoair * VolFlowRate); + } + } + Real64 CoolCapAtPeak = (rhoair * VolFlowRate * (MixEnth - SupEnth)) + FanCoolLoad; + CoolCapAtPeak = max(0.0, CoolCapAtPeak); + MixWetBulb = Psychrometrics::PsyTwbFnTdbWPb(state, MixTemp, MixHumRat, state.dataEnvrn->StdBaroPress, RoutineName); + RatedMixWetBulb = coil.RatedEntAirWetbulbTemp; + ratioTWB = (MixWetBulb + Constant::Kelvin) / Tref; + PltSizNum = getPlantSizingIndexAndRatioTS( + state, CompType, coil.Name, coil.WaterInletNodeNum, coil.WaterOutletNodeNum, "total cooling capacity", Tref, ratioTS, ErrorsFound); + RatedratioTWB = (RatedMixWetBulb + Constant::Kelvin) / Tref; + RatedratioTS = (coil.RatedEntWaterTemp + Constant::Kelvin) / Tref; + PeakTotCapTempModFac = coil.TotalCoolCapCurve->value(state, ratioTWB, ratioTS, 1.0, 1.0); + RatedTotCapTempModFac = coil.TotalCoolCapCurve->value(state, RatedratioTWB, RatedratioTS, 1.0, 1.0); + RatedCoolPowerTempModFac = coil.CoolPowCurve->value(state, RatedratioTWB, RatedratioTS, 1.0, 1.0); + RatedCapCoolTotalDes = (PeakTotCapTempModFac > 0.0) ? CoolCapAtPeak / PeakTotCapTempModFac : CoolCapAtPeak; + state.dataRptCoilSelection->coilSelectionReportObj->setCoilEntAirTemp( + state, coil.Name, CompType, MixTemp, state.dataSize->CurSysNum, state.dataSize->CurZoneEqNum); + state.dataRptCoilSelection->coilSelectionReportObj->setCoilEntAirHumRat(state, coil.Name, CompType, MixHumRat); + state.dataRptCoilSelection->coilSelectionReportObj->setCoilLvgAirTemp(state, coil.Name, CompType, SupTemp); + state.dataRptCoilSelection->coilSelectionReportObj->setCoilLvgAirHumRat(state, coil.Name, CompType, SupHumRat); + } + void SizeHVACWaterToAir(EnergyPlusData &state, int const HPNum) { @@ -1205,17 +1500,17 @@ namespace WaterToAirHeatPumpSimple { static constexpr std::string_view RoutineNameAlt("SizeHVACWaterToAir"); // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - Real64 rhoair; - Real64 MixTemp; // Mixed air temperature at cooling design conditions - Real64 MixTempSys; // Mixed air temperature at cooling design conditions at system air flow - Real64 HeatMixTemp; // Mixed air temperature at heating design conditions - Real64 HeatMixTempSys; // Mixed air temperature at heating design conditions at system air flow - Real64 MixHumRat; // Mixed air humidity ratio at cooling design conditions - Real64 MixHumRatSys; // Mixed air humidity ratio at cooling design conditions at system air flow - Real64 HeatMixHumRat; // Mixed air humidity ratio at heating design conditions - Real64 HeatMixHumRatSys; // Mixed air humidity ratio at heating design conditions at system air flow - Real64 MixEnth; // Mixed air enthalpy at cooling design conditions - Real64 MixEnthSys; // Mixed air enthalpy at cooling design conditions at system air flow + // rhoair is now computed inside the calcRated* helpers + Real64 MixTemp; // Mixed air temperature at cooling design conditions + Real64 MixTempSys; // Mixed air temperature at cooling design conditions at system air flow + Real64 HeatMixTemp; // Mixed air temperature at heating design conditions + Real64 HeatMixTempSys; // Mixed air temperature at heating design conditions at system air flow + Real64 MixHumRat; // Mixed air humidity ratio at cooling design conditions + Real64 MixHumRatSys; // Mixed air humidity ratio at cooling design conditions at system air flow + Real64 HeatMixHumRat; // Mixed air humidity ratio at heating design conditions + Real64 HeatMixHumRatSys; // Mixed air humidity ratio at heating design conditions at system air flow + // MixEnth is now computed inside calcRatedTotalCoolCap and calcRatedSensCoolCap + // MixEnthSys is now computed inside calcRatedTotalCoolCap Real64 MixWetBulb; // Mixed air wet-bulb temperature at cooling design conditions Real64 RatedMixWetBulb = 0.0; // Rated mixed air wetbulb temperature Real64 RatedMixDryBulb = 0.0; // Rated mixed air drybulb temperature @@ -1223,30 +1518,29 @@ namespace WaterToAirHeatPumpSimple { Real64 SupTemp; // Supply air temperature at cooling design conditions Real64 HeatSupTemp; // Supply air temperature at heating design conditions Real64 SupHumRat; // Supply air humidity ratio at cooling design conditions - Real64 SupEnth; // Supply air enthalpy at cooling design conditions - Real64 OutTemp; // Outdoor aur dry-bulb temperature at cooling design conditions - Real64 ratioTDB; // Load-side dry-bulb temperature ratio at cooling design conditions - Real64 HeatratioTDB; // Load-side dry-bulb temperature ratio at heating design conditions - Real64 ratioTWB; // Load-side wet-bulb temperature ratio at cooling design conditions - Real64 ratioTS; // Source-side temperature ratio at cooling design conditions - Real64 HeatratioTS; // Source-side temperature ratio at heating design conditions - Real64 RatedratioTDB; // Rated cooling load-side dry-bulb temperature ratio - Real64 RatedHeatratioTDB = 0.0; // Rated cooling load-side dry-bulb temperature ratio - Real64 RatedratioTWB; // Rated cooling load-side wet-bulb temperature ratio - Real64 RatedratioTS; // Rated cooling source-side temperature ratio - Real64 RatedHeatratioTS; // Rated heating source-side temperature ratio - Real64 OutAirFrac; // Outdoor air fraction at cooling design conditions - Real64 OutAirFracSys; // Outdoor air fraction at cooling design conditions at system air flow - Real64 HeatOutAirFrac; // Outdoor air fraction at heating design conditions - Real64 HeatOutAirFracSys; // Outdoor air fraction at heating design conditions at system air flow + // SupEnth is now computed inside calcRatedTotalCoolCap and calcRatedSensCoolCap + Real64 OutTemp; // Outdoor aur dry-bulb temperature at cooling design conditions + Real64 ratioTDB; // Load-side dry-bulb temperature ratio at cooling design conditions + Real64 HeatratioTDB; // Load-side dry-bulb temperature ratio at heating design conditions + Real64 ratioTWB; // Load-side wet-bulb temperature ratio at cooling design conditions + Real64 ratioTS; // Source-side temperature ratio at cooling design conditions + Real64 HeatratioTS; // Source-side temperature ratio at heating design conditions + Real64 RatedratioTDB; // Rated cooling load-side dry-bulb temperature ratio + Real64 RatedHeatratioTDB = 0.0; // Rated cooling load-side dry-bulb temperature ratio + Real64 RatedratioTWB; // Rated cooling load-side wet-bulb temperature ratio + Real64 RatedratioTS; // Rated cooling source-side temperature ratio + Real64 RatedHeatratioTS; // Rated heating source-side temperature ratio + Real64 OutAirFrac; // Outdoor air fraction at cooling design conditions + Real64 OutAirFracSys; // Outdoor air fraction at cooling design conditions at system air flow + Real64 HeatOutAirFrac; // Outdoor air fraction at heating design conditions + Real64 HeatOutAirFracSys; // Outdoor air fraction at heating design conditions at system air flow Real64 VolFlowRate; - Real64 CoolCapAtPeak; // Load on the cooling coil at cooling design conditions - Real64 HeatCapAtPeak; // Load on the heating coil at heating design conditions - Real64 PeakTotCapTempModFac = 1.0; // Peak total cooling capacity curve modifier - Real64 RatedTotCapTempModFac = 1.0; // Rated total cooling capacity curve modifier - Real64 PeakHeatCapTempModFac = 1.0; // Peak heating capacity curve modifier - Real64 DesignEntWaterTemp; // Design entering coil water temperature - Real64 SensCapAtPeak; // Sensible load on the cooling coil at cooling design conditions + // CoolCapAtPeak is now computed inside calcRatedTotalCoolCap + // HeatCapAtPeak is now computed inside calcRatedHeatCap + Real64 PeakTotCapTempModFac = 1.0; // Peak total cooling capacity curve modifier + Real64 RatedTotCapTempModFac = 1.0; // Rated total cooling capacity curve modifier + Real64 PeakHeatCapTempModFac = 1.0; // Peak heating capacity curve modifier + // SensCapAtPeak is now computed inside calcRatedSensCoolCap Real64 PeakSensCapTempModFac = 1.0; // Peak sensible cooling capacity curve modifier Real64 RatedSensCapTempModFac = 1.0; // Rated sensible cooling capacity curve modifier Real64 RatedHeatCapTempModFac = 1.0; // Rated heating capacity curve modifier @@ -1328,17 +1622,13 @@ namespace WaterToAirHeatPumpSimple { HardSizeNoDesRun = true; if (simpleWatertoAirHP.RatedAirVolFlowRate > 0.0) { BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), + CompType, simpleWatertoAirHP.Name, "User-Specified Rated Air Flow Rate [m3/s]", simpleWatertoAirHP.RatedAirVolFlowRate); } } else { - CheckSysSizing( - state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name); + CheckSysSizing(state, CompType, simpleWatertoAirHP.Name); if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) { RatedAirVolFlowRateDes = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow; CoolingAirVolFlowRateDes = state.dataSize->CalcSysSizing(state.dataSize->CurSysNum).DesCoolVolFlow; @@ -1352,17 +1642,13 @@ namespace WaterToAirHeatPumpSimple { HardSizeNoDesRun = true; if (simpleWatertoAirHP.RatedAirVolFlowRate > 0.0) { BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), + CompType, simpleWatertoAirHP.Name, "User-Specified Rated Air Flow Rate [m3/s]", simpleWatertoAirHP.RatedAirVolFlowRate); } } else { - CheckZoneSizing( - state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name); + CheckZoneSizing(state, CompType, simpleWatertoAirHP.Name); RatedAirVolFlowRateDes = max(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow, state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow); CoolingAirVolFlowRateDes = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow; @@ -1376,50 +1662,17 @@ namespace WaterToAirHeatPumpSimple { if (IsAutoSize) { simpleWatertoAirHP.RatedAirVolFlowRate = RatedAirVolFlowRateDes; BaseSizer::reportSizerOutput( - state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "Design Size Rated Air Flow Rate [m3/s]", - RatedAirVolFlowRateDes); + state, CompType, simpleWatertoAirHP.Name, "Design Size Rated Air Flow Rate [m3/s]", RatedAirVolFlowRateDes); } else { if (simpleWatertoAirHP.RatedAirVolFlowRate > 0.0 && RatedAirVolFlowRateDes > 0.0) { RatedAirVolFlowRateUser = simpleWatertoAirHP.RatedAirVolFlowRate; - if ((std::abs(RatedAirVolFlowRateDes - RatedAirVolFlowRateUser) / RatedAirVolFlowRateUser) > - state.dataSize->AutoVsHardSizingThreshold) { - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "Design Size Rated Air Flow Rate [m3/s]", - RatedAirVolFlowRateDes, - "User-Specified Rated Air Flow Rate [m3/s]", - RatedAirVolFlowRateUser); - } else { - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "User-Specified Rated Air Flow Rate [m3/s]", - RatedAirVolFlowRateUser); - } - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(RatedAirVolFlowRateDes - RatedAirVolFlowRateUser) / RatedAirVolFlowRateUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage( - state, - EnergyPlus::format( - "SizeHVACWaterToAir: Potential issue with equipment sizing for coil {}:WATERTOAIRHEATPUMP:EQUATIONFIT \"{}\"", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)], - simpleWatertoAirHP.Name)); - ShowContinueError( - state, EnergyPlus::format("User-Specified Rated Air Volume Flow Rate of {:.5R} [m3/s]", RatedAirVolFlowRateUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Rated Air Volume Flow Rate of {:.5R} [m3/s]", RatedAirVolFlowRateDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + reportSizingComparison(state, + CompType, + simpleWatertoAirHP.Name, + "Design Size Rated Air Flow Rate [m3/s]", + "User-Specified Rated Air Flow Rate [m3/s]", + RatedAirVolFlowRateDes, + RatedAirVolFlowRateUser); } } } @@ -1442,17 +1695,13 @@ namespace WaterToAirHeatPumpSimple { HardSizeNoDesRun = true; if (simpleWatertoAirHP.RatedCapCoolTotal > 0.0) { BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), + CompType, simpleWatertoAirHP.Name, "User-Specified Rated Total Cooling Capacity [W]", simpleWatertoAirHP.RatedCapCoolTotal); } } else { - CheckSysSizing(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name); + CheckSysSizing(state, CompType, simpleWatertoAirHP.Name); if (CoolingAirVolFlowRateDes > 0.0) { VolFlowRate = CoolingAirVolFlowRateDes; } else { @@ -1501,70 +1750,32 @@ namespace WaterToAirHeatPumpSimple { // supply air condition is capped with that of mixed air to avoid SHR > 1.0 SupTemp = min(MixTemp, SupTemp); SupHumRat = min(MixHumRat, SupHumRat); - rhoair = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, MixTemp, MixHumRat, RoutineName); - MixEnth = Psychrometrics::PsyHFnTdbW(MixTemp, MixHumRat); - MixEnthSys = Psychrometrics::PsyHFnTdbW(MixTempSys, MixHumRatSys); - SupEnth = Psychrometrics::PsyHFnTdbW(SupTemp, SupHumRat); - // determine the coil ratio of coil dT with system air flow to design heating air flow - dHratio = (SupEnth - MixEnthSys) / (SupEnth - MixEnth); - if (state.dataSize->DataFanType != HVAC::FanType::Invalid && state.dataSize->DataFanIndex > 0) { // add fan heat to coil load - FanCoolLoad = state.dataFans->fans(state.dataSize->DataFanIndex)->getDesignHeatGain(state, VolFlowRate); - - Real64 CpAir = Psychrometrics::PsyCpAirFnW(MixHumRat); - if (state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace == HVAC::FanPlace::BlowThru) { - MixTemp += FanCoolLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature entering the coil - } else if (state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace == - HVAC::FanPlace::DrawThru) { - SupTemp -= FanCoolLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature leaving the coil - } - } - CoolCapAtPeak = (rhoair * VolFlowRate * (MixEnth - SupEnth)) + - FanCoolLoad; // load on the cooling coil which includes ventilation load and fan heat - CoolCapAtPeak = max(0.0, CoolCapAtPeak); - MixWetBulb = Psychrometrics::PsyTwbFnTdbWPb(state, MixTemp, MixHumRat, state.dataEnvrn->StdBaroPress, RoutineName); - RatedMixWetBulb = simpleWatertoAirHP.RatedEntAirWetbulbTemp; - // calculate temperatue ratio at design day peak conditions - ratioTWB = (MixWetBulb + Constant::Kelvin) / Tref; - PltSizNum = - PlantUtilities::MyPlantSizingIndex(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - simpleWatertoAirHP.WaterInletNodeNum, - simpleWatertoAirHP.WaterOutletNodeNum, - ErrorsFound, - false); - if (PltSizNum > 0) { - DesignEntWaterTemp = state.dataSize->PlantSizData(PltSizNum).ExitTemp; - ratioTS = (DesignEntWaterTemp + Constant::Kelvin) / Tref; - } else { - ShowSevereError(state, "Autosizing of total cooling capacity requires a loop Sizing:Plant object"); - ShowContinueError(state, "Autosizing also requires physical connection to a plant or condenser loop."); - ShowContinueError(state, - EnergyPlus::format("Occurs in COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT Object={}", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)], - simpleWatertoAirHP.Name)); - ratioTS = 0.0; // Clang complains it is used uninitialized if you don't give it a value - ErrorsFound = true; - } - // calculate temperatue ratio at rated conditions - RatedratioTWB = (RatedMixWetBulb + Constant::Kelvin) / Tref; - RatedratioTS = (simpleWatertoAirHP.RatedEntWaterTemp + Constant::Kelvin) / Tref; - // determine curve modifiers at peak and rated conditions - PeakTotCapTempModFac = simpleWatertoAirHP.TotalCoolCapCurve->value(state, ratioTWB, ratioTS, 1.0, 1.0); - RatedTotCapTempModFac = simpleWatertoAirHP.TotalCoolCapCurve->value(state, RatedratioTWB, RatedratioTS, 1.0, 1.0); - RatedCoolPowerTempModFac = simpleWatertoAirHP.CoolPowCurve->value(state, RatedratioTWB, RatedratioTS, 1.0, 1.0); - // calculate the rated total capacity based on peak conditions - // note: the rated total capacity can be different than the total capacity at - // rated conditions if the capacity curve isn't normalized at the rated - // conditions - RatedCapCoolTotalDes = (PeakTotCapTempModFac > 0.0) ? CoolCapAtPeak / PeakTotCapTempModFac : CoolCapAtPeak; - // reporting - state.dataRptCoilSelection->coilSelectionReportObj->setCoilEntAirTemp( - state, simpleWatertoAirHP.Name, CompType, MixTemp, state.dataSize->CurSysNum, state.dataSize->CurZoneEqNum); - state.dataRptCoilSelection->coilSelectionReportObj->setCoilEntAirHumRat(state, simpleWatertoAirHP.Name, CompType, MixHumRat); - state.dataRptCoilSelection->coilSelectionReportObj->setCoilLvgAirTemp(state, simpleWatertoAirHP.Name, CompType, SupTemp); - state.dataRptCoilSelection->coilSelectionReportObj->setCoilLvgAirHumRat(state, simpleWatertoAirHP.Name, CompType, SupHumRat); + calcRatedTotalCoolCap(state, + simpleWatertoAirHP, + CompType, + VolFlowRate, + MixTemp, + MixHumRat, + MixTempSys, + MixHumRatSys, + SupTemp, + SupHumRat, + state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace, + Tref, + FanCoolLoad, + dHratio, + MixWetBulb, + RatedMixWetBulb, + ratioTWB, + ratioTS, + RatedratioTWB, + RatedratioTS, + PeakTotCapTempModFac, + RatedTotCapTempModFac, + RatedCoolPowerTempModFac, + RatedCapCoolTotalDes, + PltSizNum, + ErrorsFound); } else { RatedCapCoolTotalDes = 0.0; } @@ -1574,17 +1785,13 @@ namespace WaterToAirHeatPumpSimple { HardSizeNoDesRun = true; if (simpleWatertoAirHP.RatedCapCoolTotal > 0.0) { BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), + CompType, simpleWatertoAirHP.Name, "User-Specified Rated Total Cooling Capacity [W]", simpleWatertoAirHP.RatedCapCoolTotal); } } else { - CheckZoneSizing(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name); + CheckZoneSizing(state, CompType, simpleWatertoAirHP.Name); if (CoolingAirVolFlowRateDes > 0.0) { VolFlowRate = CoolingAirVolFlowRateDes; } else { @@ -1633,69 +1840,32 @@ namespace WaterToAirHeatPumpSimple { } else { OutTemp = 0.0; } - rhoair = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, MixTemp, MixHumRat, RoutineName); - MixEnth = Psychrometrics::PsyHFnTdbW(MixTemp, MixHumRat); - MixEnthSys = Psychrometrics::PsyHFnTdbW(MixTempSys, MixHumRatSys); - SupEnth = Psychrometrics::PsyHFnTdbW(SupTemp, SupHumRat); - // determine the coil ratio of coil dH with system air flow to design heating air flow - dHratio = (SupEnth - MixEnthSys) / (SupEnth - MixEnth); - if (state.dataSize->DataFanType != HVAC::FanType::Invalid && state.dataSize->DataFanIndex > 0) { // add fan heat to coil load - FanCoolLoad = state.dataFans->fans(state.dataSize->DataFanIndex)->getDesignHeatGain(state, VolFlowRate); - - Real64 CpAir = Psychrometrics::PsyCpAirFnW(MixHumRat); - if (state.dataSize->DataFanPlacement == HVAC::FanPlace::BlowThru) { - MixTemp += FanCoolLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature entering the coil - } else { - SupTemp -= FanCoolLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature leaving the coil - } - } - CoolCapAtPeak = (rhoair * VolFlowRate * (MixEnth - SupEnth)) + - FanCoolLoad; // load on the cooling coil which includes ventilation load and fan heat - CoolCapAtPeak = max(0.0, CoolCapAtPeak); - MixWetBulb = Psychrometrics::PsyTwbFnTdbWPb(state, MixTemp, MixHumRat, state.dataEnvrn->StdBaroPress, RoutineName); - RatedMixWetBulb = simpleWatertoAirHP.RatedEntAirWetbulbTemp; - // calculate temperatue ratio at design day peak conditions - ratioTWB = (MixWetBulb + Constant::Kelvin) / Tref; - PltSizNum = - PlantUtilities::MyPlantSizingIndex(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - simpleWatertoAirHP.WaterInletNodeNum, - simpleWatertoAirHP.WaterOutletNodeNum, - ErrorsFound, - false); - if (PltSizNum > 0) { - DesignEntWaterTemp = state.dataSize->PlantSizData(PltSizNum).ExitTemp; - ratioTS = (DesignEntWaterTemp + Constant::Kelvin) / Tref; - } else { - ShowSevereError(state, "Autosizing of total cooling capacity requires a loop Sizing:Plant object"); - ShowContinueError(state, "Autosizing also requires physical connection to a plant or condenser loop."); - ShowContinueError(state, - EnergyPlus::format("Occurs in COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT Object={}", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)], - simpleWatertoAirHP.Name)); - ratioTS = 0.0; // Clang complains it is used uninitialized if you don't give it a value - ErrorsFound = true; - } - // calculate temperatue ratio at rated conditions - RatedratioTWB = (RatedMixWetBulb + Constant::Kelvin) / Tref; - RatedratioTS = (simpleWatertoAirHP.RatedEntWaterTemp + Constant::Kelvin) / Tref; - // determine curve modifiers at peak and rated conditions - PeakTotCapTempModFac = simpleWatertoAirHP.TotalCoolCapCurve->value(state, ratioTWB, ratioTS, 1.0, 1.0); - RatedTotCapTempModFac = simpleWatertoAirHP.TotalCoolCapCurve->value(state, RatedratioTWB, RatedratioTS, 1.0, 1.0); - RatedCoolPowerTempModFac = simpleWatertoAirHP.CoolPowCurve->value(state, RatedratioTWB, RatedratioTS, 1.0, 1.0); - // calculate the rated total capacity based on peak conditions - // note: the rated total capacity can be different than the total capacity at - // rated conditions if the capacity curve isn't normalized at the rated - // conditions - RatedCapCoolTotalDes = (PeakTotCapTempModFac > 0.0) ? CoolCapAtPeak / PeakTotCapTempModFac : CoolCapAtPeak; - // reporting - state.dataRptCoilSelection->coilSelectionReportObj->setCoilEntAirTemp( - state, simpleWatertoAirHP.Name, CompType, MixTemp, state.dataSize->CurSysNum, state.dataSize->CurZoneEqNum); - state.dataRptCoilSelection->coilSelectionReportObj->setCoilEntAirHumRat(state, simpleWatertoAirHP.Name, CompType, MixHumRat); - state.dataRptCoilSelection->coilSelectionReportObj->setCoilLvgAirTemp(state, simpleWatertoAirHP.Name, CompType, SupTemp); - state.dataRptCoilSelection->coilSelectionReportObj->setCoilLvgAirHumRat(state, simpleWatertoAirHP.Name, CompType, SupHumRat); + calcRatedTotalCoolCap(state, + simpleWatertoAirHP, + CompType, + VolFlowRate, + MixTemp, + MixHumRat, + MixTempSys, + MixHumRatSys, + SupTemp, + SupHumRat, + state.dataSize->DataFanPlacement, + Tref, + FanCoolLoad, + dHratio, + MixWetBulb, + RatedMixWetBulb, + ratioTWB, + ratioTS, + RatedratioTWB, + RatedratioTS, + PeakTotCapTempModFac, + RatedTotCapTempModFac, + RatedCoolPowerTempModFac, + RatedCapCoolTotalDes, + PltSizNum, + ErrorsFound); } else { RatedCapCoolTotalDes = 0.0; } @@ -1716,17 +1886,13 @@ namespace WaterToAirHeatPumpSimple { HardSizeNoDesRun = true; if (simpleWatertoAirHP.RatedCapCoolSens > 0.0) { BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), + CompType, simpleWatertoAirHP.Name, "User-Specified Rated Sensible Cooling Capacity [W]", simpleWatertoAirHP.RatedCapCoolSens); } } else { - CheckSysSizing(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name); + CheckSysSizing(state, CompType, simpleWatertoAirHP.Name); if (CoolingAirVolFlowRateDes > 0.0) { VolFlowRate = CoolingAirVolFlowRateDes; } else { @@ -1761,66 +1927,30 @@ namespace WaterToAirHeatPumpSimple { SupTemp = min(MixTemp, SupTemp); SupHumRat = min(MixHumRat, SupHumRat); OutTemp = finalSysSizing.OutTempAtCoolPeak; - rhoair = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, MixTemp, MixHumRat, RoutineName); - MixEnth = Psychrometrics::PsyHFnTdbW(MixTemp, MixHumRat); - SupEnth = Psychrometrics::PsyHFnTdbW(SupTemp, MixHumRat); - if (state.dataSize->DataFanType != HVAC::FanType::Invalid && state.dataSize->DataFanIndex > 0) { // add fan heat to coil load - FanCoolLoad = state.dataFans->fans(state.dataSize->DataFanIndex)->getDesignHeatGain(state, VolFlowRate); - - Real64 CpAir = Psychrometrics::PsyCpAirFnW(MixHumRat); - if (state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace == HVAC::FanPlace::BlowThru) { - MixTemp += FanCoolLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature entering the coil - } else if (state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace == - HVAC::FanPlace::DrawThru) { - SupTemp -= FanCoolLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature leaving the coil - } - } - // Sensible capacity is calculated from enthalpy difference with constant humidity ratio, i.e., - // there is only temperature difference between entering and leaving air enthalpy. Previously - // it was calculated using m.cp.dT - SensCapAtPeak = (rhoair * VolFlowRate * (MixEnth - SupEnth)) + - FanCoolLoad; // load on the cooling coil which includes ventilation load and fan heat (sensible) - SensCapAtPeak = max(0.0, SensCapAtPeak); - MixWetBulb = Psychrometrics::PsyTwbFnTdbWPb(state, MixTemp, MixHumRat, state.dataEnvrn->StdBaroPress, RoutineName); - RatedMixWetBulb = simpleWatertoAirHP.RatedEntAirWetbulbTemp; - RatedMixDryBulb = simpleWatertoAirHP.RatedEntAirDrybulbTemp; - // calculate temperature ratios at design day peak conditions - ratioTDB = (MixTemp + Constant::Kelvin) / Tref; - ratioTWB = (MixWetBulb + Constant::Kelvin) / Tref; - PltSizNum = - PlantUtilities::MyPlantSizingIndex(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - simpleWatertoAirHP.WaterInletNodeNum, - simpleWatertoAirHP.WaterOutletNodeNum, - ErrorsFound, - false); - if (PltSizNum > 0) { - DesignEntWaterTemp = state.dataSize->PlantSizData(PltSizNum).ExitTemp; - ratioTS = (DesignEntWaterTemp + Constant::Kelvin) / Tref; - } else { - ShowSevereError(state, "Autosizing of sensible cooling capacity requires a loop Sizing:Plant object"); - ShowContinueError(state, "Autosizing also requires physical connection to a plant or condenser loop."); - ShowContinueError(state, - EnergyPlus::format("Occurs in COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT Object={}", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)], - simpleWatertoAirHP.Name)); - ErrorsFound = true; - } - // calculate temperatue ratio at rated conditions - RatedratioTDB = (RatedMixDryBulb + Constant::Kelvin) / Tref; - RatedratioTWB = (RatedMixWetBulb + Constant::Kelvin) / Tref; - RatedratioTS = (simpleWatertoAirHP.RatedEntWaterTemp + Constant::Kelvin) / Tref; - // determine curve modifiers at peak and rated conditions - PeakSensCapTempModFac = simpleWatertoAirHP.SensCoolCapCurve->value(state, ratioTDB, ratioTWB, ratioTS, 1.0, 1.0); - RatedSensCapTempModFac = - simpleWatertoAirHP.SensCoolCapCurve->value(state, RatedratioTDB, RatedratioTWB, RatedratioTS, 1.0, 1.0); - // calculate the rated sensible capacity based on peak conditions - // note: the rated sensible capacity can be different than the sensible capacity - // at rated conditions if the capacity curve isn't normalized at the rated - // conditions - RatedCapCoolSensDes = (PeakSensCapTempModFac > 0.0) ? SensCapAtPeak / PeakSensCapTempModFac : SensCapAtPeak; + calcRatedSensCoolCap(state, + simpleWatertoAirHP, + CompType, + VolFlowRate, + MixTemp, + MixHumRat, + SupTemp, + state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace, + Tref, + FanCoolLoad, + MixWetBulb, + RatedMixWetBulb, + RatedMixDryBulb, + ratioTDB, + ratioTWB, + ratioTS, + RatedratioTDB, + RatedratioTWB, + RatedratioTS, + PeakSensCapTempModFac, + RatedSensCapTempModFac, + RatedCapCoolSensDes, + PltSizNum, + ErrorsFound); } else { RatedCapCoolSensDes = 0.0; } @@ -1830,17 +1960,13 @@ namespace WaterToAirHeatPumpSimple { HardSizeNoDesRun = true; if (simpleWatertoAirHP.RatedCapCoolSens > 0.0) { BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), + CompType, simpleWatertoAirHP.Name, "User-Specified Rated Sensible Cooling Capacity [W]", simpleWatertoAirHP.RatedCapCoolSens); } } else { - CheckZoneSizing(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name); + CheckZoneSizing(state, CompType, simpleWatertoAirHP.Name); if (CoolingAirVolFlowRateDes > 0.0) { VolFlowRate = CoolingAirVolFlowRateDes; } else { @@ -1871,65 +1997,30 @@ namespace WaterToAirHeatPumpSimple { } else { OutTemp = 0.0; } - rhoair = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, MixTemp, MixHumRat, RoutineName); - MixEnth = Psychrometrics::PsyHFnTdbW(MixTemp, MixHumRat); - SupEnth = Psychrometrics::PsyHFnTdbW(SupTemp, MixHumRat); - if (state.dataSize->DataFanType != HVAC::FanType::Invalid && state.dataSize->DataFanIndex > 0) { // add fan heat to coil load - FanCoolLoad = state.dataFans->fans(state.dataSize->DataFanIndex)->getDesignHeatGain(state, VolFlowRate); - - Real64 CpAir = Psychrometrics::PsyCpAirFnW(MixHumRat); - if (state.dataSize->DataFanPlacement == HVAC::FanPlace::BlowThru) { - MixTemp += FanCoolLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature entering the coil - } else { - SupTemp -= FanCoolLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature leaving the coil - } - } - // Sensible capacity is calculated from enthalpy difference with constant humidity ratio, i.e., - // there is only temperature difference between entering and leaving air enthalpy. Previously - // it was calculated using m.cp.dT - SensCapAtPeak = (rhoair * VolFlowRate * (MixEnth - SupEnth)) + - FanCoolLoad; // load on the cooling coil which includes ventilation load and fan heat (sensible) - SensCapAtPeak = max(0.0, SensCapAtPeak); - MixWetBulb = Psychrometrics::PsyTwbFnTdbWPb(state, MixTemp, MixHumRat, state.dataEnvrn->StdBaroPress, RoutineName); - RatedMixWetBulb = simpleWatertoAirHP.RatedEntAirWetbulbTemp; - RatedMixDryBulb = simpleWatertoAirHP.RatedEntAirDrybulbTemp; - // calculate temperature ratios at design day peak conditions - ratioTDB = (MixTemp + Constant::Kelvin) / Tref; - ratioTWB = (MixWetBulb + Constant::Kelvin) / Tref; - PltSizNum = - PlantUtilities::MyPlantSizingIndex(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - simpleWatertoAirHP.WaterInletNodeNum, - simpleWatertoAirHP.WaterOutletNodeNum, - ErrorsFound, - false); - if (PltSizNum > 0) { - DesignEntWaterTemp = state.dataSize->PlantSizData(PltSizNum).ExitTemp; - ratioTS = (DesignEntWaterTemp + Constant::Kelvin) / Tref; - } else { - ShowSevereError(state, "Autosizing of sensible cooling capacity requires a loop Sizing:Plant object"); - ShowContinueError(state, "Autosizing also requires physical connection to a plant or condenser loop."); - ShowContinueError(state, - EnergyPlus::format("Occurs in COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT Object={}", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)], - simpleWatertoAirHP.Name)); - ErrorsFound = true; - } - // calculate temperatue ratio at rated conditions - RatedratioTDB = (RatedMixDryBulb + Constant::Kelvin) / Tref; - RatedratioTWB = (RatedMixWetBulb + Constant::Kelvin) / Tref; - RatedratioTS = (simpleWatertoAirHP.RatedEntWaterTemp + Constant::Kelvin) / Tref; - PeakSensCapTempModFac = simpleWatertoAirHP.SensCoolCapCurve->value(state, ratioTDB, ratioTWB, ratioTS, 1.0, 1.0); - RatedSensCapTempModFac = - simpleWatertoAirHP.SensCoolCapCurve->value(state, RatedratioTDB, RatedratioTWB, RatedratioTS, 1.0, 1.0); - // Check curve output when rated mixed air wetbulb is the design mixed air wetbulb - // calculate the rated sensible capacity based on peak conditions - // note: the rated sensible capacity can be different than the sensible capacity - // at rated conditions if the capacity curve isn't normalized at the rated - // conditions - RatedCapCoolSensDes = (PeakSensCapTempModFac > 0.0) ? SensCapAtPeak / PeakSensCapTempModFac : SensCapAtPeak; + calcRatedSensCoolCap(state, + simpleWatertoAirHP, + CompType, + VolFlowRate, + MixTemp, + MixHumRat, + SupTemp, + state.dataSize->DataFanPlacement, + Tref, + FanCoolLoad, + MixWetBulb, + RatedMixWetBulb, + RatedMixDryBulb, + ratioTDB, + ratioTWB, + ratioTS, + RatedratioTDB, + RatedratioTWB, + RatedratioTS, + PeakSensCapTempModFac, + RatedSensCapTempModFac, + RatedCapCoolSensDes, + PltSizNum, + ErrorsFound); } else { RatedCapCoolSensDes = 0.0; } @@ -2019,8 +2110,7 @@ namespace WaterToAirHeatPumpSimple { simpleWatertoAirHP.RatedPowerCool = simpleWatertoAirHP.RatedPowerCoolAtRatedCdts / RatedCoolPowerTempModFac; if (simpleWatertoAirHP.RatedCapCoolTotal != DataSizing::AutoSize) { BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), + CompType, simpleWatertoAirHP.Name, "Design Size Rated Total Cooling Capacity [W]", simpleWatertoAirHP.RatedCapCoolTotal); @@ -2036,42 +2126,13 @@ namespace WaterToAirHeatPumpSimple { RatedCapCoolTotalUser = simpleWatertoAirHP.RatedCapCoolTotal; state.dataSize->DXCoolCap = simpleWatertoAirHP.RatedCapCoolTotal; simpleWatertoAirHP.RatedPowerCool = simpleWatertoAirHP.RatedCapCoolTotal / simpleWatertoAirHP.RatedCOPCoolAtRatedCdts; - if ((std::abs(RatedCapCoolTotalDes - RatedCapCoolTotalUser) / RatedCapCoolTotalUser) > - state.dataSize->AutoVsHardSizingThreshold) { - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "Design Size Rated Total Cooling Capacity [W]", - RatedCapCoolTotalDes, - "User-Specified Rated Total Cooling Capacity [W]", - RatedCapCoolTotalUser); - } else { - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "User-Specified Rated Total Cooling Capacity [W]", - RatedCapCoolTotalUser); - } - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(RatedCapCoolTotalDes - RatedCapCoolTotalUser) / RatedCapCoolTotalUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage( - state, - EnergyPlus::format( - "SizeHVACWaterToAir: Potential issue with equipment sizing for coil {}:WATERTOAIRHEATPUMP:EQUATIONFIT {}", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)], - simpleWatertoAirHP.Name)); - ShowContinueError( - state, EnergyPlus::format("User-Specified Rated Total Cooling Capacity of {:.2R} [W]", RatedCapCoolTotalUser)); - ShowContinueError( - state, - EnergyPlus::format("differs from Design Size Rated Total Cooling Capacity of {:.2R} [W]", RatedCapCoolTotalDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + reportSizingComparison(state, + CompType, + simpleWatertoAirHP.Name, + "Design Size Rated Total Cooling Capacity [W]", + "User-Specified Rated Total Cooling Capacity [W]", + RatedCapCoolTotalDes, + RatedCapCoolTotalUser); } } } else { @@ -2134,52 +2195,19 @@ namespace WaterToAirHeatPumpSimple { simpleWatertoAirHP.RatedCapCoolSens = RatedCapCoolSensDes; simpleWatertoAirHP.RatedCapCoolSensDesAtRatedCdts = RatedCapCoolSensDes * RatedSensCapTempModFac; if (simpleWatertoAirHP.RatedCapCoolTotal != DataSizing::AutoSize) { - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "Design Size Rated Sensible Cooling Capacity [W]", - RatedCapCoolSensDes); + BaseSizer::reportSizerOutput( + state, CompType, simpleWatertoAirHP.Name, "Design Size Rated Sensible Cooling Capacity [W]", RatedCapCoolSensDes); } } else { if (simpleWatertoAirHP.RatedCapCoolSens > 0.0 && RatedCapCoolSensDes > 0.0) { RatedCapCoolSensUser = simpleWatertoAirHP.RatedCapCoolSens; - if ((std::abs(RatedCapCoolSensDes - RatedCapCoolSensUser) / RatedCapCoolSensUser) > - state.dataSize->AutoVsHardSizingThreshold) { - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "Design Size Rated Sensible Cooling Capacity [W]", - RatedCapCoolSensDes, - "User-Specified Rated Sensible Cooling Capacity [W]", - RatedCapCoolSensUser); - } else { - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "User-Specified Rated Sensible Cooling Capacity [W]", - RatedCapCoolSensUser); - } - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(RatedCapCoolSensDes - RatedCapCoolSensUser) / RatedCapCoolSensUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage( - state, - EnergyPlus::format( - "SizeHVACWaterToAir: Potential issue with equipment sizing for coil {}:WATERTOAIRHEATPUMP:EQUATIONFIT {}", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)], - simpleWatertoAirHP.Name)); - ShowContinueError( - state, EnergyPlus::format("User-Specified Rated Sensible Cooling Capacity of {:.2R} [W]", RatedCapCoolSensUser)); - ShowContinueError(state, - EnergyPlus::format("differs from Design Size Rated Sensible Cooling Capacity of {:.2R} [W]", - RatedCapCoolSensDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + reportSizingComparison(state, + CompType, + simpleWatertoAirHP.Name, + "Design Size Rated Sensible Cooling Capacity [W]", + "User-Specified Rated Sensible Cooling Capacity [W]", + RatedCapCoolSensDes, + RatedCapCoolSensUser); } } } @@ -2219,38 +2247,19 @@ namespace WaterToAirHeatPumpSimple { ShowContinueError(state, EnergyPlus::format("Rated Total Cooling Capacity at Rated Conditions = {:.2T} W", simpleWatertoAirHP.RatedCapCoolAtRatedCdts)); - ShowContinueError(state, "See eio file for further details."); - ShowContinueError(state, "Check Total and Sensible Cooling Capacity coefficients in curves to ensure they are accurate."); - ShowContinueError(state, "Check Zone and System Sizing objects to verify sizing inputs."); - ShowContinueError(state, "Sizing statistics:"); - ShowContinueError(state, EnergyPlus::format("Rated entering Air Wet-Bulb Temperature = {:.3T} C", RatedMixWetBulb)); - ShowContinueError(state, EnergyPlus::format("Peak entering Air Wet-Bulb Temperature = {:.3T} C", MixWetBulb)); - ShowContinueError(state, EnergyPlus::format("Entering Water Temperature used = {:.3T} C", simpleWatertoAirHP.RatedEntWaterTemp)); - ShowContinueError(state, "Design air and water flow rates = 1.0"); - ShowContinueError( - state, - EnergyPlus::format("Rated ratio of load-side air wet-bulb temperature to 283.15 C (Rated ratioTWB) = {:.3T}", RatedratioTWB)); - ShowContinueError( - state, - EnergyPlus::format("Rated ratio of source-side inlet water temperature to 283.15 C (Rated ratioTS) = {:.3T}", RatedratioTS)); - ShowContinueError( - state, EnergyPlus::format("Peak ratio of load-side air wet-bulb temperature to 283.15 C (Peak ratioTWB) = {:.3T}", ratioTWB)); - ShowContinueError( - state, EnergyPlus::format("Peak ratio of source-side inlet water temperature to 283.15 C (Peak ratioTS) = {:.3T}", ratioTS)); - ShowContinueError(state, EnergyPlus::format("Rated Total Cooling Capacity Modifier = {:.5T}", RatedTotCapTempModFac)); - ShowContinueError(state, EnergyPlus::format("Peak Design Total Cooling Capacity Modifier = {:.5T}", PeakTotCapTempModFac)); - ShowContinueError(state, EnergyPlus::format("Rated Sensible Cooling Capacity Modifier = {:.5T}", RatedSensCapTempModFac)); - ShowContinueError(state, EnergyPlus::format("Peak Design Sensible Cooling Capacity Modifier = {:.5T}", PeakSensCapTempModFac)); - ShowContinueError(state, - "...Rated Total Cooling Capacity at Rated Conditions = Total Peak Design Load * Rated Total " - "Cooling Capacity Modifier / " - "Peak Design Total Cooling Capacity Modifier"); - ShowContinueError(state, - "...Rated Sensible Cooling Capacity at Rated Conditions = Peak Design Sensible Load * Rated " - "Sensible Cooling " - "Capacity Modifier / Peak Design Sensible Cooling Capacity Modifier"); - ShowContinueError(state, "Carefully review the Load Side Total, Sensible, and Latent heat transfer rates"); - ShowContinueError(state, "... to ensure they meet the expected manufacturers performance specifications."); + showCapacitySizingStats(state, + RatedMixWetBulb, + MixWetBulb, + simpleWatertoAirHP.RatedEntWaterTemp, + RatedratioTWB, + RatedratioTS, + ratioTWB, + ratioTS, + RatedTotCapTempModFac, + PeakTotCapTempModFac, + "Sizing statistics:", + RatedSensCapTempModFac, + PeakSensCapTempModFac); } } else if (RatedCapCoolTotalAutoSized) { if (simpleWatertoAirHP.RatedCapCoolSensDesAtRatedCdts > simpleWatertoAirHP.RatedCapCoolAtRatedCdts) { @@ -2264,36 +2273,17 @@ namespace WaterToAirHeatPumpSimple { state, EnergyPlus::format("Rated Sensible Cooling Capacity = {:.2T} W", simpleWatertoAirHP.RatedCapCoolSensDesAtRatedCdts)); ShowContinueError(state, EnergyPlus::format("Rated Total Cooling Capacity = {:.2T} W", simpleWatertoAirHP.RatedCapCoolAtRatedCdts)); - ShowContinueError(state, "See eio file for further details."); - ShowContinueError(state, "Check Total and Sensible Cooling Capacity coefficients in curves to ensure they are accurate."); - ShowContinueError(state, "Check Zone and System Sizing objects to verify sizing inputs."); - ShowContinueError(state, "Sizing statistics for Total Cooling Capacity:"); - ShowContinueError(state, EnergyPlus::format("Rated entering Air Wet-Bulb Temperature = {:.3T} C", RatedMixWetBulb)); - ShowContinueError(state, EnergyPlus::format("Peak entering Air Wet-Bulb Temperature = {:.3T} C", MixWetBulb)); - ShowContinueError(state, EnergyPlus::format("Entering Water Temperature used = {:.3T} C", simpleWatertoAirHP.RatedEntWaterTemp)); - ShowContinueError(state, "Design air and water flow rates = 1.0"); - ShowContinueError( - state, - EnergyPlus::format("Rated ratio of load-side air wet-bulb temperature to 283.15 C (Rated ratioTWB) = {:.3T}", RatedratioTWB)); - ShowContinueError( - state, - EnergyPlus::format("Rated ratio of source-side inlet water temperature to 283.15 C (Rated ratioTS) = {:.3T}", RatedratioTS)); - ShowContinueError( - state, EnergyPlus::format("Peak ratio of load-side air wet-bulb temperature to 283.15 C (Peak ratioTWB) = {:.3T}", ratioTWB)); - ShowContinueError( - state, EnergyPlus::format("Peak ratio of source-side inlet water temperature to 283.15 C (Peak ratioTS) = {:.3T}", ratioTS)); - ShowContinueError(state, EnergyPlus::format("Rated Total Cooling Capacity Modifier = {:.5T}", RatedTotCapTempModFac)); - ShowContinueError(state, EnergyPlus::format("Peak Design Total Cooling Capacity Modifier = {:.5T}", PeakTotCapTempModFac)); - ShowContinueError(state, - "...Rated Total Cooling Capacity at Rated Conditions = Total Peak Design Load * Rated Total " - "Cooling Capacity Modifier / " - "Peak Design Total Cooling Capacity Modifier"); - ShowContinueError(state, - "...Rated Sensible Cooling Capacity at Rated Conditions = Peak Design Sensible Load * Rated " - "Sensible Cooling " - "Capacity Modifier / Peak Design Sensible Cooling Capacity Modifier"); - ShowContinueError(state, "Carefully review the Load Side Total, Sensible, and Latent heat transfer rates"); - ShowContinueError(state, "... to ensure they meet the expected manufacturers performance specifications."); + showCapacitySizingStats(state, + RatedMixWetBulb, + MixWetBulb, + simpleWatertoAirHP.RatedEntWaterTemp, + RatedratioTWB, + RatedratioTS, + ratioTWB, + ratioTS, + RatedTotCapTempModFac, + PeakTotCapTempModFac, + "Sizing statistics for Total Cooling Capacity:"); } } @@ -2310,10 +2300,7 @@ namespace WaterToAirHeatPumpSimple { } if (IsAutoSize) { if (state.dataSize->CurSysNum > 0) { - CheckSysSizing(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name); + CheckSysSizing(state, CompType, simpleWatertoAirHP.Name); if (HeatingAirVolFlowRateDes > 0.0) { VolFlowRate = HeatingAirVolFlowRateDes; } else { @@ -2359,82 +2346,33 @@ namespace WaterToAirHeatPumpSimple { // determine the coil ratio of coil dT with system air flow to design heating air flow HeatdTratio = (HeatSupTemp - HeatMixTempSys) / (HeatSupTemp - HeatMixTemp); } - rhoair = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, HeatMixTemp, HeatMixHumRat, RoutineName); - HeatCapAtPeak = rhoair * VolFlowRate * Psychrometrics::PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * - (HeatSupTemp - HeatMixTemp); // heating coil load - if (state.dataSize->DataFanType != HVAC::FanType::Invalid && - state.dataSize->DataFanIndex > 0) { // remove fan heat to coil load - FanHeatLoad = state.dataFans->fans(state.dataSize->DataFanIndex)->getDesignHeatGain(state, VolFlowRate); - - Real64 CpAir = Psychrometrics::PsyCpAirFnW(HeatMixHumRat); - if (state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace == HVAC::FanPlace::BlowThru) { - HeatMixTemp += FanHeatLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature entering the coil - } else if (state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace == - HVAC::FanPlace::DrawThru) { - HeatSupTemp -= FanHeatLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature leaving the coil - } - } - HeatCapAtPeak -= FanHeatLoad; // remove fan heat from heating coil load - HeatCapAtPeak = max(0.0, HeatCapAtPeak); - RatedHeatMixDryBulb = simpleWatertoAirHP.RatedEntAirDrybulbTemp; - // calculate temperatue ratio at design day peak conditions - HeatratioTDB = (HeatMixTemp + Constant::Kelvin) / Tref; - PltSizNum = - PlantUtilities::MyPlantSizingIndex(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - simpleWatertoAirHP.WaterInletNodeNum, - simpleWatertoAirHP.WaterOutletNodeNum, - ErrorsFound, - false); - if (PltSizNum > 0) { - DesignEntWaterTemp = state.dataSize->PlantSizData(PltSizNum).ExitTemp; - HeatratioTS = (DesignEntWaterTemp + Constant::Kelvin) / Tref; - } else { - ShowSevereError(state, "Autosizing of heating capacity requires a loop Sizing:Plant object"); - ShowContinueError(state, "Autosizing also requires physical connection to a plant or condenser loop."); - ShowContinueError(state, - EnergyPlus::format("Occurs in COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT Object={}", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)], - simpleWatertoAirHP.Name)); - HeatratioTS = 0.0; // Clang complains it is used uninitialized if you don't give it a value - ErrorsFound = true; - } - - // calculate temperatue ratio at refrence conditions - RatedHeatratioTDB = (RatedHeatMixDryBulb + Constant::Kelvin) / Tref; - RatedHeatratioTS = (simpleWatertoAirHP.RatedEntWaterTemp + Constant::Kelvin) / Tref; - - // determine curve modifiers at peak and rated conditions - PeakHeatCapTempModFac = simpleWatertoAirHP.HeatCapCurve->value(state, HeatratioTDB, HeatratioTS, 1.0, 1.0); - RatedHeatCapTempModFac = simpleWatertoAirHP.HeatCapCurve->value(state, RatedHeatratioTDB, RatedHeatratioTS, 1.0, 1.0); - // Check curve output when rated mixed air wetbulb is the design mixed air wetbulb - if (RatedHeatMixDryBulb == HeatMixTemp) { - if (RatedHeatCapTempModFac > 1.02 || RatedHeatCapTempModFac < 0.98) { - ShowWarningError( - state, - EnergyPlus::format("{} Coil:Heating:WaterToAirHeatPump:EquationFit={}", RoutineName, simpleWatertoAirHP.Name)); - ShowContinueError(state, - "Heating capacity as a function of temperature curve output is not equal to 1.0 (+ or - 2%) " - "at rated conditions."); - ShowContinueError(state, EnergyPlus::format("Curve output at rated conditions = {:.3T}", RatedHeatCapTempModFac)); - } - } - // calculate the rated capacity based on peak conditions - // note: the rated capacity can be different than the capacity at - // rated conditions if the capacity curve isn't normalized at the - // rated conditions - RatedCapHeatDes = (PeakHeatCapTempModFac > 0.0) ? HeatCapAtPeak / PeakHeatCapTempModFac : HeatCapAtPeak; + calcRatedHeatCap(state, + simpleWatertoAirHP, + CompType, + VolFlowRate, + HeatMixTemp, + HeatMixHumRat, + HeatSupTemp, + state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace, + Tref, + FanHeatLoad, + RatedHeatMixDryBulb, + HeatratioTDB, + HeatratioTS, + RatedHeatratioTDB, + RatedHeatratioTS, + PeakHeatCapTempModFac, + RatedHeatCapTempModFac, + RatedHeatPowerTempModFac, + RatedCapHeatDes, + PltSizNum, + ErrorsFound); } else { RatedCapHeatDes = 0.0; RatedHeatratioTS = 0.0; // Clang complains it is used uninitialized if you don't give it a value } } else if (state.dataSize->CurZoneEqNum > 0) { - CheckZoneSizing(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name); + CheckZoneSizing(state, CompType, simpleWatertoAirHP.Name); if (HeatingAirVolFlowRateDes > 0.0) { VolFlowRate = HeatingAirVolFlowRateDes; } else { @@ -2469,81 +2407,27 @@ namespace WaterToAirHeatPumpSimple { HeatSupTemp = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).HeatDesTemp; // determine the coil ratio of coil dT with system air flow to design heating air flow HeatdTratio = (HeatSupTemp - HeatMixTempSys) / (HeatSupTemp - HeatMixTemp); - rhoair = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, HeatMixTemp, HeatMixHumRat, RoutineName); - HeatCapAtPeak = rhoair * VolFlowRate * Psychrometrics::PsyCpAirFnW(DataPrecisionGlobals::constant_zero) * - (HeatSupTemp - HeatMixTemp); // heating coil load - if (state.dataSize->DataFanType != HVAC::FanType::Invalid && state.dataSize->DataFanIndex > 0) { // add fan heat to coil load - FanHeatLoad = state.dataFans->fans(state.dataSize->DataFanIndex)->getDesignHeatGain(state, VolFlowRate); - - Real64 CpAir = Psychrometrics::PsyCpAirFnW(HeatMixHumRat); - if (state.dataSize->DataFanPlacement == HVAC::FanPlace::BlowThru) { - HeatMixTemp += FanHeatLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature entering the coil - } else { - HeatSupTemp -= FanHeatLoad / (CpAir * rhoair * VolFlowRate); // this is now the temperature leaving the coil - } - } - HeatCapAtPeak -= FanHeatLoad; // remove fan heat from heating coil load - HeatCapAtPeak = max(0.0, HeatCapAtPeak); - RatedHeatMixDryBulb = simpleWatertoAirHP.RatedEntAirDrybulbTemp; - // calculate temperatue ratio at design day peak conditions - HeatratioTDB = (HeatMixTemp + Constant::Kelvin) / Tref; - PltSizNum = - PlantUtilities::MyPlantSizingIndex(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - simpleWatertoAirHP.WaterInletNodeNum, - simpleWatertoAirHP.WaterOutletNodeNum, - ErrorsFound, - false); - if (PltSizNum > 0) { - DesignEntWaterTemp = state.dataSize->PlantSizData(PltSizNum).ExitTemp; - HeatratioTS = (DesignEntWaterTemp + Constant::Kelvin) / Tref; - } else { - ShowSevereError(state, "Autosizing of heating capacity requires a loop Sizing:Plant object"); - ShowContinueError(state, "Autosizing also requires physical connection to a plant or condenser loop."); - ShowContinueError(state, - EnergyPlus::format("Occurs in COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT Object={}", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)], - simpleWatertoAirHP.Name)); - HeatratioTS = 0.0; // Clang complains it is used uninitialized if you don't give it a value - ErrorsFound = true; - } - - // calculate temperatue ratio at refrence conditions - RatedHeatratioTDB = (RatedHeatMixDryBulb + Constant::Kelvin) / Tref; - RatedHeatratioTS = (simpleWatertoAirHP.RatedEntWaterTemp + Constant::Kelvin) / Tref; - - // determine curve modifiers at peak and rated conditions - PeakHeatCapTempModFac = simpleWatertoAirHP.HeatCapCurve->value(state, HeatratioTDB, HeatratioTS, 1.0, 1.0); - RatedHeatCapTempModFac = simpleWatertoAirHP.HeatCapCurve->value(state, RatedHeatratioTDB, RatedHeatratioTS, 1.0, 1.0); - RatedHeatPowerTempModFac = simpleWatertoAirHP.HeatPowCurve->value(state, RatedHeatratioTDB, RatedHeatratioTS, 1.0, 1.0); - // Check curve output when rated mixed air wetbulb is the design mixed air wetbulb - if (RatedHeatMixDryBulb == HeatMixTemp) { - if (RatedHeatCapTempModFac > 1.02 || RatedHeatCapTempModFac < 0.98) { - ShowWarningError( - state, - EnergyPlus::format("{} Coil:Heating:WaterToAirHeatPump:EquationFit={}", RoutineName, simpleWatertoAirHP.Name)); - ShowContinueError(state, - "Heating capacity as a function of temperature curve output is not equal to 1.0 (+ or - 2%) " - "at rated conditions."); - ShowContinueError(state, EnergyPlus::format("Curve output at rated conditions = {:.3T}", RatedHeatCapTempModFac)); - } - if (RatedHeatPowerTempModFac > 1.02 || RatedHeatPowerTempModFac < 0.98) { - ShowWarningError( - state, - EnergyPlus::format("{} Coil:Heating:WaterToAirHeatPump:EquationFit={}", RoutineName, simpleWatertoAirHP.Name)); - ShowContinueError(state, - "Heating power consumption as a function of temperature curve output is not equal to " - "1.0 (+ or - 2%) at rated conditions."); - ShowContinueError(state, EnergyPlus::format("Curve output at rated conditions = {:.3T}", RatedHeatPowerTempModFac)); - } - } - // calculate the rated capacity based on peak conditions - // note: the rated capacity can be different than the capacity at - // rated conditions if the capacity curve isn't normalized at the - // rated conditions - RatedCapHeatDes = (PeakHeatCapTempModFac > 0.0) ? HeatCapAtPeak / PeakHeatCapTempModFac : HeatCapAtPeak; + calcRatedHeatCap(state, + simpleWatertoAirHP, + CompType, + VolFlowRate, + HeatMixTemp, + HeatMixHumRat, + HeatSupTemp, + state.dataSize->DataFanPlacement, + Tref, + FanHeatLoad, + RatedHeatMixDryBulb, + HeatratioTDB, + HeatratioTS, + RatedHeatratioTDB, + RatedHeatratioTS, + PeakHeatCapTempModFac, + RatedHeatCapTempModFac, + RatedHeatPowerTempModFac, + RatedCapHeatDes, + PltSizNum, + ErrorsFound); } else { RatedHeatratioTS = 0.0; // Clang complains it is used uninitialized if you don't give it a value RatedCapHeatDes = 0.0; @@ -2660,11 +2544,7 @@ namespace WaterToAirHeatPumpSimple { OutputReportPredefined::PreDefTableEntry( state, state.dataOutRptPredefined->pdchWAHPRatedWtrT, simpleWatertoAirHP.Name, simpleWatertoAirHP.RatedEntWaterTemp); BaseSizer::reportSizerOutput( - state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "Design Size Rated Heating Capacity [W]", - simpleWatertoAirHP.RatedCapHeat); + state, CompType, simpleWatertoAirHP.Name, "Design Size Rated Heating Capacity [W]", simpleWatertoAirHP.RatedCapHeat); OutputReportPredefined::PreDefTableEntry( state, state.dataOutRptPredefined->pdchHeatCoilNomCap, simpleWatertoAirHP.Name, simpleWatertoAirHP.RatedCapHeat); if (simpleWatertoAirHP.RatedCapHeat != 0.0) { @@ -2678,46 +2558,18 @@ namespace WaterToAirHeatPumpSimple { } else { if (simpleWatertoAirHP.RatedCapHeat > 0.0 && RatedCapHeatDes > 0.0 && !HardSizeNoDesRun) { RatedCapHeatUser = simpleWatertoAirHP.RatedCapHeat; - if ((std::abs(RatedCapHeatDes - RatedCapHeatUser) / RatedCapHeatUser) > state.dataSize->AutoVsHardSizingThreshold) { - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "Design Size Rated Heating Capacity [W]", - RatedCapHeatDes, - "User-Specified Rated Heating Capacity [W]", - RatedCapHeatUser); - } else { - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "User-Specified Rated Heating Capacity [W]", - RatedCapHeatUser); - } - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(RatedCapHeatDes - RatedCapHeatUser) / RatedCapHeatUser) > state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format( - "SizeHVACWaterToAir: Potential issue with equipment sizing for coil {}:WATERTOAIRHEATPUMP:EQUATIONFIT {}", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)], - simpleWatertoAirHP.Name)); - ShowContinueError(state, EnergyPlus::format("User-Specified Rated Heating Capacity of {:.2R} [W]", RatedCapHeatUser)); - ShowContinueError(state, - EnergyPlus::format("differs from Design Size Rated Heating Capacity of {:.2R} [W]", RatedCapHeatDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + reportSizingComparison(state, + CompType, + simpleWatertoAirHP.Name, + "Design Size Rated Heating Capacity [W]", + "User-Specified Rated Heating Capacity [W]", + RatedCapHeatDes, + RatedCapHeatUser); } else { if (simpleWatertoAirHP.RatedCapHeat > 0.0) { RatedCapHeatUser = simpleWatertoAirHP.RatedCapHeat; - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "User-Specified Rated Heating Capacity [W]", - RatedCapHeatUser); + BaseSizer::reportSizerOutput( + state, CompType, simpleWatertoAirHP.Name, "User-Specified Rated Heating Capacity [W]", RatedCapHeatUser); } } @@ -2749,19 +2601,18 @@ namespace WaterToAirHeatPumpSimple { } } - state.dataRptCoilSelection->coilSelectionReportObj->setCoilHeatingCapacity( - state, - simpleWatertoAirHP.Name, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - RatedCapHeatDes, - IsAutoSize, - state.dataSize->CurSysNum, - state.dataSize->CurZoneEqNum, - state.dataSize->CurOASysNum, - FanCoolLoad, - 1.0, // RatedHeatCapTempModFac, - -999.0, - -999.0); + state.dataRptCoilSelection->coilSelectionReportObj->setCoilHeatingCapacity(state, + simpleWatertoAirHP.Name, + CompType, + RatedCapHeatDes, + IsAutoSize, + state.dataSize->CurSysNum, + state.dataSize->CurZoneEqNum, + state.dataSize->CurOASysNum, + FanCoolLoad, + 1.0, // RatedHeatCapTempModFac, + -999.0, + -999.0); } // Heating @@ -2843,14 +2694,13 @@ namespace WaterToAirHeatPumpSimple { // WSHP condenser can be on either a plant loop or condenser loop. Test each to find plant sizing number. // first check to see if coil is connected to a plant loop, no warning on this CALL if (IsAutoSize) { - PltSizNum = PlantUtilities::MyPlantSizingIndex( - state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - simpleWatertoAirHP.WaterInletNodeNum, - simpleWatertoAirHP.WaterOutletNodeNum, - ErrorsFound, - false); + PltSizNum = PlantUtilities::MyPlantSizingIndex(state, + CompType, + simpleWatertoAirHP.Name, + simpleWatertoAirHP.WaterInletNodeNum, + simpleWatertoAirHP.WaterOutletNodeNum, + ErrorsFound, + false); if (PltSizNum > 0) { rho = simpleWatertoAirHP.plantLoc.loop->glycol->getDensity(state, state.dataSize->PlantSizData(PltSizNum).ExitTemp, RoutineNameAlt); @@ -2911,11 +2761,7 @@ namespace WaterToAirHeatPumpSimple { if (SystemCapacity != DataSizing::AutoSize) { simpleWatertoAirHP.RatedWaterVolFlowRate = RatedWaterVolFlowRateDes; BaseSizer::reportSizerOutput( - state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "Design Size Rated Water Flow Rate [m3/s]", - RatedWaterVolFlowRateDes); + state, CompType, simpleWatertoAirHP.Name, "Design Size Rated Water Flow Rate [m3/s]", RatedWaterVolFlowRateDes); if (simpleWatertoAirHP.WAHPType == WatertoAirHP::Heating && simpleWatertoAirHP.CompanionCoolingCoilNum > 0) { auto &companionCoolingCoil(state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(simpleWatertoAirHP.CompanionCoolingCoilNum)); companionCoolingCoil.RatedWaterVolFlowRate = RatedWaterVolFlowRateDes; @@ -2939,40 +2785,13 @@ namespace WaterToAirHeatPumpSimple { } else { if (simpleWatertoAirHP.RatedWaterVolFlowRate > 0.0 && RatedWaterVolFlowRateDes > 0.0) { RatedWaterVolFlowRateUser = simpleWatertoAirHP.RatedWaterVolFlowRate; - if ((std::abs(RatedWaterVolFlowRateDes - RatedWaterVolFlowRateUser) / RatedWaterVolFlowRateUser) > - state.dataSize->AutoVsHardSizingThreshold) { - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "Design Size Rated Water Flow Rate [m3/s]", - RatedWaterVolFlowRateDes, - "User-Specified Rated Water Flow Rate [m3/s]", - RatedWaterVolFlowRateUser); - } else { - BaseSizer::reportSizerOutput(state, - EnergyPlus::format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", - WatertoAirHPNamesUC[static_cast(simpleWatertoAirHP.WAHPType)]), - simpleWatertoAirHP.Name, - "User-Specified Rated Water Flow Rate [m3/s]", - RatedWaterVolFlowRateUser); - } - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(RatedWaterVolFlowRateDes - RatedWaterVolFlowRateUser) / RatedWaterVolFlowRateUser) > - state.dataSize->AutoVsHardSizingThreshold) { - ShowMessage(state, - EnergyPlus::format( - "SizeHVACWaterToAir: Potential issue with equipment sizing for coil {}:WATERTOAIRHEATPUMP:EQUATIONFIT {}", - simpleWatertoAirHP.WAHPType, - simpleWatertoAirHP.Name)); - ShowContinueError(state, - EnergyPlus::format("User-Specified Rated Water Flow Rate of {:.5R} [m3/s]", RatedWaterVolFlowRateUser)); - ShowContinueError( - state, EnergyPlus::format("differs from Design Size Rated Water Flow Rate of {:.5R} [m3/s]", RatedWaterVolFlowRateDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } + reportSizingComparison(state, + CompType, + simpleWatertoAirHP.Name, + "Design Size Rated Water Flow Rate [m3/s]", + "User-Specified Rated Water Flow Rate [m3/s]", + RatedWaterVolFlowRateDes, + RatedWaterVolFlowRateUser); } } diff --git a/src/EnergyPlus/WindowManager.cc b/src/EnergyPlus/WindowManager.cc index b90f0b6cb7d..d49665426d5 100644 --- a/src/EnergyPlus/WindowManager.cc +++ b/src/EnergyPlus/WindowManager.cc @@ -150,6 +150,35 @@ namespace Window { } } + // Convert glass spectral data to average properties and warn when between-glass shading is present. + // Called for both spectral-data and spectral-and-angle glass layers that have the BGFlag set. + static void convertGlassToBGSpectralAverage(EnergyPlusData &state, + Material::MaterialGlass *matGlass, + std::string const &constrName, + std::string const &dataDescription, + std::array const &tData, + std::array const &rffData, + std::array const &rbbData) + { + ShowWarningError(state, + EnergyPlus::format("Window glazing material \"{}\" was defined with full {} and has been converted to average spectral data", + matGlass->Name, + dataDescription)); + ShowContinueError(state, + EnergyPlus::format("due to its use with between-glass shades or blinds of the window construction \"{}\".", constrName)); + ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage."); + ShowContinueError(state, "If this material is also used in other window constructions without between-glass shades or blinds,"); + ShowContinueError(state, + "then make a duplicate material (with new name) if you want to model those windows (and reference the new " + "material) using the full spectral data."); + matGlass->Trans = solarSpectrumAverage(state, tData); + matGlass->TransVis = visibleSpectrumAverage(state, tData); + matGlass->ReflectSolBeamFront = solarSpectrumAverage(state, rffData); + matGlass->ReflectSolBeamBack = solarSpectrumAverage(state, rbbData); + matGlass->ReflectVisBeamFront = visibleSpectrumAverage(state, rffData); + matGlass->ReflectVisBeamBack = visibleSpectrumAverage(state, rbbData); + } + void InitGlassOpticalCalculations(EnergyPlusData &state) { @@ -561,30 +590,8 @@ namespace Window { // If there is spectral data for between-glass shades or blinds, calc the average spectral properties for use. if (wm->BGFlag) { - // Add warning message for the glazing defined with full spectral data. - ShowWarningError( - state, - EnergyPlus::format( - "Window glazing material \"{}\" was defined with full spectral data and has been converted to average spectral data", - matGlass->Name)); - ShowContinueError(state, - EnergyPlus::format("due to its use with between-glass shades or blinds of the window construction \"{}\".", - thisConstruct.Name)); - ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage."); - ShowContinueError(state, - "If this material is also used in other window constructions without between-glass shades or blinds,"); - ShowContinueError(state, - "then make a duplicate material (with new name) if you want to model those windows (and reference the new " - "material) using the full spectral data."); - - // set this material to average spectral data + convertGlassToBGSpectralAverage(state, matGlass, thisConstruct.Name, "spectral data", t[0], rff[0], rbb[0]); matGlass->GlassSpectralDataPtr = 0; - matGlass->Trans = solarSpectrumAverage(state, t[0]); - matGlass->TransVis = visibleSpectrumAverage(state, t[0]); - matGlass->ReflectSolBeamFront = solarSpectrumAverage(state, rff[0]); - matGlass->ReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]); - matGlass->ReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]); - matGlass->ReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]); SpecDataNum = 0; } } @@ -614,24 +621,6 @@ namespace Window { numptDAT = wm->wle.size(); numpt[iGlass] = numptDAT; if (wm->BGFlag) { - // 5/16/2012 CR 8793. Add warning message for the glazing defined with full spectral data. - ShowWarningError( - state, - EnergyPlus::format("Window glazing material \"{}\" was defined with full spectral and angular data and has been " - "converted to average spectral data", - matGlass->Name)); - ShowContinueError(state, - EnergyPlus::format("due to its use with between-glass shades or blinds of the window construction \"{}\".", - thisConstruct.Name)); - ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage."); - ShowContinueError(state, - "If this material is also used in other window constructions without between-glass shades or blinds,"); - ShowContinueError(state, - "then make a duplicate material (with new name) if you want to model those windows (and reference the new " - "material) using the full spectral data."); - // calc Trans, TransVis, ReflectSolBeamFront, ReflectSolBeamBack, ReflectVisBeamFront, ReflectVisBeamBack - // assuming wlt same as wle - for (int iLam = 0; iLam < nume; ++iLam) { Real64 lam = wm->wle[iLam]; wlt[iGlass][iLam] = lam; @@ -639,15 +628,8 @@ namespace Window { rff[iGlass][iLam] = matGlass->GlassSpecAngFReflCurve->value(state, 0.0, lam); rbb[iGlass][iLam] = matGlass->GlassSpecAngBReflCurve->value(state, 0.0, lam); } - - // set this material to average spectral data + convertGlassToBGSpectralAverage(state, matGlass, thisConstruct.Name, "spectral and angular data", t[0], rff[0], rbb[0]); matGlass->windowOpticalData = Window::OpticalDataModel::SpectralAverage; - matGlass->Trans = solarSpectrumAverage(state, t[0]); - matGlass->TransVis = visibleSpectrumAverage(state, t[0]); - matGlass->ReflectSolBeamFront = solarSpectrumAverage(state, rff[0]); - matGlass->ReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]); - matGlass->ReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]); - matGlass->ReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]); SpecDataNum = 0; } } @@ -966,7 +948,8 @@ namespace Window { Real64 const tsolDiff_2(pow_2(tsolDiff)); Real64 const tvisDiff_2(pow_2(tvisDiff)); - if (IntShade) { + // Extract shade material properties common to IntShade, ExtShade, and BGShade + if (ShadeOn) { auto const *matSh = dynamic_cast(s_mat->materials(constr.LayerPoint(ShadeLayNum))); assert(matSh != nullptr); ShadeAbs = matSh->AbsorpSolar; @@ -979,7 +962,41 @@ namespace Window { tsh = ShadeTrans; tshv = ShadeTransVis; ash = ShadeAbs; + } + + // Load between-glass diffuse properties common to BGShade and BGBlind + if (wm->BGFlag) { + tsh2 = pow_2(tsh); + tshv2 = pow_2(tshv); + td1 = constr.tBareSolDiff(1); + td2 = constr.tBareSolDiff(2); + td1v = constr.tBareVisDiff(1); + td2v = constr.tBareVisDiff(2); + afd1 = constr.afBareSolDiff(1); + afd2 = constr.afBareSolDiff(2); + abd1 = constr.abBareSolDiff(1); + abd2 = constr.abBareSolDiff(2); + rb1 = constr.rbBareSolDiff(1); + rb2 = constr.rbBareSolDiff(2); + rb1v = constr.rbBareVisDiff(1); + rb2v = constr.rbBareVisDiff(2); + rf1 = constr.rfBareSolDiff(1); + rf2 = constr.rfBareSolDiff(2); + rf1v = constr.rfBareVisDiff(1); + rf2v = constr.rfBareVisDiff(2); + if (NGlass == 3) { + td3 = constr.tBareSolDiff(3); + td3v = constr.tBareVisDiff(3); + afd3 = constr.afBareSolDiff(3); + abd3 = constr.abBareSolDiff(3); + rb3 = constr.rbBareSolDiff(3); + rb3v = constr.rbBareVisDiff(3); + rf3 = constr.rfBareSolDiff(3); + rf3v = constr.rfBareVisDiff(3); + } + } + if (IntShade) { // Correction factors for inter-reflections between glass and shading device ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffBack); ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffBack); @@ -1017,19 +1034,6 @@ namespace Window { // Exterior Shade } else if (ExtShade) { - auto const *matSh = dynamic_cast(s_mat->materials(constr.LayerPoint(ShadeLayNum))); - assert(matSh != nullptr); - ShadeAbs = matSh->AbsorpSolar; - ShadeTrans = matSh->Trans; - ShadeTransVis = matSh->TransVis; - ShadeRefl = matSh->ReflectShade; - ShadeReflVis = matSh->ReflectShadeVis; - rsh = ShadeRefl; - rshv = ShadeReflVis; - tsh = ShadeTrans; - tshv = ShadeTransVis; - ash = ShadeAbs; - // Correction factors for inter-reflections between glass and shading device ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffFront); ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffFront); @@ -1065,39 +1069,6 @@ namespace Window { // Between-glass shade } else if (BGShade) { - auto const *matSh = dynamic_cast(s_mat->materials(constr.LayerPoint(ShadeLayNum))); - assert(matSh != nullptr); - ShadeAbs = matSh->AbsorpSolar; - ShadeTrans = matSh->Trans; - ShadeTransVis = matSh->TransVis; - ShadeRefl = matSh->ReflectShade; - ShadeReflVis = matSh->ReflectShadeVis; - rsh = ShadeRefl; - rshv = ShadeReflVis; - tsh = ShadeTrans; - tshv = ShadeTransVis; - ash = ShadeAbs; - - // Between-glass shade/blind; assumed to be between glass #2 and glass #3 - tsh2 = pow_2(tsh); - tshv2 = pow_2(tshv); - td1 = constr.tBareSolDiff(1); - td2 = constr.tBareSolDiff(2); - td1v = constr.tBareVisDiff(1); - td2v = constr.tBareVisDiff(2); - afd1 = constr.afBareSolDiff(1); - afd2 = constr.afBareSolDiff(2); - abd1 = constr.abBareSolDiff(1); - abd2 = constr.abBareSolDiff(2); - rb1 = constr.rbBareSolDiff(1); - rb2 = constr.rbBareSolDiff(2); - rb1v = constr.rbBareVisDiff(1); - rb2v = constr.rbBareVisDiff(2); - rf1 = constr.rfBareSolDiff(1); - rf2 = constr.rfBareSolDiff(2); - rf1v = constr.rfBareVisDiff(1); - rf2v = constr.rfBareVisDiff(2); - if (NGlass == 2) { // Front incident solar, beam, between-glass shade, NGlass = 2 @@ -1134,15 +1105,6 @@ namespace Window { } else if (NGlass == 3) { - td3 = constr.tBareSolDiff(3); - td3v = constr.tBareVisDiff(3); - afd3 = constr.afBareSolDiff(3); - abd3 = constr.abBareSolDiff(3); - rb3 = constr.rbBareSolDiff(3); - rb3v = constr.rbBareVisDiff(3); - rf3 = constr.rfBareSolDiff(3); - rf3v = constr.rfBareVisDiff(3); - // Front incident solar, beam, between-glass shade, NGlass = 3 for (int iPhi = 0; iPhi < numPhis; ++iPhi) { @@ -1295,26 +1257,6 @@ namespace Window { auto const *matBlind = dynamic_cast(s_mat->materials(BlNum)); assert(matBlind != nullptr); - // Between-glass shade/blind; assumed to be between glass #2 and glass #3 - tsh2 = pow_2(tsh); - tshv2 = pow_2(tshv); - td1 = constr.tBareSolDiff(1); - td2 = constr.tBareSolDiff(2); - td1v = constr.tBareVisDiff(1); - td2v = constr.tBareVisDiff(2); - afd1 = constr.afBareSolDiff(1); - afd2 = constr.afBareSolDiff(2); - abd1 = constr.abBareSolDiff(1); - abd2 = constr.abBareSolDiff(2); - rb1 = constr.rbBareSolDiff(1); - rb2 = constr.rbBareSolDiff(2); - rb1v = constr.rbBareVisDiff(1); - rb2v = constr.rbBareVisDiff(2); - rf1 = constr.rfBareSolDiff(1); - rf2 = constr.rfBareSolDiff(2); - rf1v = constr.rfBareVisDiff(1); - rf2v = constr.rfBareVisDiff(2); - for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) { auto const &btar = matBlind->TARs[iSlatAng]; tsh = btar.Sol.Ft.Df.Tra; @@ -1365,14 +1307,6 @@ namespace Window { auto &dfAbs1 = constr.layerSlatBlindDfAbs(1)[iSlatAng]; auto &dfAbs2 = constr.layerSlatBlindDfAbs(2)[iSlatAng]; auto &dfAbs3 = constr.layerSlatBlindDfAbs(3)[iSlatAng]; - td3 = constr.tBareSolDiff(3); - td3v = constr.tBareVisDiff(3); - afd3 = constr.afBareSolDiff(3); - abd3 = constr.abBareSolDiff(3); - rb3 = constr.rbBareSolDiff(3); - rb3v = constr.rbBareVisDiff(3); - rf3 = constr.rfBareSolDiff(3); - rf3v = constr.rfBareVisDiff(3); // Front incident solar, diffuse, between-glass blind, NGlass = 3 diff --git a/src/EnergyPlus/ZoneEquipmentManager.cc b/src/EnergyPlus/ZoneEquipmentManager.cc index 47c1b8a2a58..81b85cc4fa7 100644 --- a/src/EnergyPlus/ZoneEquipmentManager.cc +++ b/src/EnergyPlus/ZoneEquipmentManager.cc @@ -5567,6 +5567,95 @@ void UpdateZoneEquipment(EnergyPlusData &state, bool &SimAir) } } +// Check a min/max temperature schedule pair for a mixing object. +// Returns true if the temperature is outside the [min, max] range (i.e. mixing should be skipped). +// Also validates that min <= max and issues warnings/recurring errors when violated. +static bool checkMixingTempLimits(EnergyPlusData &state, + Sched::Schedule *minTempSched, + Sched::Schedule *maxTempSched, + Real64 tempToCheck, + int &errCount, + int &errIndex, + std::string_view const objectName, + std::string_view const contextMsg, + std::string_view const minLabel, + std::string_view const maxLabel) +{ + Real64 tMin = 0.0; + Real64 tMax = 0.0; + if (minTempSched != nullptr) { + tMin = minTempSched->getCurrentVal(); + } + if (maxTempSched != nullptr) { + tMax = maxTempSched->getCurrentVal(); + } + if (minTempSched != nullptr && maxTempSched != nullptr) { + if (tMin > tMax) { + ++errCount; + if (errCount < 2) { + ShowWarningError(state, EnergyPlus::format("{}: The {} is above the {} in {}", contextMsg, minLabel, maxLabel, objectName)); + ShowContinueError(state, EnergyPlus::format("The {} is set to the {}. Simulation continues.", minLabel, maxLabel)); + ShowContinueErrorTimeStamp(state, " Occurrence info:"); + } else { + ShowRecurringWarningErrorAtEnd(state, EnergyPlus::format("The {} is still above the {}", minLabel, maxLabel), errIndex, tMin, tMin); + } + tMin = tMax; + } + } + if (minTempSched != nullptr && tempToCheck < tMin) { + return true; + } + if (maxTempSched != nullptr && tempToCheck > tMax) { + return true; + } + return false; +} + +// Zero the mixing-related heat balance fields for a single ZoneHeatBalanceData object. +static void zeroMixingHeatBalanceFields(ZoneTempPredictorCorrector::ZoneSpaceHeatBalanceData &hb) +{ + hb.MCPM = 0.0; + hb.MCPTM = 0.0; + hb.MCPTI = 0.0; + hb.MCPI = 0.0; + hb.OAMFL = 0.0; + hb.MCPTV = 0.0; + hb.MCPV = 0.0; + hb.VAMFL = 0.0; + hb.MDotCPOA = 0.0; + hb.MDotOA = 0.0; + hb.MCPThermChim = 0.0; + hb.ThermChimAMFL = 0.0; + hb.MCPTThermChim = 0.0; + hb.MixingMassFlowZone = 0.0; + hb.MixingMassFlowXHumRat = 0.0; +} + +// Calculate air density based on the density basis setting (Standard, Indoor, or Outdoor). +static Real64 calcInfVentAirDensity(EnergyPlusData &state, + DataHeatBalance::InfVentDensityBasis densityBasis, + int spaceIndex, + Real64 indoorTemp, + Real64 zoneHumRat, + Real64 TempExt, + Real64 HumRatExt, + std::string_view const routineName) +{ + switch (densityBasis) { + case DataHeatBalance::InfVentDensityBasis::Standard: + return state.dataEnvrn->StdRhoAir; + case DataHeatBalance::InfVentDensityBasis::Indoor: { + Real64 humRat = zoneHumRat; + if (state.dataHeatBal->doSpaceHeatBalance) { + humRat = state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceIndex).MixingHumRat; + } + return Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, indoorTemp, humRat, routineName); + } + default: + return PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, TempExt, HumRatExt, routineName); + } +} + void CalcAirFlowSimple(EnergyPlusData &state, int const SysTimestepLoop, // System time step index bool const AdjustZoneMixingFlowFlag, // holds zone mixing air flow calc status @@ -5596,39 +5685,11 @@ void CalcAirFlowSimple(EnergyPlusData &state, static constexpr std::string_view RoutineNameZoneAirBalance("CalcAirFlowSimple:ZoneAirBalance"); for (auto &thisZoneHB : state.dataZoneTempPredictorCorrector->zoneHeatBalance) { - thisZoneHB.MCPM = 0.0; - thisZoneHB.MCPTM = 0.0; - thisZoneHB.MCPTI = 0.0; - thisZoneHB.MCPI = 0.0; - thisZoneHB.OAMFL = 0.0; - thisZoneHB.MCPTV = 0.0; - thisZoneHB.MCPV = 0.0; - thisZoneHB.VAMFL = 0.0; - thisZoneHB.MDotCPOA = 0.0; - thisZoneHB.MDotOA = 0.0; - thisZoneHB.MCPThermChim = 0.0; - thisZoneHB.ThermChimAMFL = 0.0; - thisZoneHB.MCPTThermChim = 0.0; - thisZoneHB.MixingMassFlowZone = 0.0; - thisZoneHB.MixingMassFlowXHumRat = 0.0; + zeroMixingHeatBalanceFields(thisZoneHB); } if (state.dataHeatBal->doSpaceHeatBalance) { for (auto &thisSpaceHB : state.dataZoneTempPredictorCorrector->spaceHeatBalance) { - thisSpaceHB.MCPM = 0.0; - thisSpaceHB.MCPTM = 0.0; - thisSpaceHB.MCPTI = 0.0; - thisSpaceHB.MCPI = 0.0; - thisSpaceHB.OAMFL = 0.0; - thisSpaceHB.MCPTV = 0.0; - thisSpaceHB.MCPV = 0.0; - thisSpaceHB.VAMFL = 0.0; - thisSpaceHB.MDotCPOA = 0.0; - thisSpaceHB.MDotOA = 0.0; - thisSpaceHB.MCPThermChim = 0.0; - thisSpaceHB.ThermChimAMFL = 0.0; - thisSpaceHB.MCPTThermChim = 0.0; - thisSpaceHB.MixingMassFlowZone = 0.0; - thisSpaceHB.MixingMassFlowXHumRat = 0.0; + zeroMixingHeatBalanceFields(thisSpaceHB); } } if (state.dataContaminantBalance->Contaminant.CO2Simulation && @@ -5725,25 +5786,14 @@ void CalcAirFlowSimple(EnergyPlusData &state, EnthalpyExt = state.dataEnvrn->OutEnthalpy; } - Real64 AirDensity = 0.0; // Density of air for converting from volume flow to mass flow (kg/m^3) - switch (thisVentilation.densityBasis) { - case DataHeatBalance::InfVentDensityBasis::Standard: { - AirDensity = state.dataEnvrn->StdRhoAir; - } break; - case DataHeatBalance::InfVentDensityBasis::Indoor: { - if (state.dataHeatBal->doSpaceHeatBalance) { - auto &thisSpaceHB = state.dataZoneTempPredictorCorrector->spaceHeatBalance(thisVentilation.spaceIndex); - AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW( - state, state.dataEnvrn->OutBaroPress, thisMixingMAT, thisSpaceHB.MixingHumRat, RoutineNameInfiltration); - } else { - AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW( - state, state.dataEnvrn->OutBaroPress, thisMixingMAT, thisZoneHB.MixingHumRat, RoutineNameInfiltration); - } - } break; - default: - AirDensity = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, TempExt, HumRatExt, RoutineNameInfiltration); - break; - } + Real64 AirDensity = calcInfVentAirDensity(state, + thisVentilation.densityBasis, + thisVentilation.spaceIndex, + thisMixingMAT, + thisZoneHB.MixingHumRat, + TempExt, + HumRatExt, + RoutineNameInfiltration); Real64 CpAir = PsyCpAirFnW(HumRatExt); @@ -6103,122 +6153,41 @@ void CalcAirFlowSimple(EnergyPlusData &state, continue; } } else { - // Ensure the minimum indoor temperature <= the maximum indoor temperature - Real64 MixingTmin = 0.0; - Real64 MixingTmax = 0.0; - if (thisMixing.minIndoorTempSched != nullptr) { - MixingTmin = thisMixing.minIndoorTempSched->getCurrentVal(); - } - if (thisMixing.maxIndoorTempSched != nullptr) { - MixingTmax = thisMixing.maxIndoorTempSched->getCurrentVal(); - } - if (thisMixing.minIndoorTempSched != nullptr && thisMixing.maxIndoorTempSched != nullptr) { - if (MixingTmin > MixingTmax) { - ++thisMixing.IndoorTempErrCount; - if (thisMixing.IndoorTempErrCount < 2) { - ShowWarningError( - state, - EnergyPlus::format( - "Mixing zone temperature control: The minimum zone temperature is above the maximum zone temperature in {}", - thisMixing.Name)); - ShowContinueError(state, "The minimum zone temperature is set to the maximum zone temperature. Simulation continues."); - ShowContinueErrorTimeStamp(state, " Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd(state, - "The minimum zone temperature is still above the maximum zone temperature", + Real64 TempExt = state.dataHeatBal->Zone(thisZoneNum).OutDryBulbTemp; + // Evaluate all three checks independently (no short-circuit) so that + // error counters and warnings are updated for every violated limit. + bool indoorLimited = checkMixingTempLimits(state, + thisMixing.minIndoorTempSched, + thisMixing.maxIndoorTempSched, + TZN, + thisMixing.IndoorTempErrCount, thisMixing.IndoorTempErrIndex, - MixingTmin, - MixingTmin); - } - MixingTmin = MixingTmax; - } - } - if (thisMixing.minIndoorTempSched != nullptr) { - if (TZN < MixingTmin) { - MixingLimitFlag = true; - } - } - if (thisMixing.maxIndoorTempSched != nullptr) { - if (TZN > MixingTmax) { - MixingLimitFlag = true; - } - } - // Ensure the minimum source temperature <= the maximum source temperature - if (thisMixing.minSourceTempSched != nullptr) { - MixingTmin = thisMixing.minSourceTempSched->getCurrentVal(); - } - if (thisMixing.maxSourceTempSched != nullptr) { - MixingTmax = thisMixing.maxSourceTempSched->getCurrentVal(); - } - if (thisMixing.minSourceTempSched != nullptr && thisMixing.maxSourceTempSched != nullptr) { - if (MixingTmin > MixingTmax) { - ++thisMixing.SourceTempErrCount; - if (thisMixing.SourceTempErrCount < 2) { - ShowWarningError( - state, - EnergyPlus::format( - "Mixing source temperature control: The minimum source temperature is above the maximum source temperature in {}", - thisMixing.Name)); - ShowContinueError(state, "The minimum source temperature is set to the maximum source temperature. Simulation continues."); - ShowContinueErrorTimeStamp(state, " Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd(state, - "The minimum source temperature is still above the maximum source temperature", + thisMixing.Name, + "Mixing zone temperature control", + "minimum zone temperature", + "maximum zone temperature"); + bool sourceLimited = checkMixingTempLimits(state, + thisMixing.minSourceTempSched, + thisMixing.maxSourceTempSched, + TZM, + thisMixing.SourceTempErrCount, thisMixing.SourceTempErrIndex, - MixingTmin, - MixingTmin); - } - MixingTmin = MixingTmax; - } - } - if (thisMixing.minSourceTempSched != nullptr) { - if (TZM < MixingTmin) { - MixingLimitFlag = true; - } - } - if (thisMixing.maxSourceTempSched != nullptr) { - if (TZM > MixingTmax) { - MixingLimitFlag = true; - } - } - // Ensure the minimum outdoor temperature <= the maximum outdoor temperature - Real64 TempExt = state.dataHeatBal->Zone(thisZoneNum).OutDryBulbTemp; - if (thisMixing.minOutdoorTempSched != nullptr) { - MixingTmin = thisMixing.minOutdoorTempSched->getCurrentVal(); - } - if (thisMixing.maxOutdoorTempSched != nullptr) { - MixingTmax = thisMixing.maxOutdoorTempSched->getCurrentVal(); - } - if (thisMixing.minOutdoorTempSched != nullptr && thisMixing.maxOutdoorTempSched != nullptr) { - if (MixingTmin > MixingTmax) { - ++thisMixing.OutdoorTempErrCount; - if (thisMixing.OutdoorTempErrCount < 2) { - ShowWarningError( - state, - EnergyPlus::format("Mixing outdoor temperature control: The minimum outdoor temperature is above the maximum " - "outdoor temperature in {}", - thisMixing.Name)); - ShowContinueError(state, "The minimum outdoor temperature is set to the maximum source temperature. Simulation continues."); - ShowContinueErrorTimeStamp(state, " Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd(state, - "The minimum outdoor temperature is still above the maximum outdoor temperature", - thisMixing.OutdoorTempErrIndex, - MixingTmin, - MixingTmin); - } - MixingTmin = MixingTmax; - } - } - if (thisMixing.minOutdoorTempSched != nullptr) { - if (TempExt < MixingTmin) { - MixingLimitFlag = true; - } - } - if (thisMixing.maxOutdoorTempSched != nullptr) { - if (TempExt > MixingTmax) { - MixingLimitFlag = true; - } + thisMixing.Name, + "Mixing source temperature control", + "minimum source temperature", + "maximum source temperature"); + bool outdoorLimited = checkMixingTempLimits(state, + thisMixing.minOutdoorTempSched, + thisMixing.maxOutdoorTempSched, + TempExt, + thisMixing.OutdoorTempErrCount, + thisMixing.OutdoorTempErrIndex, + thisMixing.Name, + "Mixing outdoor temperature control", + "minimum outdoor temperature", + "maximum outdoor temperature"); + if (indoorLimited || sourceLimited || outdoorLimited) { + MixingLimitFlag = true; } } @@ -6238,59 +6207,8 @@ void CalcAirFlowSimple(EnergyPlusData &state, // for mixing conditions if user input delta temp > 0, then from zone temp (TZM) // must be td degrees warmer than zone temp (TZN). If user input delta temp < 0, // then from zone temp (TZM) must be TD degrees cooler than zone temp (TZN). - if (TD < 0.0) { - if (TZM < TZN + TD) { - - thisMixing.DesiredAirFlowRate = thisMixing.DesiredAirFlowRateSaved; - if (state.dataHeatBalFanSys->ZoneMassBalanceFlag(thisZoneNum) && AdjustZoneMixingFlowFlag) { - if (thisMixing.MixingMassFlowRate > 0.0) { - thisMixing.DesiredAirFlowRate = thisMixing.MixingMassFlowRate / AirDensity; - } - } - thisMixing.MixingMassFlowRate = thisMixing.DesiredAirFlowRate * AirDensity; - - thisMCPM = thisMixing.MixingMassFlowRate * CpAir; - thisMCPTM = thisMCPM * TZN; - - // Now to determine the moisture conditions - thisMixingMassFlow = thisMixing.DesiredAirFlowRate * AirDensity; - thisMixingMassFlowXHumRat = thisMixing.DesiredAirFlowRate * AirDensity * HumRatZM; - if (state.dataContaminantBalance->Contaminant.CO2Simulation) { - state.dataContaminantBalance->MixingMassFlowCO2(thisZoneNum) += - thisMixing.DesiredAirFlowRate * AirDensity * state.dataContaminantBalance->ZoneAirCO2(fromZoneNum); - } - if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) { - state.dataContaminantBalance->MixingMassFlowGC(thisZoneNum) += - thisMixing.DesiredAirFlowRate * AirDensity * state.dataContaminantBalance->ZoneAirGC(fromZoneNum); - } - thisMixing.ReportFlag = true; - } - } else if (TD > 0.0) { - if (TZM > TZN + TD) { - thisMixing.DesiredAirFlowRate = thisMixing.DesiredAirFlowRateSaved; - if (state.dataHeatBalFanSys->ZoneMassBalanceFlag(thisZoneNum) && AdjustZoneMixingFlowFlag) { - if (thisMixing.MixingMassFlowRate > 0.0) { - thisMixing.DesiredAirFlowRate = thisMixing.MixingMassFlowRate / AirDensity; - } - } - thisMixing.MixingMassFlowRate = thisMixing.DesiredAirFlowRate * AirDensity; - - thisMCPM = thisMixing.MixingMassFlowRate * CpAir; - thisMCPTM = thisMCPM * TZM; - // Now to determine the moisture conditions - thisMixingMassFlow = thisMixing.MixingMassFlowRate; - thisMixingMassFlowXHumRat = thisMixing.MixingMassFlowRate * HumRatZM; - if (state.dataContaminantBalance->Contaminant.CO2Simulation) { - state.dataContaminantBalance->MixingMassFlowCO2(thisZoneNum) += - thisMixing.MixingMassFlowRate * state.dataContaminantBalance->ZoneAirCO2(fromZoneNum); - } - if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) { - state.dataContaminantBalance->MixingMassFlowGC(thisZoneNum) += - thisMixing.MixingMassFlowRate * state.dataContaminantBalance->ZoneAirGC(fromZoneNum); - } - thisMixing.ReportFlag = true; - } - } else if (TD == 0.0) { + bool doMixing = (TD < 0.0) ? (TZM < TZN + TD) : (TD > 0.0) ? (TZM > TZN + TD) : true; + if (doMixing) { thisMixing.DesiredAirFlowRate = thisMixing.DesiredAirFlowRateSaved; if (state.dataHeatBalFanSys->ZoneMassBalanceFlag(thisZoneNum) && AdjustZoneMixingFlowFlag) { if (thisMixing.MixingMassFlowRate > 0.0) { @@ -6300,7 +6218,8 @@ void CalcAirFlowSimple(EnergyPlusData &state, thisMixing.MixingMassFlowRate = thisMixing.DesiredAirFlowRate * AirDensity; thisMCPM = thisMixing.MixingMassFlowRate * CpAir; - thisMCPTM = thisMCPM * TZM; + // For TD < 0, use TZN (this zone temp); otherwise use TZM (from zone temp) + thisMCPTM = thisMCPM * ((TD < 0.0) ? TZN : TZM); // Now to determine the moisture conditions thisMixingMassFlow = thisMixing.MixingMassFlowRate; thisMixingMassFlowXHumRat = thisMixing.MixingMassFlowRate * HumRatZM; @@ -6373,125 +6292,41 @@ void CalcAirFlowSimple(EnergyPlusData &state, HumRatZN = thisZoneHB.MixingHumRat; // HumRat of this zone HumRatZM = fromZoneHB.MixingHumRat; // HumRat of From Zone } - // Check temperature limit - bool MixingLimitFlag = false; - // Ensure the minimum indoor temperature <= the maximum indoor temperature - Real64 MixingTmin = 0.0; - Real64 MixingTmax = 0.0; - if (thisCrossMixing.minIndoorTempSched != nullptr) { - MixingTmin = thisCrossMixing.minIndoorTempSched->getCurrentVal(); - } - if (thisCrossMixing.maxIndoorTempSched != nullptr) { - MixingTmax = thisCrossMixing.maxIndoorTempSched->getCurrentVal(); - } - if (thisCrossMixing.minIndoorTempSched != nullptr && thisCrossMixing.maxIndoorTempSched != nullptr) { - if (MixingTmin > MixingTmax) { - ++thisCrossMixing.IndoorTempErrCount; - if (thisCrossMixing.IndoorTempErrCount < 2) { - ShowWarningError( - state, - EnergyPlus::format( - "CrossMixing zone temperature control: The minimum zone temperature is above the maximum zone temperature in {}", - thisCrossMixing.Name)); - ShowContinueError(state, "The minimum zone temperature is set to the maximum zone temperature. Simulation continues."); - ShowContinueErrorTimeStamp(state, " Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd(state, - "The minimum zone temperature is still above the maximum zone temperature", + // Check temperature limits + Real64 TempExt = state.dataHeatBal->Zone(thisZoneNum).OutDryBulbTemp; + // Evaluate all three checks independently (no short-circuit) so that + // error counters and warnings are updated for every violated limit. + bool indoorLimited = checkMixingTempLimits(state, + thisCrossMixing.minIndoorTempSched, + thisCrossMixing.maxIndoorTempSched, + TZN, + thisCrossMixing.IndoorTempErrCount, thisCrossMixing.IndoorTempErrIndex, - MixingTmin, - MixingTmin); - } - MixingTmin = MixingTmax; - } - } - if (thisCrossMixing.minIndoorTempSched != nullptr) { - if (TZN < MixingTmin) { - MixingLimitFlag = true; - } - } - if (thisCrossMixing.maxIndoorTempSched != nullptr) { - if (TZN > MixingTmax) { - MixingLimitFlag = true; - } - } - // Ensure the minimum source temperature <= the maximum source temperature - if (thisCrossMixing.minSourceTempSched != nullptr) { - MixingTmin = thisCrossMixing.minSourceTempSched->getCurrentVal(); - } - if (thisCrossMixing.maxSourceTempSched != nullptr) { - MixingTmax = thisCrossMixing.maxSourceTempSched->getCurrentVal(); - } - if (thisCrossMixing.minSourceTempSched != nullptr && thisCrossMixing.maxSourceTempSched != nullptr) { - if (MixingTmin > MixingTmax) { - ++thisCrossMixing.SourceTempErrCount; - if (thisCrossMixing.SourceTempErrCount < 2) { - ShowWarningError( - state, - EnergyPlus::format("CrossMixing source temperature control: The minimum source temperature is above the maximum source " - "temperature in {}", - thisCrossMixing.Name)); - ShowContinueError(state, "The minimum source temperature is set to the maximum source temperature. Simulation continues."); - ShowContinueErrorTimeStamp(state, " Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd(state, - "The minimum source temperature is still above the maximum source temperature", + thisCrossMixing.Name, + "CrossMixing zone temperature control", + "minimum zone temperature", + "maximum zone temperature"); + bool sourceLimited = checkMixingTempLimits(state, + thisCrossMixing.minSourceTempSched, + thisCrossMixing.maxSourceTempSched, + TZM, + thisCrossMixing.SourceTempErrCount, thisCrossMixing.SourceTempErrIndex, - MixingTmin, - MixingTmin); - } - MixingTmin = MixingTmax; - } - } - if (thisCrossMixing.minSourceTempSched != nullptr) { - if (TZM < MixingTmin) { - MixingLimitFlag = true; - } - } - if (thisCrossMixing.maxSourceTempSched != nullptr) { - if (TZM > MixingTmax) { - MixingLimitFlag = true; - } - } - // Ensure the minimum outdoor temperature <= the maximum outdoor temperature - Real64 TempExt = state.dataHeatBal->Zone(thisZoneNum).OutDryBulbTemp; - if (thisCrossMixing.minOutdoorTempSched != nullptr) { - MixingTmin = thisCrossMixing.minOutdoorTempSched->getCurrentVal(); - } - if (thisCrossMixing.maxOutdoorTempSched != nullptr) { - MixingTmax = thisCrossMixing.maxOutdoorTempSched->getCurrentVal(); - } - if (thisCrossMixing.minOutdoorTempSched != nullptr && thisCrossMixing.maxOutdoorTempSched != nullptr) { - if (MixingTmin > MixingTmax) { - ++thisCrossMixing.OutdoorTempErrCount; - if (thisCrossMixing.OutdoorTempErrCount < 2) { - ShowWarningError( - state, - EnergyPlus::format("CrossMixing outdoor temperature control: The minimum outdoor temperature is above the maximum " - "outdoor temperature in {}", - state.dataHeatBal->Mixing(j).Name)); - ShowContinueError(state, "The minimum outdoor temperature is set to the maximum source temperature. Simulation continues."); - ShowContinueErrorTimeStamp(state, " Occurrence info:"); - } else { - ShowRecurringWarningErrorAtEnd(state, - "The minimum outdoor temperature is still above the maximum outdoor temperature", - thisCrossMixing.OutdoorTempErrIndex, - MixingTmin, - MixingTmin); - } - MixingTmin = MixingTmax; - } - } - if (thisCrossMixing.minOutdoorTempSched != nullptr) { - if (TempExt < MixingTmin) { - MixingLimitFlag = true; - } - } - if (thisCrossMixing.maxOutdoorTempSched != nullptr) { - if (TempExt > MixingTmax) { - MixingLimitFlag = true; - } - } + thisCrossMixing.Name, + "CrossMixing source temperature control", + "minimum source temperature", + "maximum source temperature"); + bool outdoorLimited = checkMixingTempLimits(state, + thisCrossMixing.minOutdoorTempSched, + thisCrossMixing.maxOutdoorTempSched, + TempExt, + thisCrossMixing.OutdoorTempErrCount, + thisCrossMixing.OutdoorTempErrIndex, + thisCrossMixing.Name, + "CrossMixing outdoor temperature control", + "minimum outdoor temperature", + "maximum outdoor temperature"); + bool MixingLimitFlag = indoorLimited || sourceLimited || outdoorLimited; if (MixingLimitFlag) { continue; } @@ -6731,25 +6566,14 @@ void CalcAirFlowSimple(EnergyPlusData &state, HumRatExt = state.dataEnvrn->OutHumRat; } - Real64 AirDensity = 0.0; // Density of air for converting from volume flow to mass flow (kg/m^3) - switch (thisInfiltration.densityBasis) { - case DataHeatBalance::InfVentDensityBasis::Standard: { - AirDensity = state.dataEnvrn->StdRhoAir; - } break; - case DataHeatBalance::InfVentDensityBasis::Indoor: { - if (state.dataHeatBal->doSpaceHeatBalance) { - auto &thisSpaceHB = state.dataZoneTempPredictorCorrector->spaceHeatBalance(thisInfiltration.spaceIndex); - AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW( - state, state.dataEnvrn->OutBaroPress, tempInt, thisSpaceHB.MixingHumRat, RoutineNameInfiltration); - } else { - AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW( - state, state.dataEnvrn->OutBaroPress, tempInt, thisZoneHB.MixingHumRat, RoutineNameInfiltration); - } - } break; - default: - AirDensity = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, TempExt, HumRatExt, RoutineNameInfiltration); - break; - } + Real64 AirDensity = calcInfVentAirDensity(state, + thisInfiltration.densityBasis, + thisInfiltration.spaceIndex, + tempInt, + thisZoneHB.MixingHumRat, + TempExt, + HumRatExt, + RoutineNameInfiltration); Real64 CpAir = PsyCpAirFnW(HumRatExt); Real64 MCpI_temp = 0.0; diff --git a/src/EnergyPlus/ZoneTempPredictorCorrector.cc b/src/EnergyPlus/ZoneTempPredictorCorrector.cc index ca3e024b17e..c7dbeffe10d 100644 --- a/src/EnergyPlus/ZoneTempPredictorCorrector.cc +++ b/src/EnergyPlus/ZoneTempPredictorCorrector.cc @@ -191,6 +191,217 @@ Array1D_string const AdaptiveComfortModelTypes(8, "AdaptiveCEN15251CategoryIIUpperLine", "AdaptiveCEN15251CategoryIIIUpperLine"}); +// Helper: apply Operative Temperature control settings to a single TempControlledZone. +// showErrors controls whether validation errors are emitted (false when processing +// zones after the first in a zone-list, where errors were already reported for item 1). +static void applyOpTempCtrlToZone(EnergyPlusData &state, + DataZoneControls::ZoneTempControls &tempZone, + ErrorObjectHeader const &eoh, + int NumAlphas, + bool showErrors, + bool &ErrorsFound) +{ + auto &s_ipsc = state.dataIPShortCut; + auto &s_ztpc = state.dataZoneTempPredictorCorrector; + + tempZone.OpTempCtrl = static_cast(getEnumValue(DataZoneControls::tempCtrlNamesUC, s_ipsc->cAlphaArgs(2))); + + if (showErrors) { + if (tempZone.OpTempCtrl != DataZoneControls::TempCtrl::Constant && tempZone.OpTempCtrl != DataZoneControls::TempCtrl::Scheduled) { + ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)); + ErrorsFound = true; + } + } + + tempZone.FixedRadiativeFraction = s_ipsc->rNumericArgs(1); + + if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Scheduled) { + if (s_ipsc->lAlphaFieldBlanks(3)) { + if (showErrors) { + ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3)); + ErrorsFound = true; + } + } else if ((tempZone.opTempRadiativeFractionSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) { + if (showErrors) { + ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)); + ErrorsFound = true; + } + } else if (!tempZone.opTempRadiativeFractionSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::Ex, 0.9)) { + if (showErrors) { + Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, 0.0, Clusive::Ex, 0.9); + ErrorsFound = true; + } + } + } else { + if (showErrors) { + if (tempZone.FixedRadiativeFraction < 0.0) { + ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::In, 0.0); + ErrorsFound = true; + } else if (tempZone.FixedRadiativeFraction >= 0.9) { + ShowSevereBadMax(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::Ex, 0.9); + ErrorsFound = true; + } + } + } + + // Adaptive comfort model + if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Constant || tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Scheduled) { + if (NumAlphas >= 4 && !s_ipsc->lAlphaFieldBlanks(4)) { + int adaptiveComfortModelTypeIndex = Util::FindItem(s_ipsc->cAlphaArgs(4), AdaptiveComfortModelTypes, AdaptiveComfortModelTypes.isize()); + if (adaptiveComfortModelTypeIndex == 0) { + ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)); + ErrorsFound = true; + } else if (adaptiveComfortModelTypeIndex != static_cast(AdaptiveComfortModel::ADAP_NONE)) { + tempZone.AdaptiveComfortTempControl = true; + tempZone.AdaptiveComfortModelTypeIndex = adaptiveComfortModelTypeIndex; + if (!s_ztpc->AdapComfortDailySetPointSchedule.initialized) { + Array1D runningAverageASH(state.dataWeather->NumDaysInYear, 0.0); + Array1D runningAverageCEN(state.dataWeather->NumDaysInYear, 0.0); + CalculateMonthlyRunningAverageDryBulb(state, runningAverageASH, runningAverageCEN); + CalculateAdaptiveComfortSetPointSchl(state, runningAverageASH, runningAverageCEN); + } + } + } + + auto &Zone = state.dataHeatBal->Zone; + SetupOutputVariable(state, + "Zone Thermostat Operative Temperature", + Constant::Units::C, + state.dataHeatBal->ZnAirRpt(tempZone.ActualZoneNum).ThermOperativeTemp, + OutputProcessor::TimeStepType::Zone, + OutputProcessor::StoreType::Average, + Zone(tempZone.ActualZoneNum).Name); + } +} + +// Helper: emit a "control type not valid for this zone" error for a missing setpoint schedule. +// Used by both TStat and ComfortTStat schedule validation. +static void showMissingSetptSchedError(EnergyPlusData &state, + Sched::Schedule const *setptTypeSched, + HVAC::SetptType setptType, + std::string_view controlTypeName, + std::string_view zoneName, + std::string_view zoneRealName, + bool &ErrorsFound) +{ + if (setptTypeSched->hasVal(state, (int)setptType)) { + ShowSevereError(state, EnergyPlus::format("Control Type Schedule={}", setptTypeSched->Name)); + ShowContinueError( + state, + EnergyPlus::format("..specifies {} ({}) as the control type. Not valid for this zone.", (int)setptType, setptTypeNames[(int)setptType])); + ShowContinueError(state, EnergyPlus::format("..reference {}={}", controlTypeName, zoneName)); + ShowContinueError(state, EnergyPlus::format("..reference ZONE={}", zoneRealName)); + ErrorsFound = true; + } +} + +// Helper: read a single schedule field, look it up, and optionally validate min/max range. +// Assigns the result to *target. Returns true if an error was found. +static bool readSetptSchedField(EnergyPlusData &state, + ErrorObjectHeader const &eoh, + int fieldIdx, + Sched::Schedule *&target, + bool checkRange = false, + Real64 rangeMin = 0.0, + Real64 rangeMax = 0.0) +{ + auto &s_ipsc = state.dataIPShortCut; + if (s_ipsc->lAlphaFieldBlanks(fieldIdx)) { + ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(fieldIdx)); + return true; + } + if ((target = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(fieldIdx))) == nullptr) { + ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(fieldIdx), s_ipsc->cAlphaArgs(fieldIdx)); + return true; + } + if (checkRange && !target->checkMinMaxVals(state, Clusive::In, rangeMin, Clusive::In, rangeMax)) { + Sched::ShowSevereBadMinMax( + state, eoh, s_ipsc->cAlphaFieldNames(fieldIdx), s_ipsc->cAlphaArgs(fieldIdx), Clusive::In, rangeMin, Clusive::In, rangeMax); + return true; + } + return false; +} + +// Helper: load setpoint schedule objects for a given setpoint type. +// Reads the IDF objects, allocates the array, and fills in heatSched/coolSched. +// objectNames is the array of object names indexed by SetptType. +// numControls/setptScheds are arrays indexed by SetptType to fill in. +static void loadSetptSchedObjects(EnergyPlusData &state, + std::string_view routineName, + HVAC::SetptType setptType, + std::array const &objectNames, + std::array &numControls, + std::array, (int)HVAC::SetptType::Num> &setptScheds, + bool &ErrorsFound, + bool checkRange = false, + Real64 rangeMin = 0.0, + Real64 rangeMax = 0.0) +{ + auto &s_ipsc = state.dataIPShortCut; + auto &s_ip = state.dataInputProcessing->inputProcessor; + int NumAlphas, NumNums, IOStat; + int iType = (int)setptType; + + s_ipsc->cCurrentModuleObject = std::string(objectNames[iType]); + numControls[iType] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); + + if (numControls[iType] > 0) { + setptScheds[iType].allocate(numControls[iType]); + } + + bool needsHeat = + (setptType == HVAC::SetptType::SingleHeat || setptType == HVAC::SetptType::SingleHeatCool || setptType == HVAC::SetptType::DualHeatCool); + bool needsCool = + (setptType == HVAC::SetptType::SingleCool || setptType == HVAC::SetptType::SingleHeatCool || setptType == HVAC::SetptType::DualHeatCool); + bool isDual = (setptType == HVAC::SetptType::DualHeatCool); + + for (int idx = 1; idx <= numControls[iType]; ++idx) { + s_ip->getObjectItem(state, + s_ipsc->cCurrentModuleObject, + idx, + s_ipsc->cAlphaArgs, + NumAlphas, + s_ipsc->rNumericArgs, + NumNums, + IOStat, + s_ipsc->lNumericFieldBlanks, + s_ipsc->lAlphaFieldBlanks, + s_ipsc->cAlphaFieldNames, + s_ipsc->cNumericFieldNames); + + ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; + + auto &setpt = setptScheds[iType](idx); + setpt.Name = s_ipsc->cAlphaArgs(1); + + if (isDual) { + // DualHeatCool: field 2 = heat schedule, field 3 = cool schedule + if (readSetptSchedField(state, eoh, 2, setpt.heatSched, checkRange, rangeMin, rangeMax)) { + ErrorsFound = true; + } + if (readSetptSchedField(state, eoh, 3, setpt.coolSched, checkRange, rangeMin, rangeMax)) { + ErrorsFound = true; + } + } else if (needsHeat && needsCool) { + // SingleHeatCool: field 2 = both heat and cool schedule + if (readSetptSchedField(state, eoh, 2, setpt.heatSched, checkRange, rangeMin, rangeMax)) { + ErrorsFound = true; + } else { + setpt.coolSched = setpt.heatSched; + } + } else if (needsHeat) { + if (readSetptSchedField(state, eoh, 2, setpt.heatSched, checkRange, rangeMin, rangeMax)) { + ErrorsFound = true; + } + } else { + // SingleCool + if (readSetptSchedField(state, eoh, 2, setpt.coolSched, checkRange, rangeMin, rangeMax)) { + ErrorsFound = true; + } + } + } +} + // Functions void ManageZoneAirUpdates(EnergyPlusData &state, DataHeatBalFanSys::PredictorCorrectorCtrl const UpdateType, // Can be iGetZoneSetPoints, iPredictStep, iCorrectStep @@ -518,158 +729,18 @@ void GetZoneAirSetPoints(EnergyPlusData &state) } // NumTStatStatements } // Check on number of TempControlledZones - s_ipsc->cCurrentModuleObject = setptTypeNamesUC[(int)HVAC::SetptType::SingleHeat]; - s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeat] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); + // Temperature setpoint object names indexed by SetptType (preserving original UC/non-UC usage) + static constexpr std::array tempSetptObjNames = { + "", + setptTypeNamesUC[(int)HVAC::SetptType::SingleHeat], + setptTypeNamesUC[(int)HVAC::SetptType::SingleCool], + setptTypeNames[(int)HVAC::SetptType::SingleHeatCool], + setptTypeNames[(int)HVAC::SetptType::DualHeatCool]}; - if (s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeat] > 0) { - s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleHeat].allocate(s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeat]); + for (HVAC::SetptType setptType : HVAC::controlledSetptTypes) { + loadSetptSchedObjects(state, routineName, setptType, tempSetptObjNames, s_ztpc->NumTempControls, s_ztpc->tempSetptScheds, ErrorsFound); } - for (int idx = 1; idx <= s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeat]; ++idx) { - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - idx, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); - - ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - - auto &setpt = s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleHeat](idx); - setpt.Name = s_ipsc->cAlphaArgs(1); - - if (s_ipsc->lAlphaFieldBlanks(2)) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2)); - ErrorsFound = true; - } else if ((setpt.heatSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)); - ErrorsFound = true; - } - - } // SingleTempHeatingControlNum - - s_ipsc->cCurrentModuleObject = setptTypeNamesUC[(int)HVAC::SetptType::SingleCool]; - s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); - - if (s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleCool] > 0) { - s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleCool].allocate(s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleCool]); - } - - for (int idx = 1; idx <= s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleCool]; ++idx) { - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - idx, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); - - ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - - auto &setpt = s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleCool](idx); - setpt.Name = s_ipsc->cAlphaArgs(1); - - if (s_ipsc->lAlphaFieldBlanks(2)) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2)); - ErrorsFound = true; - } else if ((setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)); - ErrorsFound = true; - } - - } // SingleTempCoolingControlNum - - s_ipsc->cCurrentModuleObject = setptTypeNames[(int)HVAC::SetptType::SingleHeatCool]; - s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeatCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); - - if (s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeatCool] > 0) { - s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleHeatCool].allocate(s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeatCool]); - } - - for (int idx = 1; idx <= s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeatCool]; ++idx) { - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - idx, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); - - ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - - auto &setpt = s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleHeatCool](idx); - setpt.Name = s_ipsc->cAlphaArgs(1); - - if (s_ipsc->lAlphaFieldBlanks(2)) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2)); - ErrorsFound = true; - } else if ((setpt.heatSched = setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)); - ErrorsFound = true; - } - - } // SingleTempHeatCoolControlNum - - s_ipsc->cCurrentModuleObject = setptTypeNames[(int)HVAC::SetptType::DualHeatCool]; - s_ztpc->NumTempControls[(int)HVAC::SetptType::DualHeatCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); - - if (s_ztpc->NumTempControls[(int)HVAC::SetptType::DualHeatCool] > 0) { - s_ztpc->tempSetptScheds[(int)HVAC::SetptType::DualHeatCool].allocate(s_ztpc->NumTempControls[(int)HVAC::SetptType::DualHeatCool]); - } - - for (int idx = 1; idx <= s_ztpc->NumTempControls[(int)HVAC::SetptType::DualHeatCool]; ++idx) { - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - idx, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); - - ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - - auto &setpt = s_ztpc->tempSetptScheds[(int)HVAC::SetptType::DualHeatCool](idx); - setpt.Name = s_ipsc->cAlphaArgs(1); - - if (s_ipsc->lAlphaFieldBlanks(2)) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2)); - ErrorsFound = true; - } else if ((setpt.heatSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)); - ErrorsFound = true; - } - - if (s_ipsc->lAlphaFieldBlanks(3)) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3)); - ErrorsFound = true; - } else if ((setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)); - ErrorsFound = true; - } - - } // DualTempHeatCoolControlNum - // Finish filling in Schedule pointing indexes for (TempControlledZoneNum = 1; TempControlledZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TempControlledZoneNum) { auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum); @@ -735,45 +806,39 @@ void GetZoneAirSetPoints(EnergyPlusData &state) if (!setpt.isUsed) { // Catch early issues - if (tempZone.setptTypeSched->hasVal(state, (int)setptType)) { - ShowSevereError(state, EnergyPlus::format("Control Type Schedule={}", tempZone.setptTypeSched->Name)); - ShowContinueError(state, - EnergyPlus::format("..specifies {} ({}) as the control type. Not valid for this zone.", - (int)setptType, - setptTypeNames[(int)setptType])); - ShowContinueError(state, EnergyPlus::format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TStat), tempZone.Name)); - ShowContinueError(state, EnergyPlus::format("..reference ZONE={}", tempZone.ZoneName)); - ErrorsFound = true; - } + showMissingSetptSchedError(state, + tempZone.setptTypeSched, + setptType, + cZControlTypes((int)ZoneControlTypes::TStat), + tempZone.Name, + tempZone.ZoneName, + ErrorsFound); continue; } - if (setpt.heatSetptSched == nullptr && - (setptType == HVAC::SetptType::SingleHeat || setptType == HVAC::SetptType::SingleHeatCool || - setptType == HVAC::SetptType::DualHeatCool) && - tempZone.setptTypeSched->hasVal(state, (int)setptType)) { - ShowSevereError(state, EnergyPlus::format("Control Type Schedule={}", tempZone.setptTypeSched->Name)); - ShowContinueError(state, - EnergyPlus::format("..specifies {} ({}) as the control type. Not valid for this zone.", - (int)setptType, - setptTypeNames[(int)setptType])); - ShowContinueError(state, EnergyPlus::format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TStat), tempZone.Name)); - ShowContinueError(state, EnergyPlus::format("..reference ZONE={}", tempZone.ZoneName)); - ErrorsFound = true; + bool needsHeat = (setptType == HVAC::SetptType::SingleHeat || setptType == HVAC::SetptType::SingleHeatCool || + setptType == HVAC::SetptType::DualHeatCool); + bool needsCool = (setptType == HVAC::SetptType::SingleCool || setptType == HVAC::SetptType::SingleHeatCool || + setptType == HVAC::SetptType::DualHeatCool); + + if (needsHeat && setpt.heatSetptSched == nullptr) { + showMissingSetptSchedError(state, + tempZone.setptTypeSched, + setptType, + cZControlTypes((int)ZoneControlTypes::TStat), + tempZone.Name, + tempZone.ZoneName, + ErrorsFound); } - if (setpt.coolSetptSched == nullptr && - (setptType == HVAC::SetptType::SingleCool || setptType == HVAC::SetptType::SingleHeatCool || - setptType == HVAC::SetptType::DualHeatCool) && - tempZone.setptTypeSched->hasVal(state, (int)setptType)) { - ShowSevereError(state, EnergyPlus::format("Control Type Schedule={}", tempZone.setptTypeSched->Name)); - ShowContinueError(state, - EnergyPlus::format("..specifies {} ({}) as the control type. Not valid for this zone.", - (int)setptType, - setptTypeNames[(int)setptType])); - ShowContinueError(state, EnergyPlus::format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TStat), tempZone.Name)); - ShowContinueError(state, EnergyPlus::format("..reference ZONE={}", tempZone.ZoneName)); - ErrorsFound = true; + if (needsCool && setpt.coolSetptSched == nullptr) { + showMissingSetptSchedError(state, + tempZone.setptTypeSched, + setptType, + cZControlTypes((int)ZoneControlTypes::TStat), + tempZone.Name, + tempZone.ZoneName, + ErrorsFound); } } // for (setptType) } @@ -1163,172 +1228,19 @@ void GetZoneAirSetPoints(EnergyPlusData &state) } // End of Thermal comfort control reading and checking - s_ipsc->cCurrentModuleObject = comfortSetptTypeNames[(int)HVAC::SetptType::SingleHeat]; - s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeat] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); - - if (s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeat] > 0) { - s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleHeat].allocate(s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeat]); - } - - for (int idx = 1; idx <= s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeat]; ++idx) { - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - idx, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); - - ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - - auto &setpt = s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleHeat](idx); - setpt.Name = s_ipsc->cAlphaArgs(1); - - if (s_ipsc->lAlphaFieldBlanks(2)) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2)); - ErrorsFound = true; - } else if ((setpt.heatSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)); - ErrorsFound = true; - } else if (!setpt.heatSched->checkMinMaxVals(state, Clusive::In, -3.0, Clusive::In, 3.0)) { - Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, -3.0, Clusive::In, 3.0); - ErrorsFound = true; - } - } // SingleFangerHeatingControlNum - - s_ipsc->cCurrentModuleObject = comfortSetptTypeNames[(int)HVAC::SetptType::SingleCool]; - s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); - - if (s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleCool] > 0) { - s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleCool].allocate(s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleCool]); + for (HVAC::SetptType setptType : HVAC::controlledSetptTypes) { + loadSetptSchedObjects(state, + routineName, + setptType, + comfortSetptTypeNames, + s_ztpc->NumComfortControls, + s_ztpc->comfortSetptScheds, + ErrorsFound, + true, + -3.0, + 3.0); } - for (int idx = 1; idx <= s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleCool]; ++idx) { - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - idx, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); - - ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - - auto &setpt = s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleCool](idx); - setpt.Name = s_ipsc->cAlphaArgs(1); - - if (s_ipsc->lAlphaFieldBlanks(2)) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2)); - ErrorsFound = true; - } else if ((setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)); - ErrorsFound = true; - } else if (!setpt.coolSched->checkMinMaxVals(state, Clusive::In, -3.0, Clusive::In, 3.0)) { - Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, -3.0, Clusive::In, 3.0); - ErrorsFound = true; - } - - } // SingleFangerCoolingControlNum - - s_ipsc->cCurrentModuleObject = comfortSetptTypeNames[(int)HVAC::SetptType::SingleHeatCool]; - s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeatCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); - - if (s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeatCool] > 0) { - s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleHeatCool].allocate(s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeatCool]); - } - - for (int idx = 1; idx <= s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeatCool]; ++idx) { - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - idx, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); - - ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - - auto &setpt = s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleHeatCool](idx); - setpt.Name = s_ipsc->cAlphaArgs(1); - - if (s_ipsc->lAlphaFieldBlanks(2)) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2)); - ErrorsFound = true; - } else if ((setpt.heatSched = setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)); - ErrorsFound = true; - } else if (!setpt.heatSched->checkMinMaxVals(state, Clusive::In, -3.0, Clusive::In, 3.0)) { - Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, -3.0, Clusive::In, 3.0); - ErrorsFound = true; - } - - } // SingleFangerHeatCoolControlNum - - s_ipsc->cCurrentModuleObject = comfortSetptTypeNames[(int)HVAC::SetptType::DualHeatCool]; - s_ztpc->NumComfortControls[(int)HVAC::SetptType::DualHeatCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); - - if (s_ztpc->NumComfortControls[(int)HVAC::SetptType::DualHeatCool] > 0) { - s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::DualHeatCool].allocate(s_ztpc->NumComfortControls[(int)HVAC::SetptType::DualHeatCool]); - } - - for (int idx = 1; idx <= s_ztpc->NumComfortControls[(int)HVAC::SetptType::DualHeatCool]; ++idx) { - s_ip->getObjectItem(state, - s_ipsc->cCurrentModuleObject, - idx, - s_ipsc->cAlphaArgs, - NumAlphas, - s_ipsc->rNumericArgs, - NumNums, - IOStat, - s_ipsc->lNumericFieldBlanks, - s_ipsc->lAlphaFieldBlanks, - s_ipsc->cAlphaFieldNames, - s_ipsc->cNumericFieldNames); - - ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)}; - - auto &setpt = s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::DualHeatCool](idx); - setpt.Name = s_ipsc->cAlphaArgs(1); - - if (s_ipsc->lAlphaFieldBlanks(2)) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2)); - ErrorsFound = true; - } else if ((setpt.heatSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)); - ErrorsFound = true; - } else if (!setpt.heatSched->checkMinMaxVals(state, Clusive::In, -3.0, Clusive::In, 3.0)) { - Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, -3.0, Clusive::In, 3.0); - ErrorsFound = true; - } - - if (s_ipsc->lAlphaFieldBlanks(3)) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3)); - ErrorsFound = true; - } else if ((setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)); - ErrorsFound = true; - } else if (!setpt.coolSched->checkMinMaxVals(state, Clusive::In, -3.0, Clusive::In, 3.0)) { - Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, -3.0, Clusive::In, 3.0); - ErrorsFound = true; - } - - } // DualFangerHeatCoolControlNum - // Finish filling in Schedule pointing indexes for Thermal Comfort Control for (ComfortControlledZoneNum = 1; ComfortControlledZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++ComfortControlledZoneNum) { @@ -1385,32 +1297,29 @@ void GetZoneAirSetPoints(EnergyPlusData &state) TComfortControlTypes(ComfortControlledZoneNum).DidHave[(int)setptType] = true; - if (setpt.heatSetptSched == nullptr && - (setptType == HVAC::SetptType::SingleHeat || setptType == HVAC::SetptType::SingleHeatCool || - setptType == HVAC::SetptType::DualHeatCool) && - comfortZone.setptTypeSched->hasVal(state, (int)setptType)) { - ShowSevereError(state, EnergyPlus::format("Control Type Schedule={}", comfortZone.setptTypeSched->Name)); - ShowContinueError(state, - EnergyPlus::format("..specifies {} ({}) as the control type. Not valid for this zone.", - (int)setptType, - setptTypeNames[(int)setptType])); - ShowContinueError(state, EnergyPlus::format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TStat), comfortZone.Name)); - ShowContinueError(state, EnergyPlus::format("..reference ZONE={}", comfortZone.ZoneName)); - ErrorsFound = true; - } - - if (setpt.coolSetptSched == nullptr && - (setptType == HVAC::SetptType::SingleCool || setptType == HVAC::SetptType::SingleHeatCool || - setptType == HVAC::SetptType::DualHeatCool) && - comfortZone.setptTypeSched->hasVal(state, (int)setptType)) { - ShowSevereError(state, EnergyPlus::format("Control Type Schedule={}", comfortZone.setptTypeSched->Name)); - ShowContinueError(state, - EnergyPlus::format("..specifies {} ({}) as the control type. Not valid for this zone.", - (int)setptType, - setptTypeNames[(int)setptType])); - ShowContinueError(state, EnergyPlus::format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TStat), comfortZone.Name)); - ShowContinueError(state, EnergyPlus::format("..reference ZONE={}", comfortZone.ZoneName)); - ErrorsFound = true; + bool needsHeat = (setptType == HVAC::SetptType::SingleHeat || setptType == HVAC::SetptType::SingleHeatCool || + setptType == HVAC::SetptType::DualHeatCool); + bool needsCool = (setptType == HVAC::SetptType::SingleCool || setptType == HVAC::SetptType::SingleHeatCool || + setptType == HVAC::SetptType::DualHeatCool); + + if (needsHeat && setpt.heatSetptSched == nullptr) { + showMissingSetptSchedError(state, + comfortZone.setptTypeSched, + setptType, + cZControlTypes((int)ZoneControlTypes::TStat), + comfortZone.Name, + comfortZone.ZoneName, + ErrorsFound); + } + + if (needsCool && setpt.coolSetptSched == nullptr) { + showMissingSetptSchedError(state, + comfortZone.setptTypeSched, + setptType, + cZControlTypes((int)ZoneControlTypes::TStat), + comfortZone.Name, + comfortZone.ZoneName, + ErrorsFound); } } // for (setptType) } // for (ComfortControlledZoneNum) @@ -1596,83 +1505,7 @@ void GetZoneAirSetPoints(EnergyPlusData &state) continue; } auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum); - tempZone.OpTempCtrl = - static_cast(getEnumValue(DataZoneControls::tempCtrlNamesUC, s_ipsc->cAlphaArgs(2))); - - if (Item == 1) { - if (tempZone.OpTempCtrl != DataZoneControls::TempCtrl::Constant && - tempZone.OpTempCtrl != DataZoneControls::TempCtrl::Scheduled) { - ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)); - ErrorsFound = true; - } - } - - tempZone.FixedRadiativeFraction = s_ipsc->rNumericArgs(1); - - if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Scheduled) { - if (s_ipsc->lAlphaFieldBlanks(3)) { - if (Item == 1) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3)); - ErrorsFound = true; - } - } else if ((tempZone.opTempRadiativeFractionSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) { - if (Item == 1) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)); - ErrorsFound = true; - } - } else if (!tempZone.opTempRadiativeFractionSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::Ex, 0.9)) { - if (Item == 1) { - Sched::ShowSevereBadMinMax( - state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, 0.0, Clusive::Ex, 0.9); - ErrorsFound = true; - } - } - - } else { // !tempZone.OpTempCntrlModeScheduled - - // check validity of fixed radiative fraction - if (Item == 1) { - if (tempZone.FixedRadiativeFraction < 0.0) { - ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::In, 0.0); - ErrorsFound = true; - } else if (tempZone.FixedRadiativeFraction >= 0.9) { - ShowSevereBadMax(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::Ex, 0.9); - ErrorsFound = true; - } - } - } - - // added Jan, 2017 - Xuan Luo - // read adaptive comfort model and calculate adaptive thermal comfort setpoint - if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Constant || tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Scheduled) { - if (NumAlphas >= 4 && !s_ipsc->lAlphaFieldBlanks(4)) { - int adaptiveComfortModelTypeIndex = - Util::FindItem(s_ipsc->cAlphaArgs(4), AdaptiveComfortModelTypes, AdaptiveComfortModelTypes.isize()); - if (adaptiveComfortModelTypeIndex == 0) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)); - ErrorsFound = true; - } else if (adaptiveComfortModelTypeIndex != static_cast(AdaptiveComfortModel::ADAP_NONE)) { - tempZone.AdaptiveComfortTempControl = true; - tempZone.AdaptiveComfortModelTypeIndex = - Util::FindItem(s_ipsc->cAlphaArgs(4), AdaptiveComfortModelTypes, AdaptiveComfortModelTypes.isize()); - if (!s_ztpc->AdapComfortDailySetPointSchedule.initialized) { - Array1D runningAverageASH(state.dataWeather->NumDaysInYear, 0.0); - Array1D runningAverageCEN(state.dataWeather->NumDaysInYear, 0.0); - CalculateMonthlyRunningAverageDryBulb(state, runningAverageASH, runningAverageCEN); - CalculateAdaptiveComfortSetPointSchl(state, runningAverageASH, runningAverageCEN); - } - } - } - } - - // CurrentModuleObject='ZoneControl:Thermostat:OperativeTemperature' - SetupOutputVariable(state, - "Zone Thermostat Operative Temperature", - Constant::Units::C, - state.dataHeatBal->ZnAirRpt(tempZone.ActualZoneNum).ThermOperativeTemp, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - Zone(tempZone.ActualZoneNum).Name); + applyOpTempCtrlToZone(state, tempZone, eoh, NumAlphas, /*showErrors=*/Item == 1, ErrorsFound); } // TStat Objects Loop // It might be in the TempControlledZones @@ -1680,69 +1513,7 @@ void GetZoneAirSetPoints(EnergyPlusData &state) TempControlledZoneNum = found; auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum); - tempZone.OpTempCtrl = static_cast(getEnumValue(DataZoneControls::tempCtrlNamesUC, s_ipsc->cAlphaArgs(2))); - if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Invalid || tempZone.OpTempCtrl == DataZoneControls::TempCtrl::None) { - ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)); - ErrorsFound = true; - } - - tempZone.FixedRadiativeFraction = s_ipsc->rNumericArgs(1); - - if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Scheduled) { - if (s_ipsc->lAlphaFieldBlanks(3)) { - ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3)); - ErrorsFound = true; - } else if ((tempZone.opTempRadiativeFractionSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)); - ErrorsFound = true; - } else if (!tempZone.opTempRadiativeFractionSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::Ex, 0.9)) { - Sched::ShowSevereBadMinMax( - state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, 0.0, Clusive::Ex, 0.9); - ErrorsFound = true; - } - - } else { // !tempZone.OpTempCntrlModeScheduled - - if (tempZone.FixedRadiativeFraction < 0.0) { - ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::In, 0.0); - ErrorsFound = true; - } else if (tempZone.FixedRadiativeFraction >= 0.9) { - ShowSevereBadMax(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::Ex, 0.9); - ErrorsFound = true; - } - } - - // added Jan, 2017 - Xuan Luo - // read adaptive comfort model and calculate adaptive thermal comfort setpoint - if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Constant || tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Scheduled) { - if (NumAlphas >= 4 && !s_ipsc->lAlphaFieldBlanks(4)) { - int adaptiveComfortModelTypeIndex = - Util::FindItem(s_ipsc->cAlphaArgs(4), AdaptiveComfortModelTypes, AdaptiveComfortModelTypes.isize()); - if (adaptiveComfortModelTypeIndex == 0) { - ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)); - ErrorsFound = true; - } else if (adaptiveComfortModelTypeIndex != static_cast(AdaptiveComfortModel::ADAP_NONE)) { - tempZone.AdaptiveComfortTempControl = true; - tempZone.AdaptiveComfortModelTypeIndex = adaptiveComfortModelTypeIndex; - if (!s_ztpc->AdapComfortDailySetPointSchedule.initialized) { - Array1D runningAverageASH(state.dataWeather->NumDaysInYear, 0.0); - Array1D runningAverageCEN(state.dataWeather->NumDaysInYear, 0.0); - // What does this accomplish? - CalculateMonthlyRunningAverageDryBulb(state, runningAverageASH, runningAverageCEN); - CalculateAdaptiveComfortSetPointSchl(state, runningAverageASH, runningAverageCEN); - } - } - } - - // CurrentModuleObject='ZoneControl:Thermostat:OperativeTemperature' - SetupOutputVariable(state, - "Zone Thermostat Operative Temperature", - Constant::Units::C, - state.dataHeatBal->ZnAirRpt(tempZone.ActualZoneNum).ThermOperativeTemp, - OutputProcessor::TimeStepType::Zone, - OutputProcessor::StoreType::Average, - Zone(tempZone.ActualZoneNum).Name); - } + applyOpTempCtrlToZone(state, tempZone, eoh, NumAlphas, /*showErrors=*/true, ErrorsFound); // throw error } else { ShowSevereError(state, diff --git a/third_party/fmt-8.0.1/include/fmt/core.h b/third_party/fmt-8.0.1/include/fmt/core.h index 1bfb2e15b2a..63fd1132e95 100644 --- a/third_party/fmt-8.0.1/include/fmt/core.h +++ b/third_party/fmt-8.0.1/include/fmt/core.h @@ -1634,7 +1634,16 @@ FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg { template FMT_CONSTEXPR FMT_INLINE auto make_arg(T&& val) -> value { + // Suppress false-positive -Wdangling-reference from GCC 13+; the temporary + // arg_mapper is intentional and the mapped reference outlives this expression. +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 13 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdangling-reference" +#endif const auto& arg = arg_mapper().map(std::forward(val)); +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 13 +# pragma GCC diagnostic pop +#endif constexpr bool formattable_char = !std::is_same::value; diff --git a/third_party/fmt-8.0.1/include/fmt/format.h b/third_party/fmt-8.0.1/include/fmt/format.h index ea29f0cd987..edc1b289951 100644 --- a/third_party/fmt-8.0.1/include/fmt/format.h +++ b/third_party/fmt-8.0.1/include/fmt/format.h @@ -1718,6 +1718,12 @@ inline auto write_significand(OutputIt out, T significand, int significand_size, return grouping.apply(out, string_view(buffer.data(), buffer.size())); } +// Suppress false-positive -Wrestrict from GCC 13+/15+ when this function is +// deeply inlined through write_float → write_padded → write_significand. +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wrestrict" +#endif template ::value)> inline auto write_significand(Char* out, UInt significand, int significand_size, @@ -1734,6 +1740,9 @@ inline auto write_significand(Char* out, UInt significand, int significand_size, out[integral_size] = decimal_point; return end; } +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic pop +#endif template >::value)> diff --git a/third_party/ssc/shared/lib_battery_dispatch.cpp b/third_party/ssc/shared/lib_battery_dispatch.cpp index 6b3acbf7d9a..451a4b18eef 100644 --- a/third_party/ssc/shared/lib_battery_dispatch.cpp +++ b/third_party/ssc/shared/lib_battery_dispatch.cpp @@ -26,6 +26,8 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include +#include /* Dispatch base class diff --git a/tools/dry-refactor-done.txt b/tools/dry-refactor-done.txt new file mode 100644 index 00000000000..587386f1cfb --- /dev/null +++ b/tools/dry-refactor-done.txt @@ -0,0 +1,64 @@ +# Functions already refactored by the dry-refactor agent. +# Format: file_path:function_name +# The auto-dry-refactor agent should skip these when selecting candidates. + +src/EnergyPlus/DXCoils.cc:GetDXCoils +src/EnergyPlus/RefrigeratedCase.cc:GetRefrigerationInput +src/EnergyPlus/Furnaces.cc:GetFurnaceInput +src/EnergyPlus/HeatBalanceAirManager.cc:GetSimpleAirModelInputs +src/EnergyPlus/SetPointManager.cc:GetSetPointManagerInputData +src/EnergyPlus/AirflowNetwork/src/Solver.cpp:get_input +src/EnergyPlus/HVACVariableRefrigerantFlow.cc:GetVRFInputData +src/EnergyPlus/UnitarySystem.cc:processInputSpec +src/EnergyPlus/InternalHeatGains.cc:GetInternalHeatGainsInput +src/EnergyPlus/VariableSpeedCoils.cc:GetVarSpeedCoilInput +src/EnergyPlus/SetPointManager.cc:InitSetPointManagers +src/EnergyPlus/RefrigeratedCase.cc:ReportRefrigerationComponents +src/EnergyPlus/RefrigeratedCase.cc:CalculateCompressors +src/EnergyPlus/RefrigeratedCase.cc:CalculateTransCompressors +src/EnergyPlus/RefrigeratedCase.cc:SimulateDetailedTransRefrigSystems +src/EnergyPlus/RefrigeratedCase.cc:CalculateSubcoolers +src/EnergyPlus/UnitarySystem.cc:reportUnitarySystem +src/EnergyPlus/UnitarySystem.cc:simMultiSpeedCoils +src/EnergyPlus/UnitarySystem.cc:setupAllOutputVars +src/EnergyPlus/UnitarySystem.cc:sizeSystem +src/EnergyPlus/WaterToAirHeatPumpSimple.cc:SizeHVACWaterToAir +src/EnergyPlus/SurfaceGeometry.cc:GetSurfaceData +src/EnergyPlus/SolarShading.cc:SHADOW +src/EnergyPlus/Material.cc:GetMaterialData +src/EnergyPlus/SimAirServingZones.cc:UpdateSysSizing +src/EnergyPlus/CurveManager.cc:GetCurveInputData +src/EnergyPlus/HVACVariableRefrigerantFlow.cc:InitVRF +src/EnergyPlus/FaultsManager.cc:CheckAndReadFaults +src/EnergyPlus/InternalHeatGains.cc:setupIHGOutputs +src/EnergyPlus/OutputReportTabular.cc:WriteBEPSTable +src/EnergyPlus/WaterToAirHeatPumpSimple.cc:SizeHVACWaterToAir +src/EnergyPlus/ZoneTempPredictorCorrector.cc:GetZoneAirSetPoints +src/EnergyPlus/SingleDuct.cc:GetSysInput +src/EnergyPlus/PackagedThermalStorageCoil.cc:GetTESCoilInput +src/EnergyPlus/SolarShading.cc:AllocateModuleArrays +src/EnergyPlus/CondenserLoopTowers.cc:GetTowerInput +src/EnergyPlus/UnitarySystem.cc:controlCoolingSystemToSP +src/EnergyPlus/ScheduleManager.cc:ProcessScheduleInput +src/EnergyPlus/LowTempRadiantSystem.cc:GetLowTempRadiantSystem +src/EnergyPlus/RefrigeratedCase.cc:SetupReportInput +src/EnergyPlus/HVACMultiSpeedHeatPump.cc:GetMSHeatPumpInput +src/EnergyPlus/HeatingCoils.cc:GetHeatingCoilInput +src/EnergyPlus/DesiccantDehumidifiers.cc:GetDesiccantDehumidifierInput +src/EnergyPlus/UnitarySystem.cc:controlUnitarySystemOutput +src/EnergyPlus/DXCoils.cc:SizeDXCoil +src/EnergyPlus/HVACUnitaryBypassVAV.cc:CalcCBVAV +src/EnergyPlus/VariableSpeedCoils.cc:SizeVarSpeedCoil +src/EnergyPlus/HVACVariableRefrigerantFlow.cc:SizeVRF +src/EnergyPlus/ZoneEquipmentManager.cc:CalcAirFlowSimple +src/EnergyPlus/SystemAvailabilityManager.cc:CalcOptStartSysAvailMgr +src/EnergyPlus/Furnaces.cc:CalcNewZoneHeatCoolFlowRates +src/EnergyPlus/Pumps.cc:GetPumpInput +src/EnergyPlus/EvaporativeFluidCoolers.cc:SizeEvapFluidCooler +src/EnergyPlus/FluidProperties.cc:GetFluidPropertiesData +src/EnergyPlus/UnitarySystem.cc:controlCoolingSystemToSP +src/EnergyPlus/WindowManager.cc:InitGlassOpticalCalculations +src/EnergyPlus/HVACVariableRefrigerantFlow.cc:CalcVRFCondenser_FluidTCtrl +src/EnergyPlus/SimAirServingZones.cc:GetAirPathData +src/EnergyPlus/FanCoilUnits.cc:Sim4PipeFanCoil +src/EnergyPlus/OutputReportPredefined.cc:SetPredefinedTables diff --git a/tools/dry-refactor-viz.html b/tools/dry-refactor-viz.html new file mode 100644 index 00000000000..c87d721e744 --- /dev/null +++ b/tools/dry-refactor-viz.html @@ -0,0 +1,1004 @@ + + + + + +DRY Refactor Dashboard — EnergyPlus + + + +
Loading data
+ + + + + + + diff --git a/tools/generate-dry-data.sh b/tools/generate-dry-data.sh new file mode 100644 index 00000000000..81801763b1d --- /dev/null +++ b/tools/generate-dry-data.sh @@ -0,0 +1,249 @@ +#!/usr/bin/env bash +# Generate dry-refactor-data.json from git history on dry-refactor-agent branch +# Usage: bash tools/generate-dry-data.sh [base_branch] + +set -euo pipefail + +BASE_BRANCH="${1:-develop}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OUTPUT="$SCRIPT_DIR/dry-refactor-data.json" +REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel)" + +cd "$REPO_ROOT" + +BRANCH=$(git rev-parse --abbrev-ref HEAD) +MERGE_BASE=$(git merge-base "$BASE_BRANCH" HEAD) + +# Get all commit hashes in chronological order (oldest first) +mapfile -t HASHES < <(git log --reverse --format='%H' "$MERGE_BASE..HEAD") +TOTAL_COMMITS=${#HASHES[@]} + +if [ "$TOTAL_COMMITS" -eq 0 ]; then + echo '{"error": "No commits found"}' > "$OUTPUT" + exit 1 +fi + +echo "Processing $TOTAL_COMMITS commits..." >&2 + +# Collect overall stats +read TOTAL_INS TOTAL_DEL < <(git diff --numstat "$MERGE_BASE..HEAD" | awk '{i+=$1; d+=$2} END {print i, d}') +NET_REDUCTION=$((TOTAL_DEL - TOTAL_INS)) + +# Start JSON output +{ + cat <
/dev/null || true) + + if [ $FIRST_FILE -eq 0 ]; then + echo "" + echo " ]" + else + echo "]" + fi + echo -n " }" + + # Progress + if (( (i + 1) % 20 == 0 )); then + echo " Processed $((i+1))/$TOTAL_COMMITS commits..." >&2 + fi + done + + echo "" + echo " ]," + + # Per-file cumulative sizes via running delta + echo " \"files\": {" + + # Get list of all files touched + mapfile -t ALL_FILES < <(git diff --numstat "$MERGE_BASE..HEAD" | awk '{print $3}' | sort) + TOTAL_FILES=${#ALL_FILES[@]} + + FIRST_FENTRY=1 + for FILE in "${ALL_FILES[@]}"; do + [ -z "$FILE" ] && continue + + if [ $FIRST_FENTRY -eq 1 ]; then + FIRST_FENTRY=0 + else + echo " ," + fi + + # Get baseline size (LOC at merge base) + BASELINE_SIZE=$(git show "$MERGE_BASE:$FILE" 2>/dev/null | wc -l || true) + BASELINE_SIZE=$(echo "$BASELINE_SIZE" | tr -dc '0-9') + BASELINE_SIZE=${BASELINE_SIZE:-0} + + # Get current size + CURRENT_SIZE=$(git show "HEAD:$FILE" 2>/dev/null | wc -l || true) + CURRENT_SIZE=$(echo "$CURRENT_SIZE" | tr -dc '0-9') + CURRENT_SIZE=${CURRENT_SIZE:-0} + + echo " \"$FILE\": {" + echo " \"baselineSize\": $BASELINE_SIZE," + echo " \"currentSize\": $CURRENT_SIZE," + echo -n " \"snapshots\": [" + + # Build snapshots: track cumulative delta per commit that touches this file + RUNNING_SIZE=$BASELINE_SIZE + FIRST_SNAP=1 + echo "" + echo -n " {\"commitIdx\": -1, \"size\": $RUNNING_SIZE}" + + for i in "${!HASHES[@]}"; do + HASH="${HASHES[$i]}" + NUMSTAT=$(git diff --numstat "${HASH}~1" "$HASH" -- "$FILE" 2>/dev/null || true) + [ -z "$NUMSTAT" ] && continue + + read INS DEL _ <<< "$NUMSTAT" + [ "$INS" = "-" ] && continue + RUNNING_SIZE=$((RUNNING_SIZE + INS - DEL)) + + echo "," + echo -n " {\"commitIdx\": $i, \"size\": $RUNNING_SIZE}" + FIRST_SNAP=0 + done + + echo "" + echo " ]" + echo -n " }" + done + + echo "" + echo " }," + + # Function-level changes from diff hunk headers + echo " \"functions\": {" + + FIRST_FFILE=1 + for FILE in "${ALL_FILES[@]}"; do + [ -z "$FILE" ] && continue + # Only process C++ source files + [[ "$FILE" != *.cc && "$FILE" != *.hh && "$FILE" != *.cpp && "$FILE" != *.hpp ]] && continue + + # Parse hunk headers to extract function names and line counts + # Format: @@ -old,count +new,count @@ FunctionName + FUNC_DATA=$(git log --reverse --format='COMMIT:%H' -p --diff-filter=M -U0 "$MERGE_BASE..HEAD" -- "$FILE" 2>/dev/null | awk ' + /^COMMIT:/ { commit_idx++ } + /^@@/ { + # Extract function context after the second @@ + n = index($0, "@@ ") + rest = substr($0, n+3) + n2 = index(rest, " @@") + if (n2 > 0) { + fname = substr(rest, n2+4) + # Clean up: strip return type, take function name + gsub(/^[ \t]+/, "", fname) + gsub(/\(.*/, "", fname) + gsub(/^.*[ *&]/, "", fname) + if (fname != "" && fname !~ /^[{}]$/) { + # Parse hunk header for line counts + # @@ -start,count +start,count @@ + split($0, parts, "@@") + hdr = parts[2] + gsub(/^[ \t]+/, "", hdr) + # Parse old range + split(hdr, ranges, " ") + old_range = ranges[1] # -start,count + new_range = ranges[2] # +start,count + if (index(old_range, ",") > 0) { + split(old_range, oc, ","); del = oc[2]+0 + } else { del = 1 } + if (index(new_range, ",") > 0) { + split(new_range, nc, ","); ins = nc[2]+0 + } else { ins = 1 } + + func_ins[fname] += ins + func_del[fname] += del + key = fname SUBSEP commit_idx + if (!(key in seen)) { + seen[key] = 1 + if (func_commits[fname] != "") + func_commits[fname] = func_commits[fname] "," (commit_idx - 1) + else + func_commits[fname] = (commit_idx - 1) + } + } + } + } + END { + for (f in func_ins) { + printf "%s\t%d\t%d\t%s\n", f, func_ins[f]+0, func_del[f]+0, func_commits[f] + } + } + ' 2>/dev/null || true) + + [ -z "$FUNC_DATA" ] && continue + + if [ $FIRST_FFILE -eq 1 ]; then + FIRST_FFILE=0 + else + echo " ," + fi + + echo " \"$FILE\": [" + FIRST_FUNC=1 + while IFS=$'\t' read -r FNAME FINS FDEL FCOMMITS; do + [ -z "$FNAME" ] && continue + if [ $FIRST_FUNC -eq 1 ]; then + FIRST_FUNC=0 + else + echo " ," + fi + # Escape function name + FNAME_ESC=$(echo "$FNAME" | sed 's/\\/\\\\/g; s/"/\\"/g') + echo -n " {\"name\": \"$FNAME_ESC\", \"totalIns\": $FINS, \"totalDel\": $FDEL, \"commits\": [$FCOMMITS]}" + done <<< "$FUNC_DATA" + echo "" + echo -n " ]" + done + + echo "" + echo " }" + echo "}" + +} > "$OUTPUT" + +echo "Generated $OUTPUT ($TOTAL_COMMITS commits, $TOTAL_FILES files, net -$NET_REDUCTION lines)" >&2 diff --git a/tst/EnergyPlus/unit/FluidProperties.unit.cc b/tst/EnergyPlus/unit/FluidProperties.unit.cc index 2a8c0adbc04..be45622aa1b 100644 --- a/tst/EnergyPlus/unit/FluidProperties.unit.cc +++ b/tst/EnergyPlus/unit/FluidProperties.unit.cc @@ -54,7 +54,7 @@ #include #include -#include +#include #include "Fixtures/EnergyPlusFixture.hh"