Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cassert>
50 : #include <cmath>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Autosizing/Base.hh>
57 : #include <EnergyPlus/BranchNodeConnections.hh>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
60 : #include <EnergyPlus/DataEnvironment.hh>
61 : #include <EnergyPlus/DataHVACGlobals.hh>
62 : #include <EnergyPlus/DataIPShortCuts.hh>
63 : #include <EnergyPlus/DataLoopNode.hh>
64 : #include <EnergyPlus/DataPrecisionGlobals.hh>
65 : #include <EnergyPlus/DataSizing.hh>
66 : #include <EnergyPlus/EMSManager.hh>
67 : #include <EnergyPlus/FluidProperties.hh>
68 : #include <EnergyPlus/General.hh>
69 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
70 : #include <EnergyPlus/NodeInputManager.hh>
71 : #include <EnergyPlus/OutputProcessor.hh>
72 : #include <EnergyPlus/OutputReportPredefined.hh>
73 : #include <EnergyPlus/Plant/DataPlant.hh>
74 : #include <EnergyPlus/PlantHeatExchangerFluidToFluid.hh>
75 : #include <EnergyPlus/PlantUtilities.hh>
76 : #include <EnergyPlus/ScheduleManager.hh>
77 : #include <EnergyPlus/UtilityRoutines.hh>
78 :
79 : namespace EnergyPlus::PlantHeatExchangerFluidToFluid {
80 :
81 : // Module containing the routines dealing with the HeatExchanger:FluidToFluid
82 :
83 : // MODULE INFORMATION:
84 : // AUTHOR B. Griffith, derived from legacy code by Sankaranarayanan K P, and S. Rees
85 : // DATE WRITTEN November 2012
86 : // MODIFIED na
87 : // RE-ENGINEERED na
88 :
89 : // PURPOSE OF THIS MODULE:
90 : // Simulate a generic plant heat exchanger with a variety of control options
91 :
92 : std::string const ComponentClassName("HeatExchanger:FluidToFluid");
93 :
94 : constexpr std::array<std::string_view, (int)FluidHXType::Num> fluidHXTypeNames = {"CrossFlowBothUnMixed",
95 : "CrossFlowBothMixed",
96 : "CrossFlowSupplyMixedDemandUnMixed",
97 : "CrossFlowSupplyUnMixedDemandMixed",
98 : "CounterFlow",
99 : "ParallelFlow",
100 : "Ideal"};
101 : constexpr std::array<std::string_view, (int)FluidHXType::Num> fluidHXTypeNamesUC = {"CROSSFLOWBOTHUNMIXED",
102 : "CROSSFLOWBOTHMIXED",
103 : "CROSSFLOWSUPPLYMIXEDDEMANDUNMIXED",
104 : "CROSSFLOWSUPPLYUNMIXEDDEMANDMIXED",
105 : "COUNTERFLOW",
106 : "PARALLELFLOW",
107 : "IDEAL"};
108 :
109 : constexpr std::array<std::string_view, (int)ControlType::Num> controlTypeNames = {"UncontrolledOn",
110 : "OperationSchemeModulated",
111 : "OperationSchemeOnOff",
112 : "HeatingSetpointModulated",
113 : "HeatingSetpointOnOff",
114 : "CoolingSetpointModulated",
115 : "CoolingSetpointOnOff",
116 : "DualDeadbandSetpointModulated",
117 : "DualDeadbandSetpointOnOff",
118 : "CoolingDifferentialOnOff",
119 : "CoolingSetpointOnOffWithComponentOverride",
120 : "TrackComponentOnOff"};
121 : constexpr std::array<std::string_view, (int)ControlType::Num> controlTypeNamesUC = {"UNCONTROLLEDON",
122 : "OPERATIONSCHEMEMODULATED",
123 : "OPERATIONSCHEMEONOFF",
124 : "HEATINGSETPOINTMODULATED",
125 : "HEATINGSETPOINTONOFF",
126 : "COOLINGSETPOINTMODULATED",
127 : "COOLINGSETPOINTONOFF",
128 : "DUALDEADBANDSETPOINTMODULATED",
129 : "DUALDEADBANDSETPOINTONOFF",
130 : "COOLINGDIFFERENTIALONOFF",
131 : "COOLINGSETPOINTONOFFWITHCOMPONENTOVERRIDE",
132 : "TRACKCOMPONENTONOFF"};
133 :
134 : constexpr std::array<std::string_view, (int)CtrlTempType::Num> ctrlTempTypeNames = {"WetBulbTemperature", "DryBulbTemperature", "Loop"};
135 : constexpr std::array<std::string_view, (int)CtrlTempType::Num> ctrlTempTypeNamesUC = {"WETBULBTEMPERATURE", "DRYBULBTEMPERATURE", "LOOP"};
136 :
137 12 : PlantComponent *HeatExchangerStruct::factory(EnergyPlusData &state, std::string const &objectName)
138 : {
139 : // Process the input data for heat exchangers if it hasn't been done already
140 12 : if (state.dataPlantHXFluidToFluid->GetInput) {
141 2 : GetFluidHeatExchangerInput(state);
142 2 : state.dataPlantHXFluidToFluid->GetInput = false;
143 : }
144 : // Now look for this particular object
145 24 : for (auto &obj : state.dataPlantHXFluidToFluid->FluidHX) {
146 24 : if (obj.Name == objectName) {
147 12 : return &obj;
148 : }
149 24 : }
150 : // If we didn't find it, fatal
151 : ShowFatalError(state, format("LocalPlantFluidHXFactory: Error getting inputs for object named: {}", objectName)); // LCOV_EXCL_LINE
152 : // Shut up the compiler
153 : return nullptr; // LCOV_EXCL_LINE
154 : }
155 :
156 60 : void HeatExchangerStruct::onInitLoopEquip(EnergyPlusData &state, [[maybe_unused]] const PlantLocation &calledFromLocation)
157 : {
158 60 : this->initialize(state);
159 60 : }
160 :
161 60 : void HeatExchangerStruct::getDesignCapacities(
162 : EnergyPlusData &state, const PlantLocation &calledFromLocation, Real64 &MaxLoad, Real64 &MinLoad, Real64 &OptLoad)
163 : {
164 60 : if (calledFromLocation.loopNum == this->DemandSideLoop.loopNum) {
165 30 : MinLoad = 0.0;
166 30 : MaxLoad = this->DemandSideLoop.MaxLoad;
167 30 : OptLoad = this->DemandSideLoop.MaxLoad * 0.9;
168 30 : } else if (calledFromLocation.loopNum == this->SupplySideLoop.loopNum) {
169 30 : this->size(state); // only call sizing from the loop that sizes are based on
170 30 : MinLoad = 0.0;
171 30 : MaxLoad = this->SupplySideLoop.MaxLoad;
172 30 : OptLoad = this->SupplySideLoop.MaxLoad * 0.9;
173 : }
174 60 : }
175 :
176 34940 : void HeatExchangerStruct::simulate(EnergyPlusData &state,
177 : const PlantLocation &calledFromLocation,
178 : bool const FirstHVACIteration,
179 : Real64 &CurLoad,
180 : [[maybe_unused]] bool const RunFlag)
181 : {
182 :
183 : // SUBROUTINE INFORMATION:
184 : // AUTHOR B. Griffith
185 : // DATE WRITTEN November 2012
186 : // MODIFIED na
187 : // RE-ENGINEERED na
188 :
189 : // PURPOSE OF THIS SUBROUTINE:
190 : // Main entry point and simulation manager for heat exchanger
191 :
192 34940 : this->initialize(state);
193 :
194 : // for op scheme led HXs, only call controls if called from Loop Supply Side
195 34940 : if ((this->controlMode == ControlType::OperationSchemeModulated) || (this->controlMode == ControlType::OperationSchemeOnOff)) {
196 0 : if (calledFromLocation.loopNum == this->SupplySideLoop.loopNum) {
197 0 : this->control(state, CurLoad, FirstHVACIteration);
198 : }
199 : } else {
200 34940 : this->control(state, CurLoad, FirstHVACIteration);
201 : }
202 :
203 69880 : this->calculate(state,
204 34940 : state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).MassFlowRate,
205 34940 : state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).MassFlowRate);
206 34940 : }
207 :
208 2 : void GetFluidHeatExchangerInput(EnergyPlusData &state)
209 : {
210 :
211 : // SUBROUTINE INFORMATION:
212 : // AUTHOR B. Griffith
213 : // DATE WRITTEN November 2012
214 : // MODIFIED na
215 : // RE-ENGINEERED na
216 :
217 : // PURPOSE OF THIS SUBROUTINE:
218 : // get input for heat exchanger model
219 :
220 : static constexpr std::string_view RoutineName("GetFluidHeatExchangerInput: ");
221 : static constexpr std::string_view routineName = "GetFluidHeatExchangerInput";
222 :
223 2 : bool ErrorsFound(false);
224 : int NumAlphas; // Number of elements in the alpha array
225 : int NumNums; // Number of elements in the numeric array
226 : int IOStat; // IO Status when calling get input subroutine
227 2 : int MaxNumAlphas(0); // argument for call to GetObjectDefMaxArgs
228 2 : int MaxNumNumbers(0); // argument for call to GetObjectDefMaxArgs
229 2 : int TotalArgs(0); // argument for call to GetObjectDefMaxArgs
230 2 : Array1D_string cAlphaFieldNames;
231 2 : Array1D_string cNumericFieldNames;
232 2 : Array1D_bool lNumericFieldBlanks;
233 2 : Array1D_bool lAlphaFieldBlanks;
234 2 : Array1D_string cAlphaArgs;
235 2 : Array1D<Real64> rNumericArgs;
236 2 : std::string cCurrentModuleObject;
237 :
238 2 : cCurrentModuleObject = "HeatExchanger:FluidToFluid";
239 :
240 2 : state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
241 2 : if (state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs == 0) {
242 0 : return;
243 : }
244 :
245 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
246 2 : MaxNumNumbers = NumNums;
247 2 : MaxNumAlphas = NumAlphas;
248 :
249 2 : cAlphaFieldNames.allocate(MaxNumAlphas);
250 2 : cAlphaArgs.allocate(MaxNumAlphas);
251 2 : lAlphaFieldBlanks.dimension(MaxNumAlphas, false);
252 2 : cNumericFieldNames.allocate(MaxNumNumbers);
253 2 : rNumericArgs.dimension(MaxNumNumbers, 0.0);
254 2 : lNumericFieldBlanks.dimension(MaxNumNumbers, false);
255 :
256 2 : if (state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs > 0) {
257 2 : state.dataPlantHXFluidToFluid->FluidHX.allocate(state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs);
258 8 : for (int CompLoop = 1; CompLoop <= state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs; ++CompLoop) {
259 6 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
260 : cCurrentModuleObject,
261 : CompLoop,
262 : cAlphaArgs,
263 : NumAlphas,
264 : rNumericArgs,
265 : NumNums,
266 : IOStat,
267 : lNumericFieldBlanks,
268 : lAlphaFieldBlanks,
269 : cAlphaFieldNames,
270 : cNumericFieldNames);
271 :
272 6 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)};
273 :
274 6 : Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
275 :
276 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).Name = cAlphaArgs(1);
277 :
278 6 : if (lAlphaFieldBlanks(2)) {
279 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).availSched = Sched::GetScheduleAlwaysOn(state);
280 6 : } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) {
281 0 : ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2));
282 0 : ErrorsFound = true;
283 : }
284 :
285 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.inletNodeNum =
286 12 : NodeInputManager::GetOnlySingleNode(state,
287 6 : cAlphaArgs(3),
288 : ErrorsFound,
289 : DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
290 6 : cAlphaArgs(1),
291 : DataLoopNode::NodeFluidType::Water,
292 : DataLoopNode::ConnectionType::Inlet,
293 : NodeInputManager::CompFluidStream::Primary,
294 : DataLoopNode::ObjectIsNotParent);
295 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.outletNodeNum =
296 18 : NodeInputManager::GetOnlySingleNode(state,
297 6 : cAlphaArgs(4),
298 : ErrorsFound,
299 : DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
300 6 : cAlphaArgs(1),
301 : DataLoopNode::NodeFluidType::Water,
302 : DataLoopNode::ConnectionType::Outlet,
303 : NodeInputManager::CompFluidStream::Primary,
304 : DataLoopNode::ObjectIsNotParent);
305 12 : BranchNodeConnections::TestCompSet(
306 6 : state, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(3), cAlphaArgs(4), "Loop Demand Side Plant Nodes");
307 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.DesignVolumeFlowRate = rNumericArgs(1);
308 6 : if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.DesignVolumeFlowRate == DataSizing::AutoSize) {
309 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.DesignVolumeFlowRateWasAutoSized = true;
310 : }
311 :
312 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.inletNodeNum =
313 12 : NodeInputManager::GetOnlySingleNode(state,
314 6 : cAlphaArgs(5),
315 : ErrorsFound,
316 : DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
317 6 : cAlphaArgs(1),
318 : DataLoopNode::NodeFluidType::Water,
319 : DataLoopNode::ConnectionType::Inlet,
320 : NodeInputManager::CompFluidStream::Secondary,
321 : DataLoopNode::ObjectIsNotParent);
322 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.outletNodeNum =
323 18 : NodeInputManager::GetOnlySingleNode(state,
324 6 : cAlphaArgs(6),
325 : ErrorsFound,
326 : DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
327 6 : cAlphaArgs(1),
328 : DataLoopNode::NodeFluidType::Water,
329 : DataLoopNode::ConnectionType::Outlet,
330 : NodeInputManager::CompFluidStream::Secondary,
331 : DataLoopNode::ObjectIsNotParent);
332 12 : BranchNodeConnections::TestCompSet(
333 6 : state, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(5), cAlphaArgs(6), "Loop Supply Side Plant Nodes");
334 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.DesignVolumeFlowRate = rNumericArgs(2);
335 6 : if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.DesignVolumeFlowRate == DataSizing::AutoSize) {
336 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.DesignVolumeFlowRateWasAutoSized = true;
337 : }
338 :
339 6 : if (lAlphaFieldBlanks(7)) {
340 0 : ShowSevereEmptyField(state, eoh, cAlphaFieldNames(7), cAlphaArgs(7));
341 0 : ErrorsFound = true;
342 6 : } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatExchangeModelType =
343 12 : static_cast<FluidHXType>(getEnumValue(fluidHXTypeNamesUC, cAlphaArgs(7)))) == FluidHXType::Invalid) {
344 0 : ShowSevereInvalidKey(state, eoh, cAlphaFieldNames(7), cAlphaArgs(7));
345 0 : ErrorsFound = true;
346 : }
347 :
348 6 : if (!lNumericFieldBlanks(3)) {
349 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).UA = rNumericArgs(3);
350 6 : if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).UA == DataSizing::AutoSize) {
351 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).UAWasAutoSized = true;
352 : }
353 : } else {
354 0 : if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatExchangeModelType != FluidHXType::Ideal) {
355 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid entry.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
356 0 : ShowContinueError(state, format("Missing entry for {}", cNumericFieldNames(3)));
357 0 : ErrorsFound = true;
358 : }
359 : }
360 :
361 6 : if (lAlphaFieldBlanks(8)) {
362 0 : ShowSevereEmptyField(state, eoh, cAlphaFieldNames(8));
363 0 : ErrorsFound = true;
364 6 : } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode =
365 12 : static_cast<ControlType>(getEnumValue(controlTypeNamesUC, cAlphaArgs(8)))) == ControlType::Invalid) {
366 0 : ShowSevereInvalidKey(state, eoh, cAlphaFieldNames(8), cAlphaArgs(8));
367 0 : ErrorsFound = true;
368 : }
369 :
370 6 : if (!lAlphaFieldBlanks(9)) {
371 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum =
372 12 : NodeInputManager::GetOnlySingleNode(state,
373 6 : cAlphaArgs(9),
374 : ErrorsFound,
375 : DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
376 6 : cAlphaArgs(1),
377 : DataLoopNode::NodeFluidType::Water,
378 : DataLoopNode::ConnectionType::Sensor,
379 : NodeInputManager::CompFluidStream::Primary,
380 : DataLoopNode::ObjectIsNotParent);
381 : // check that node actually has setpoints on it
382 6 : if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointModulated) ||
383 4 : (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointOnOff) ||
384 4 : (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointModulated) ||
385 12 : (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOff) ||
386 2 : (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride)) {
387 4 : if (state.dataLoopNodes->Node(state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum).TempSetPoint ==
388 : DataLoopNode::SensedNodeFlagValue) {
389 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
390 0 : ShowSevereError(state, format("{} Missing temperature setpoint for DataLoopNode::Node = {}", RoutineName, cAlphaArgs(9)));
391 0 : ShowContinueError(state, format("Occurs for {}=\"{}", cCurrentModuleObject, cAlphaArgs(1)));
392 0 : ShowContinueError(state, " Use a setpoint manager to place a single temperature setpoint on the node");
393 0 : ErrorsFound = true;
394 : } else {
395 : // need call to EMS to check node
396 0 : bool NodeEMSSetPointMissing = false;
397 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state,
398 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum,
399 : HVAC::CtrlVarType::Temp,
400 : NodeEMSSetPointMissing);
401 0 : if (NodeEMSSetPointMissing) {
402 0 : ShowSevereError(state, format("{} Missing temperature setpoint for node = {}", RoutineName, cAlphaArgs(9)));
403 0 : ShowContinueError(state, format("Occurs for {}=\"{}", cCurrentModuleObject, cAlphaArgs(1)));
404 0 : ShowContinueError(state, "Use a setpoint manager or EMS actuator to place a single temperature setpoint on the node");
405 0 : ErrorsFound = true;
406 : }
407 : }
408 : }
409 2 : } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointModulated) ||
410 0 : (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointOnOff)) {
411 2 : if ((state.dataLoopNodes->Node(state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum).TempSetPointHi ==
412 4 : DataLoopNode::SensedNodeFlagValue) ||
413 2 : (state.dataLoopNodes->Node(state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum).TempSetPointLo ==
414 : DataLoopNode::SensedNodeFlagValue)) {
415 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
416 0 : ShowSevereError(state, format("{} Missing dual temperature setpoints for node = {}", RoutineName, cAlphaArgs(9)));
417 0 : ShowContinueError(state, format("Occurs for {}=\"{}", cCurrentModuleObject, cAlphaArgs(1)));
418 0 : ShowContinueError(state, " Use a setpoint manager to place a dual temperature setpoint on the node");
419 0 : ErrorsFound = true;
420 : } else {
421 : // need call to EMS to check node
422 0 : bool NodeEMSSetPointMissing = false;
423 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state,
424 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum,
425 : HVAC::CtrlVarType::Temp,
426 : NodeEMSSetPointMissing);
427 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state,
428 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum,
429 : HVAC::CtrlVarType::Temp,
430 : NodeEMSSetPointMissing);
431 0 : if (NodeEMSSetPointMissing) {
432 0 : ShowSevereError(state, format("{} Missing temperature setpoint for node = {}", RoutineName, cAlphaArgs(9)));
433 0 : ShowContinueError(state, format("Occurs for {}=\"{}", cCurrentModuleObject, cAlphaArgs(1)));
434 0 : ShowContinueError(state, "Use a setpoint manager or EMS actuators to place a dual temperature setpoints on the node");
435 0 : ErrorsFound = true;
436 : }
437 : }
438 : }
439 : }
440 :
441 : } else {
442 : // need to name a setpoint node if using a setpoint type control mode
443 0 : if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointModulated) ||
444 0 : (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointOnOff) ||
445 0 : (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointModulated) ||
446 0 : (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOff) ||
447 0 : (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointModulated) ||
448 0 : (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointOnOff) ||
449 0 : (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride)) {
450 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid entry.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
451 0 : ShowContinueError(state, format("Missing entry for {}", cAlphaFieldNames(9)));
452 0 : ErrorsFound = true;
453 : }
454 : }
455 :
456 6 : if (!lNumericFieldBlanks(4)) {
457 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).TempControlTol = rNumericArgs(4);
458 : } else {
459 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).TempControlTol = 0.01;
460 : }
461 :
462 6 : std::string endUseCat = Util::makeUPPER(cAlphaArgs(10));
463 6 : if (endUseCat == "FREECOOLING") {
464 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::FreeCooling;
465 6 : } else if (endUseCat == "HEATREJECTION") {
466 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::HeatRejection;
467 6 : } else if (endUseCat == "HEATRECOVERYFORCOOLING") {
468 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::HeatRecoveryForCooling;
469 6 : } else if (endUseCat == "HEATRECOVERYFORCOOLING") {
470 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::HeatRecoveryForHeating;
471 6 : } else if (endUseCat == "LOOPTOLOOP") {
472 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::LoopToLoop;
473 : } else {
474 0 : ShowWarningError(
475 : state,
476 0 : format("{} = {}, {} is an invalid value for {}", cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(10), cAlphaFieldNames(10)));
477 0 : ErrorsFound = true;
478 : }
479 :
480 6 : if (!lAlphaFieldBlanks(11)) {
481 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).OtherCompSupplySideLoop.inletNodeNum =
482 0 : NodeInputManager::GetOnlySingleNode(state,
483 0 : cAlphaArgs(11),
484 : ErrorsFound,
485 : DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
486 0 : cAlphaArgs(1),
487 : DataLoopNode::NodeFluidType::Water,
488 : DataLoopNode::ConnectionType::Actuator,
489 : NodeInputManager::CompFluidStream::Primary,
490 : DataLoopNode::ObjectIsNotParent);
491 : } else {
492 6 : if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride) {
493 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid entry.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
494 0 : ShowContinueError(state, format("Missing entry for {}", cAlphaFieldNames(11)));
495 0 : ErrorsFound = true;
496 : }
497 : }
498 :
499 6 : if (!lAlphaFieldBlanks(12)) {
500 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).OtherCompDemandSideLoop.inletNodeNum =
501 0 : NodeInputManager::GetOnlySingleNode(state,
502 0 : cAlphaArgs(12),
503 : ErrorsFound,
504 : DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
505 0 : cAlphaArgs(1),
506 : DataLoopNode::NodeFluidType::Water,
507 : DataLoopNode::ConnectionType::Actuator,
508 : NodeInputManager::CompFluidStream::Primary,
509 : DataLoopNode::ObjectIsNotParent);
510 : } else {
511 6 : if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride) {
512 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid entry.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
513 0 : ShowContinueError(state, format("Missing entry for {}", cAlphaFieldNames(12)));
514 0 : ErrorsFound = true;
515 : }
516 : }
517 :
518 6 : if (lAlphaFieldBlanks(13)) {
519 6 : if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride) {
520 0 : ShowSevereEmptyField(state, eoh, cAlphaFieldNames(13), cAlphaFieldNames(8), cAlphaArgs(8));
521 0 : ErrorsFound = true;
522 : }
523 0 : } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).ControlSignalTemp =
524 0 : static_cast<CtrlTempType>(getEnumValue(ctrlTempTypeNamesUC, cAlphaArgs(13)))) == CtrlTempType::Invalid) {
525 0 : ShowSevereInvalidKey(state, eoh, cAlphaFieldNames(13), cAlphaArgs(13));
526 0 : ErrorsFound = true;
527 : }
528 :
529 6 : if (!lNumericFieldBlanks(5)) {
530 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SizingFactor = rNumericArgs(5);
531 : } else {
532 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SizingFactor = 1.0;
533 : }
534 :
535 6 : if (!lNumericFieldBlanks(6)) {
536 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MinOperationTemp = rNumericArgs(6);
537 : } else {
538 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MinOperationTemp = -9999.0;
539 : }
540 :
541 6 : if (!lNumericFieldBlanks(7)) {
542 0 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MaxOperationTemp = rNumericArgs(7);
543 : } else {
544 6 : state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MaxOperationTemp = 9999.0;
545 : }
546 6 : }
547 : }
548 :
549 2 : if (ErrorsFound) {
550 0 : ShowFatalError(state, format("{}Errors found in processing {} input.", RoutineName, cCurrentModuleObject));
551 : }
552 2 : }
553 :
554 7 : void HeatExchangerStruct::setupOutputVars(EnergyPlusData &state)
555 : {
556 14 : SetupOutputVariable(state,
557 : "Fluid Heat Exchanger Heat Transfer Rate",
558 : Constant::Units::W,
559 7 : this->HeatTransferRate,
560 : OutputProcessor::TimeStepType::System,
561 : OutputProcessor::StoreType::Average,
562 7 : this->Name);
563 :
564 14 : SetupOutputVariable(state,
565 : "Fluid Heat Exchanger Heat Transfer Energy",
566 : Constant::Units::J,
567 7 : this->HeatTransferEnergy,
568 : OutputProcessor::TimeStepType::System,
569 : OutputProcessor::StoreType::Sum,
570 7 : this->Name,
571 : Constant::eResource::EnergyTransfer,
572 : OutputProcessor::Group::Plant,
573 : this->HeatTransferMeteringEndUse);
574 :
575 14 : SetupOutputVariable(state,
576 : "Fluid Heat Exchanger Loop Supply Side Mass Flow Rate",
577 : Constant::Units::kg_s,
578 7 : this->SupplySideLoop.InletMassFlowRate,
579 : OutputProcessor::TimeStepType::System,
580 : OutputProcessor::StoreType::Average,
581 7 : this->Name);
582 :
583 14 : SetupOutputVariable(state,
584 : "Fluid Heat Exchanger Loop Supply Side Inlet Temperature",
585 : Constant::Units::C,
586 7 : this->SupplySideLoop.InletTemp,
587 : OutputProcessor::TimeStepType::System,
588 : OutputProcessor::StoreType::Average,
589 7 : this->Name);
590 :
591 14 : SetupOutputVariable(state,
592 : "Fluid Heat Exchanger Loop Supply Side Outlet Temperature",
593 : Constant::Units::C,
594 7 : this->SupplySideLoop.OutletTemp,
595 : OutputProcessor::TimeStepType::System,
596 : OutputProcessor::StoreType::Average,
597 7 : this->Name);
598 :
599 14 : SetupOutputVariable(state,
600 : "Fluid Heat Exchanger Loop Demand Side Mass Flow Rate",
601 : Constant::Units::kg_s,
602 7 : this->DemandSideLoop.InletMassFlowRate,
603 : OutputProcessor::TimeStepType::System,
604 : OutputProcessor::StoreType::Average,
605 7 : this->Name);
606 :
607 14 : SetupOutputVariable(state,
608 : "Fluid Heat Exchanger Loop Demand Side Inlet Temperature",
609 : Constant::Units::C,
610 7 : this->DemandSideLoop.InletTemp,
611 : OutputProcessor::TimeStepType::System,
612 : OutputProcessor::StoreType::Average,
613 7 : this->Name);
614 :
615 14 : SetupOutputVariable(state,
616 : "Fluid Heat Exchanger Loop Demand Side Outlet Temperature",
617 : Constant::Units::C,
618 7 : this->DemandSideLoop.OutletTemp,
619 : OutputProcessor::TimeStepType::System,
620 : OutputProcessor::StoreType::Average,
621 7 : this->Name);
622 :
623 14 : SetupOutputVariable(state,
624 : "Fluid Heat Exchanger Operation Status",
625 : Constant::Units::None,
626 7 : this->OperationStatus,
627 : OutputProcessor::TimeStepType::System,
628 : OutputProcessor::StoreType::Average,
629 7 : this->Name);
630 :
631 14 : SetupOutputVariable(state,
632 : "Fluid Heat Exchanger Effectiveness",
633 : Constant::Units::None,
634 7 : this->Effectiveness,
635 : OutputProcessor::TimeStepType::System,
636 : OutputProcessor::StoreType::Average,
637 7 : this->Name);
638 7 : }
639 :
640 35002 : void HeatExchangerStruct::initialize(EnergyPlusData &state)
641 : {
642 :
643 : // SUBROUTINE INFORMATION:
644 : // AUTHOR B. Griffith
645 : // DATE WRITTEN november, 2012
646 : // MODIFIED na
647 : // RE-ENGINEERED na
648 :
649 : // PURPOSE OF THIS SUBROUTINE:
650 : // Initialize heat exchanger model
651 :
652 : static constexpr std::string_view RoutineNameNoColon("InitFluidHeatExchanger");
653 :
654 35002 : this->oneTimeInit(state); // plant setup
655 :
656 35002 : if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
657 :
658 12 : Real64 rho = this->DemandSideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineNameNoColon);
659 12 : this->DemandSideLoop.MassFlowRateMax = rho * this->DemandSideLoop.DesignVolumeFlowRate;
660 12 : PlantUtilities::InitComponentNodes(state,
661 : this->DemandSideLoop.MassFlowRateMin,
662 : this->DemandSideLoop.MassFlowRateMax,
663 : this->DemandSideLoop.inletNodeNum,
664 : this->DemandSideLoop.outletNodeNum);
665 :
666 12 : rho = this->SupplySideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineNameNoColon);
667 12 : this->SupplySideLoop.MassFlowRateMax = rho * this->SupplySideLoop.DesignVolumeFlowRate;
668 12 : PlantUtilities::InitComponentNodes(state,
669 : this->SupplySideLoop.MassFlowRateMin,
670 : this->SupplySideLoop.MassFlowRateMax,
671 : this->SupplySideLoop.inletNodeNum,
672 : this->SupplySideLoop.outletNodeNum);
673 12 : this->MyEnvrnFlag = false;
674 : }
675 35002 : if (!state.dataGlobal->BeginEnvrnFlag) {
676 34642 : this->MyEnvrnFlag = true;
677 : }
678 :
679 35002 : this->DemandSideLoop.InletTemp = state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp;
680 35002 : this->SupplySideLoop.InletTemp = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp;
681 :
682 35002 : if (this->controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride) {
683 : // store current value for setpoint in central plant loop data structure
684 2 : this->OtherCompSupplySideLoop.comp->FreeCoolCntrlMinCntrlTemp =
685 2 : state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint - this->TempControlTol; // issue #5626, include control tolerance
686 : }
687 35002 : }
688 :
689 30 : void HeatExchangerStruct::size(EnergyPlusData &state)
690 : {
691 :
692 : // SUBROUTINE INFORMATION:
693 : // AUTHOR B. Griffith
694 : // DATE WRITTEN December 2012
695 : // MODIFIED na
696 : // RE-ENGINEERED na
697 :
698 : // PURPOSE OF THIS SUBROUTINE:
699 : // Size plant heat exchanger flow rates, UA, and max capacity
700 :
701 : // METHODOLOGY EMPLOYED:
702 : // the supply side flow rate is obtained from the plant sizing structure
703 : // the demand side is sized to match the supply side
704 : // the UA is sized for an effectiveness of 1.0 using sizing temps
705 : // the capacity uses the full HX model
706 :
707 : static constexpr std::string_view RoutineName("SizeFluidHeatExchanger");
708 :
709 : // first deal with Loop Supply Side
710 30 : int PltSizNumSupSide = this->SupplySideLoop.loop->PlantSizNum;
711 30 : int PltSizNumDmdSide = this->DemandSideLoop.loop->PlantSizNum;
712 30 : Real64 tmpSupSideDesignVolFlowRate = this->SupplySideLoop.DesignVolumeFlowRate;
713 30 : if (this->SupplySideLoop.DesignVolumeFlowRateWasAutoSized) {
714 0 : if (PltSizNumSupSide > 0) {
715 0 : if (state.dataSize->PlantSizData(PltSizNumSupSide).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
716 0 : tmpSupSideDesignVolFlowRate = state.dataSize->PlantSizData(PltSizNumSupSide).DesVolFlowRate * this->SizingFactor;
717 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
718 0 : this->SupplySideLoop.DesignVolumeFlowRate = tmpSupSideDesignVolFlowRate;
719 : }
720 : } else {
721 0 : tmpSupSideDesignVolFlowRate = 0.0;
722 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
723 0 : this->SupplySideLoop.DesignVolumeFlowRate = tmpSupSideDesignVolFlowRate;
724 : }
725 : }
726 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
727 0 : BaseSizer::reportSizerOutput(state,
728 : "HeatExchanger:FluidToFluid",
729 : this->Name,
730 : "Loop Supply Side Design Fluid Flow Rate [m3/s]",
731 : this->SupplySideLoop.DesignVolumeFlowRate);
732 : }
733 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
734 0 : BaseSizer::reportSizerOutput(state,
735 : "HeatExchanger:FluidToFluid",
736 : this->Name,
737 : "Initial Loop Supply Side Design Fluid Flow Rate [m3/s]",
738 : this->SupplySideLoop.DesignVolumeFlowRate);
739 : }
740 : } else {
741 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
742 0 : ShowSevereError(state, "SizeFluidHeatExchanger: Autosizing of requires a loop Sizing:Plant object");
743 0 : ShowContinueError(state, format("Occurs in heat exchanger object={}", this->Name));
744 : }
745 : }
746 : }
747 30 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->SupplySideLoop.inletNodeNum, tmpSupSideDesignVolFlowRate);
748 :
749 : // second deal with Loop Demand Side
750 30 : Real64 tmpDmdSideDesignVolFlowRate = this->DemandSideLoop.DesignVolumeFlowRate;
751 30 : if (this->DemandSideLoop.DesignVolumeFlowRateWasAutoSized) {
752 0 : if (tmpSupSideDesignVolFlowRate > HVAC::SmallWaterVolFlow) {
753 0 : tmpDmdSideDesignVolFlowRate = tmpSupSideDesignVolFlowRate;
754 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
755 0 : this->DemandSideLoop.DesignVolumeFlowRate = tmpDmdSideDesignVolFlowRate;
756 : }
757 : } else {
758 0 : tmpDmdSideDesignVolFlowRate = 0.0;
759 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
760 0 : this->DemandSideLoop.DesignVolumeFlowRate = tmpDmdSideDesignVolFlowRate;
761 : }
762 : }
763 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
764 0 : BaseSizer::reportSizerOutput(state,
765 : "HeatExchanger:FluidToFluid",
766 : this->Name,
767 : "Loop Demand Side Design Fluid Flow Rate [m3/s]",
768 : this->DemandSideLoop.DesignVolumeFlowRate);
769 : }
770 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
771 0 : BaseSizer::reportSizerOutput(state,
772 : "HeatExchanger:FluidToFluid",
773 : this->Name,
774 : "Initial Loop Demand Side Design Fluid Flow Rate [m3/s]",
775 : this->DemandSideLoop.DesignVolumeFlowRate);
776 : }
777 : }
778 30 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->DemandSideLoop.inletNodeNum, tmpDmdSideDesignVolFlowRate);
779 :
780 : // size UA if needed
781 30 : if (this->UAWasAutoSized) {
782 : // get nominal delta T between two loops
783 0 : if (PltSizNumSupSide > 0 && PltSizNumDmdSide > 0) {
784 :
785 0 : Real64 tmpDeltaTloopToLoop(0.0);
786 :
787 0 : switch (state.dataSize->PlantSizData(PltSizNumSupSide).LoopType) {
788 :
789 0 : case DataSizing::TypeOfPlantLoop::Heating:
790 : case DataSizing::TypeOfPlantLoop::Steam: {
791 : tmpDeltaTloopToLoop =
792 0 : std::abs((state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp - state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT) -
793 0 : state.dataSize->PlantSizData(PltSizNumDmdSide).ExitTemp);
794 0 : break;
795 : }
796 0 : case DataSizing::TypeOfPlantLoop::Cooling:
797 : case DataSizing::TypeOfPlantLoop::Condenser: {
798 : tmpDeltaTloopToLoop =
799 0 : std::abs((state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp + state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT) -
800 0 : state.dataSize->PlantSizData(PltSizNumDmdSide).ExitTemp);
801 0 : break;
802 : }
803 0 : default:
804 0 : assert(false);
805 : break;
806 : }
807 :
808 0 : tmpDeltaTloopToLoop = max(2.0, tmpDeltaTloopToLoop);
809 0 : Real64 tmpDeltaTSupLoop = state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT;
810 0 : if (tmpSupSideDesignVolFlowRate >= HVAC::SmallWaterVolFlow) {
811 :
812 0 : Real64 Cp = this->SupplySideLoop.loop->glycol->getSpecificHeat(state, Constant::InitConvTemp, RoutineName);
813 :
814 0 : Real64 rho = this->SupplySideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
815 :
816 0 : Real64 tmpDesCap = Cp * rho * tmpDeltaTSupLoop * tmpSupSideDesignVolFlowRate;
817 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
818 0 : this->UA = tmpDesCap / tmpDeltaTloopToLoop;
819 : }
820 : } else {
821 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
822 0 : this->UA = 0.0;
823 : }
824 : }
825 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
826 0 : BaseSizer::reportSizerOutput(
827 : state, "HeatExchanger:FluidToFluid", this->Name, "Heat Exchanger U-Factor Times Area Value [W/C]", this->UA);
828 0 : BaseSizer::reportSizerOutput(state,
829 : "HeatExchanger:FluidToFluid",
830 : this->Name,
831 : "Loop-to-loop Temperature Difference Used to Size Heat Exchanger U-Factor Times Area Value [C]",
832 : tmpDeltaTloopToLoop);
833 : }
834 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
835 0 : BaseSizer::reportSizerOutput(
836 : state, "HeatExchanger:FluidToFluid", this->Name, "Initial Heat Exchanger U-Factor Times Area Value [W/C]", this->UA);
837 0 : BaseSizer::reportSizerOutput(state,
838 : "HeatExchanger:FluidToFluid",
839 : this->Name,
840 : "Initial Loop-to-loop Temperature Difference Used to Size Heat Exchanger U-Factor Times Area Value [C]",
841 : tmpDeltaTloopToLoop);
842 : }
843 0 : } else {
844 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
845 0 : ShowSevereError(state, "SizeFluidHeatExchanger: Autosizing of heat Exchanger UA requires a loop Sizing:Plant objects for both loops");
846 0 : ShowContinueError(state, format("Occurs in heat exchanger object={}", this->Name));
847 : }
848 : }
849 : }
850 :
851 : // size capacities for load range based op schemes
852 30 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
853 :
854 6 : if (PltSizNumSupSide > 0) {
855 0 : switch (state.dataSize->PlantSizData(PltSizNumSupSide).LoopType) {
856 0 : case DataSizing::TypeOfPlantLoop::Heating:
857 : case DataSizing::TypeOfPlantLoop::Steam: {
858 0 : state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
859 0 : (state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp - state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT);
860 0 : break;
861 : }
862 0 : case DataSizing::TypeOfPlantLoop::Cooling:
863 : case DataSizing::TypeOfPlantLoop::Condenser: {
864 0 : state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
865 0 : (state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp + state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT);
866 0 : break;
867 : }
868 0 : default:
869 0 : break;
870 : }
871 :
872 : } else { // don't rely on sizing, use loop setpoints
873 : // loop supply side
874 6 : if (this->SupplySideLoop.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
875 4 : state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
876 4 : state.dataLoopNodes->Node(this->SupplySideLoop.loop->TempSetPointNodeNum).TempSetPoint;
877 2 : } else if (this->SupplySideLoop.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
878 2 : state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
879 2 : (state.dataLoopNodes->Node(this->SupplySideLoop.loop->TempSetPointNodeNum).TempSetPointHi +
880 2 : state.dataLoopNodes->Node(this->SupplySideLoop.loop->TempSetPointNodeNum).TempSetPointLo) /
881 : 2.0;
882 : }
883 : }
884 :
885 6 : if (PltSizNumDmdSide > 0) {
886 0 : state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp = state.dataSize->PlantSizData(PltSizNumDmdSide).ExitTemp;
887 : } else { // don't rely on sizing, use loop setpoints
888 : // loop demand side
889 6 : if (this->DemandSideLoop.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
890 2 : state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp =
891 2 : state.dataLoopNodes->Node(this->DemandSideLoop.loop->TempSetPointNodeNum).TempSetPoint;
892 4 : } else if (this->DemandSideLoop.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
893 4 : state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp =
894 4 : (state.dataLoopNodes->Node(this->DemandSideLoop.loop->TempSetPointNodeNum).TempSetPointHi +
895 4 : state.dataLoopNodes->Node(this->DemandSideLoop.loop->TempSetPointNodeNum).TempSetPointLo) /
896 : 2.0;
897 : }
898 : }
899 :
900 6 : Real64 rho = this->SupplySideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
901 6 : Real64 SupSideMdot = this->SupplySideLoop.DesignVolumeFlowRate * rho;
902 6 : rho = this->DemandSideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
903 6 : Real64 DmdSideMdot = this->DemandSideLoop.DesignVolumeFlowRate * rho;
904 :
905 6 : this->calculate(state, SupSideMdot, DmdSideMdot);
906 6 : this->SupplySideLoop.MaxLoad = std::abs(this->HeatTransferRate);
907 : }
908 30 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
909 6 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechType, this->Name, "HeatExchanger:FluidToFluid");
910 6 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->SupplySideLoop.MaxLoad);
911 : }
912 30 : }
913 :
914 34942 : void HeatExchangerStruct::control(EnergyPlusData &state, Real64 MyLoad, bool FirstHVACIteration)
915 : {
916 :
917 : // SUBROUTINE INFORMATION:
918 : // AUTHOR B. Griffith
919 : // DATE WRITTEN November 2012
920 : // MODIFIED na
921 : // RE-ENGINEERED na
922 :
923 : // PURPOSE OF THIS SUBROUTINE:
924 : // determine control state for fluid to fluid heat exchanger
925 : // make fluid flow requests accordingly
926 :
927 : // METHODOLOGY EMPLOYED:
928 : // long CASE statement for different control options
929 :
930 : static constexpr std::string_view RoutineName("ControlFluidHeatExchanger");
931 :
932 : Real64 mdotSupSide;
933 : Real64 mdotDmdSide;
934 :
935 : // check if available by schedule
936 : bool ScheduledOff;
937 34942 : Real64 AvailSchedValue = this->availSched->getCurrentVal();
938 34942 : if (AvailSchedValue <= 0) {
939 0 : ScheduledOff = true;
940 : } else {
941 34942 : ScheduledOff = false;
942 : }
943 :
944 : // check if operational limits trip off unit
945 34942 : bool LimitTrippedOff = false;
946 69884 : if ((state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp < this->MinOperationTemp) ||
947 34942 : (state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp < this->MinOperationTemp)) {
948 0 : LimitTrippedOff = true;
949 : }
950 69884 : if ((state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp > this->MaxOperationTemp) ||
951 34942 : (state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp > this->MaxOperationTemp)) {
952 0 : LimitTrippedOff = true;
953 : }
954 :
955 34942 : if (!ScheduledOff && !LimitTrippedOff) {
956 :
957 34942 : switch (this->controlMode) {
958 :
959 0 : case ControlType::UncontrolledOn: {
960 :
961 : // make passive request for supply side loop flow
962 0 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
963 0 : PlantUtilities::SetComponentFlowRate(
964 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
965 0 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
966 : // if supply side loop has massflow, request demand side flow
967 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
968 : } else {
969 0 : mdotDmdSide = 0.0;
970 : }
971 0 : PlantUtilities::SetComponentFlowRate(
972 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
973 :
974 0 : break;
975 : }
976 0 : case ControlType::OperationSchemeModulated: {
977 :
978 0 : if (std::abs(MyLoad) > HVAC::SmallLoad) {
979 0 : if (MyLoad < -1.0 * HVAC::SmallLoad) { // requesting cooling
980 0 : Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
981 0 : if (DeltaTCooling > this->TempControlTol) { // can do cooling so turn on
982 0 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
983 0 : PlantUtilities::SetComponentFlowRate(
984 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
985 0 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
986 : // if supply side loop has massflow, request demand side flow
987 0 : Real64 cp = this->SupplySideLoop.loop->glycol->getSpecificHeat(state, this->SupplySideLoop.InletTemp, RoutineName);
988 0 : Real64 TargetLeavingTemp = this->SupplySideLoop.InletTemp - std::abs(MyLoad) / (cp * mdotSupSide);
989 :
990 0 : this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::CoolingSupplySideLoop);
991 : } else { // no flow on supply side so do not request flow on demand side
992 0 : mdotDmdSide = 0.0;
993 0 : PlantUtilities::SetComponentFlowRate(
994 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
995 : }
996 : } else { // not able to cool so turn off
997 0 : mdotSupSide = 0.0;
998 0 : PlantUtilities::SetComponentFlowRate(
999 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1000 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a
1001 : // fresh demand side inlet temperature value
1002 0 : if (FirstHVACIteration) {
1003 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1004 : } else {
1005 0 : mdotDmdSide = 0.0;
1006 : }
1007 0 : PlantUtilities::SetComponentFlowRate(
1008 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1009 : }
1010 :
1011 : } else { // requesting heating
1012 0 : Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
1013 0 : if (DeltaTHeating > this->TempControlTol) { // can do heating so turn on
1014 0 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1015 0 : PlantUtilities::SetComponentFlowRate(
1016 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1017 0 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1018 0 : Real64 cp = this->SupplySideLoop.loop->glycol->getSpecificHeat(state, this->SupplySideLoop.InletTemp, RoutineName);
1019 0 : Real64 TargetLeavingTemp = this->SupplySideLoop.InletTemp + std::abs(MyLoad) / (cp * mdotSupSide);
1020 :
1021 0 : this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::HeatingSupplySideLoop);
1022 : } else { // no flow on supply side so do not request flow on demand side
1023 0 : mdotDmdSide = 0.0;
1024 0 : PlantUtilities::SetComponentFlowRate(
1025 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1026 : }
1027 : } else { // not able to heat so turn off
1028 0 : mdotSupSide = 0.0;
1029 0 : PlantUtilities::SetComponentFlowRate(
1030 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1031 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a
1032 : // fresh demand side inlet temperature value
1033 0 : if (FirstHVACIteration) {
1034 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1035 : } else {
1036 0 : mdotDmdSide = 0.0;
1037 : }
1038 0 : PlantUtilities::SetComponentFlowRate(
1039 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1040 : }
1041 : }
1042 :
1043 : } else { // no load
1044 0 : mdotSupSide = 0.0;
1045 0 : PlantUtilities::SetComponentFlowRate(
1046 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1047 0 : mdotDmdSide = 0.0;
1048 0 : PlantUtilities::SetComponentFlowRate(
1049 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1050 : }
1051 :
1052 0 : break;
1053 : }
1054 0 : case ControlType::OperationSchemeOnOff: {
1055 0 : if (std::abs(MyLoad) > HVAC::SmallLoad) {
1056 0 : if (MyLoad < HVAC::SmallLoad) { // requesting cooling
1057 0 : Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
1058 0 : if (DeltaTCooling > this->TempControlTol) { // can do cooling so turn on
1059 0 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1060 0 : PlantUtilities::SetComponentFlowRate(
1061 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1062 0 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1063 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1064 : } else {
1065 0 : mdotDmdSide = 0.0;
1066 : }
1067 :
1068 0 : PlantUtilities::SetComponentFlowRate(
1069 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1070 : } else { // not able to cool so turn off
1071 0 : mdotSupSide = 0.0;
1072 0 : PlantUtilities::SetComponentFlowRate(
1073 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1074 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a
1075 : // fresh demand side inlet temperature value
1076 0 : if (FirstHVACIteration) {
1077 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1078 : } else {
1079 0 : mdotDmdSide = 0.0;
1080 : }
1081 0 : PlantUtilities::SetComponentFlowRate(
1082 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1083 : }
1084 :
1085 : } else { // requesting heating
1086 0 : Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
1087 0 : if (DeltaTHeating > this->TempControlTol) { // can do heating so turn on
1088 0 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1089 0 : PlantUtilities::SetComponentFlowRate(
1090 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1091 0 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1092 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1093 : } else {
1094 0 : mdotDmdSide = 0.0;
1095 : }
1096 0 : PlantUtilities::SetComponentFlowRate(
1097 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1098 : } else { // not able to heat so turn off
1099 0 : mdotSupSide = 0.0;
1100 0 : PlantUtilities::SetComponentFlowRate(
1101 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1102 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a
1103 : // fresh demand side inlet temperature value
1104 0 : if (FirstHVACIteration) {
1105 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1106 : } else {
1107 0 : mdotDmdSide = 0.0;
1108 : }
1109 0 : PlantUtilities::SetComponentFlowRate(
1110 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1111 : }
1112 : }
1113 :
1114 : } else { // no load
1115 0 : mdotSupSide = 0.0;
1116 0 : PlantUtilities::SetComponentFlowRate(
1117 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1118 0 : mdotDmdSide = 0.0;
1119 0 : PlantUtilities::SetComponentFlowRate(
1120 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1121 : }
1122 :
1123 0 : break;
1124 : }
1125 11648 : case ControlType::HeatingSetPointModulated: {
1126 :
1127 11648 : Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
1128 11648 : Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
1129 11648 : if ((DeltaTHeating > this->TempControlTol) && (SetPointTemp > this->SupplySideLoop.InletTemp)) {
1130 : // can and want to heat
1131 5750 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1132 5750 : PlantUtilities::SetComponentFlowRate(
1133 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1134 5750 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1135 :
1136 5750 : Real64 TargetLeavingTemp = SetPointTemp;
1137 5750 : this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::HeatingSupplySideLoop);
1138 : } else {
1139 0 : mdotDmdSide = 0.0;
1140 0 : PlantUtilities::SetComponentFlowRate(
1141 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1142 : }
1143 5750 : } else { // not able are wanting to heat so turn off
1144 5898 : mdotSupSide = 0.0;
1145 5898 : PlantUtilities::SetComponentFlowRate(
1146 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1147 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
1148 : // demand side inlet temperature value
1149 5898 : if (FirstHVACIteration) {
1150 2388 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1151 : } else {
1152 3510 : mdotDmdSide = 0.0;
1153 : }
1154 5898 : PlantUtilities::SetComponentFlowRate(
1155 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1156 : }
1157 :
1158 11648 : break;
1159 : }
1160 0 : case ControlType::HeatingSetPointOnOff: {
1161 :
1162 0 : Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
1163 0 : Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
1164 0 : if ((DeltaTHeating > this->TempControlTol) && (SetPointTemp > this->SupplySideLoop.InletTemp)) {
1165 : // can and want to heat
1166 0 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1167 0 : PlantUtilities::SetComponentFlowRate(
1168 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1169 0 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1170 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1171 : } else {
1172 0 : mdotDmdSide = 0.0;
1173 : }
1174 0 : PlantUtilities::SetComponentFlowRate(
1175 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1176 : } else { // not able or are wanting to heat so turn off
1177 0 : mdotSupSide = 0.0;
1178 0 : PlantUtilities::SetComponentFlowRate(
1179 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1180 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
1181 : // demand side inlet temperature value
1182 0 : if (FirstHVACIteration) {
1183 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1184 : } else {
1185 0 : mdotDmdSide = 0.0;
1186 : }
1187 0 : PlantUtilities::SetComponentFlowRate(
1188 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1189 : }
1190 :
1191 0 : break;
1192 : }
1193 11648 : case ControlType::CoolingSetPointModulated: {
1194 :
1195 11648 : Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
1196 11648 : Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
1197 11648 : if ((DeltaTCooling > this->TempControlTol) && (SetPointTemp < this->SupplySideLoop.InletTemp)) {
1198 : // can and want to cool
1199 5750 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1200 5750 : PlantUtilities::SetComponentFlowRate(
1201 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1202 5750 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1203 5750 : Real64 TargetLeavingTemp = SetPointTemp;
1204 5750 : this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::CoolingSupplySideLoop);
1205 : } else {
1206 0 : mdotDmdSide = 0.0;
1207 0 : PlantUtilities::SetComponentFlowRate(
1208 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1209 : }
1210 5750 : } else { // not able or are wanting to cool so turn off
1211 5898 : mdotSupSide = 0.0;
1212 5898 : PlantUtilities::SetComponentFlowRate(
1213 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1214 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
1215 : // demand side inlet temperature value
1216 5898 : if (FirstHVACIteration) {
1217 2388 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1218 : } else {
1219 3510 : mdotDmdSide = 0.0;
1220 : }
1221 5898 : PlantUtilities::SetComponentFlowRate(
1222 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1223 : }
1224 :
1225 11648 : break;
1226 : }
1227 0 : case ControlType::CoolingSetPointOnOff: {
1228 :
1229 0 : Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
1230 0 : Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
1231 0 : if ((DeltaTCooling > this->TempControlTol) && (SetPointTemp < this->SupplySideLoop.InletTemp)) {
1232 : // can and want to cool
1233 0 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1234 0 : PlantUtilities::SetComponentFlowRate(
1235 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1236 0 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1237 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1238 : } else {
1239 0 : mdotDmdSide = 0.0;
1240 : }
1241 0 : PlantUtilities::SetComponentFlowRate(
1242 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1243 : } else { // not able or are wanting to cool so turn off
1244 0 : mdotSupSide = 0.0;
1245 0 : PlantUtilities::SetComponentFlowRate(
1246 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1247 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
1248 : // demand side inlet temperature value
1249 0 : if (FirstHVACIteration) {
1250 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1251 : } else {
1252 0 : mdotDmdSide = 0.0;
1253 : }
1254 0 : PlantUtilities::SetComponentFlowRate(
1255 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1256 : }
1257 :
1258 0 : break;
1259 : }
1260 11644 : case ControlType::DualDeadBandSetPointModulated: {
1261 :
1262 11644 : Real64 SetPointTempLo = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPointLo;
1263 11644 : Real64 SetPointTempHi = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPointHi;
1264 11644 : Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
1265 11644 : Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
1266 11644 : if ((DeltaTCooling > this->TempControlTol) && (SetPointTempHi < this->SupplySideLoop.InletTemp)) {
1267 :
1268 : // can and want to cool
1269 5736 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1270 5736 : PlantUtilities::SetComponentFlowRate(
1271 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1272 5736 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1273 5736 : Real64 TargetLeavingTemp = SetPointTempHi;
1274 5736 : this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::CoolingSupplySideLoop);
1275 : } else {
1276 0 : mdotDmdSide = 0.0;
1277 0 : PlantUtilities::SetComponentFlowRate(
1278 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1279 : }
1280 11644 : } else if ((DeltaTHeating > this->TempControlTol) && (SetPointTempLo > this->SupplySideLoop.InletTemp)) {
1281 : // can and want to heat
1282 5736 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1283 5736 : PlantUtilities::SetComponentFlowRate(
1284 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1285 5736 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1286 5736 : Real64 TargetLeavingTemp = SetPointTempLo;
1287 5736 : this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::HeatingSupplySideLoop);
1288 : } else {
1289 0 : mdotDmdSide = 0.0;
1290 0 : PlantUtilities::SetComponentFlowRate(
1291 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1292 : }
1293 5736 : } else { // not able or don't want conditioning
1294 172 : mdotSupSide = 0.0;
1295 172 : PlantUtilities::SetComponentFlowRate(
1296 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1297 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
1298 : // demand side inlet temperature value
1299 172 : if (FirstHVACIteration) {
1300 100 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1301 : } else {
1302 72 : mdotDmdSide = 0.0;
1303 : }
1304 172 : PlantUtilities::SetComponentFlowRate(
1305 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1306 : }
1307 :
1308 11644 : break;
1309 : }
1310 0 : case ControlType::DualDeadBandSetPointOnOff: {
1311 :
1312 0 : Real64 SetPointTempLo = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPointLo;
1313 0 : Real64 SetPointTempHi = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPointHi;
1314 0 : Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
1315 0 : Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
1316 0 : if ((DeltaTCooling > this->TempControlTol) && (SetPointTempHi < this->SupplySideLoop.InletTemp)) {
1317 : // can and want to cool
1318 0 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1319 0 : PlantUtilities::SetComponentFlowRate(
1320 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1321 0 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1322 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1323 : } else {
1324 0 : mdotDmdSide = 0.0;
1325 : }
1326 0 : PlantUtilities::SetComponentFlowRate(
1327 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1328 0 : } else if ((DeltaTHeating > this->TempControlTol) && (SetPointTempLo > this->SupplySideLoop.InletTemp)) {
1329 : // can and want to heat
1330 0 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1331 0 : PlantUtilities::SetComponentFlowRate(
1332 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1333 0 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1334 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1335 : } else {
1336 0 : mdotDmdSide = 0.0;
1337 : }
1338 0 : PlantUtilities::SetComponentFlowRate(
1339 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1340 : } else { // not able or don't want conditioning
1341 0 : mdotSupSide = 0.0;
1342 0 : PlantUtilities::SetComponentFlowRate(
1343 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1344 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
1345 : // demand side inlet temperature value
1346 0 : if (FirstHVACIteration) {
1347 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1348 : } else {
1349 0 : mdotDmdSide = 0.0;
1350 : }
1351 0 : PlantUtilities::SetComponentFlowRate(
1352 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1353 : }
1354 :
1355 0 : break;
1356 : }
1357 2 : case ControlType::CoolingDifferentialOnOff: {
1358 :
1359 2 : Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
1360 2 : if (DeltaTCooling > this->TempControlTol) {
1361 : // want to cool
1362 0 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1363 0 : PlantUtilities::SetComponentFlowRate(
1364 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1365 0 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1366 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1367 : } else {
1368 0 : mdotDmdSide = 0.0;
1369 : }
1370 0 : PlantUtilities::SetComponentFlowRate(
1371 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1372 : } else { // not wanting to cool so turn off
1373 2 : mdotSupSide = 0.0;
1374 2 : PlantUtilities::SetComponentFlowRate(
1375 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1376 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
1377 : // demand side inlet temperature value
1378 2 : if (FirstHVACIteration) {
1379 1 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1380 : } else {
1381 1 : mdotDmdSide = 0.0;
1382 : }
1383 2 : PlantUtilities::SetComponentFlowRate(
1384 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1385 : }
1386 :
1387 2 : break;
1388 : }
1389 0 : case ControlType::CoolingSetPointOnOffWithComponentOverride: {
1390 :
1391 0 : Real64 ControlSignalValue(0.0);
1392 :
1393 0 : switch (this->ControlSignalTemp) {
1394 0 : case CtrlTempType::WetBulbTemperature: {
1395 0 : ControlSignalValue = state.dataEnvrn->OutWetBulbTemp;
1396 0 : break;
1397 : }
1398 0 : case CtrlTempType::DryBulbTemperature: {
1399 0 : ControlSignalValue = state.dataEnvrn->OutDryBulbTemp;
1400 0 : break;
1401 : }
1402 0 : case CtrlTempType::LoopTemperature: {
1403 0 : ControlSignalValue = state.dataLoopNodes->Node(this->OtherCompDemandSideLoop.inletNodeNum).TempLastTimestep;
1404 0 : break;
1405 : }
1406 0 : default:
1407 0 : assert(false);
1408 : break;
1409 : }
1410 :
1411 0 : Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
1412 0 : Real64 DeltaTCooling = SetPointTemp - ControlSignalValue;
1413 : // obtain shut down state
1414 0 : bool ChillerShutDown = this->OtherCompSupplySideLoop.comp->FreeCoolCntrlShutDown;
1415 0 : if (ChillerShutDown && (DeltaTCooling > this->TempControlTol)) {
1416 : // can and want to cool
1417 0 : mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
1418 0 : PlantUtilities::SetComponentFlowRate(
1419 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1420 0 : if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
1421 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1422 : } else {
1423 0 : mdotDmdSide = 0.0;
1424 : }
1425 0 : PlantUtilities::SetComponentFlowRate(
1426 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1427 :
1428 : } else {
1429 0 : mdotSupSide = 0.0;
1430 0 : PlantUtilities::SetComponentFlowRate(
1431 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1432 : // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
1433 : // demand side inlet temperature value
1434 0 : if (FirstHVACIteration) {
1435 0 : mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
1436 : } else {
1437 0 : mdotDmdSide = 0.0;
1438 : }
1439 0 : PlantUtilities::SetComponentFlowRate(
1440 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1441 : }
1442 0 : break;
1443 : }
1444 0 : default:
1445 0 : break;
1446 : }
1447 :
1448 34942 : } else { // scheduled off
1449 0 : mdotSupSide = 0.0;
1450 0 : PlantUtilities::SetComponentFlowRate(
1451 : state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
1452 0 : mdotDmdSide = 0.0;
1453 0 : PlantUtilities::SetComponentFlowRate(
1454 : state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1455 : }
1456 34942 : }
1457 :
1458 142906 : void HeatExchangerStruct::calculate(EnergyPlusData &state, Real64 const SupSideMdot, Real64 const DmdSideMdot)
1459 : {
1460 :
1461 : // SUBROUTINE INFORMATION:
1462 : // AUTHOR B.Griffith, derived from CalcEconHeatExchanger by Sankaranarayanan K P aug. 2007
1463 : // DATE WRITTEN November 2012
1464 : // MODIFIED na
1465 : // RE-ENGINEERED na
1466 :
1467 : // PURPOSE OF THIS SUBROUTINE:
1468 : // Evalutate heat exchanger model and calculate leaving temperatures
1469 :
1470 : // METHODOLOGY EMPLOYED:
1471 : // apply heat transfer model depending on type of HX used
1472 :
1473 : static constexpr std::string_view RoutineName("CalcFluidHeatExchanger");
1474 :
1475 142906 : int constexpr CmaxMixedCminUnmixed(40);
1476 142906 : int constexpr CmaxUnMixedCminMixed(41);
1477 :
1478 142906 : Real64 SupSideLoopInletTemp = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp;
1479 142906 : Real64 DmdSideLoopInletTemp = state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp;
1480 :
1481 : // specific heat of fluid entering from supply side loop at inlet temp
1482 142906 : Real64 SupSideLoopInletCp = this->SupplySideLoop.loop->glycol->getSpecificHeat(state, SupSideLoopInletTemp, RoutineName);
1483 :
1484 : // specific heat of fluid entering from demand side loop at inlet temp
1485 142906 : Real64 DmdSideLoopInletCp = this->DemandSideLoop.loop->glycol->getSpecificHeat(state, DmdSideLoopInletTemp, RoutineName);
1486 :
1487 142906 : Real64 SupSideCapRate = SupSideMdot * SupSideLoopInletCp;
1488 142906 : Real64 DmdSideCapRate = DmdSideMdot * DmdSideLoopInletCp;
1489 142906 : Real64 MinCapRate = min(SupSideCapRate, DmdSideCapRate);
1490 142906 : Real64 MaxCapRate = max(SupSideCapRate, DmdSideCapRate);
1491 :
1492 142906 : if (MinCapRate > 0.0) {
1493 :
1494 96504 : switch (this->HeatExchangeModelType) {
1495 :
1496 96504 : case FluidHXType::CrossFlowBothUnMixed: {
1497 96504 : Real64 NTU = this->UA / MinCapRate;
1498 96504 : Real64 CapRatio = MinCapRate / MaxCapRate;
1499 96504 : Real64 ExpCheckValue1 = std::pow(NTU, 0.22) / CapRatio;
1500 96504 : Real64 ExpCheckValue2 = -CapRatio * std::pow(NTU, 0.78);
1501 96504 : if ((ExpCheckValue1 > DataPrecisionGlobals::EXP_UpperLimit) || (ExpCheckValue2 > DataPrecisionGlobals::EXP_UpperLimit)) {
1502 12 : if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
1503 0 : this->Effectiveness = 1.0 - std::exp(-NTU);
1504 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1505 : } else {
1506 12 : this->Effectiveness = 1.0;
1507 : }
1508 : } else {
1509 96492 : this->Effectiveness = 1.0 - std::exp((std::pow(NTU, 0.22) / CapRatio) * (std::exp(-CapRatio * std::pow(NTU, 0.78)) - 1.0));
1510 96492 : this->Effectiveness = min(1.0, this->Effectiveness);
1511 : }
1512 :
1513 96504 : break;
1514 : }
1515 0 : case FluidHXType::CrossFlowBothMixed: {
1516 0 : Real64 NTU = this->UA / MinCapRate;
1517 0 : Real64 CapRatio = MinCapRate / MaxCapRate;
1518 0 : Real64 ExpCheckValue1 = -CapRatio * NTU;
1519 0 : Real64 ExpCheckValue2 = -NTU;
1520 0 : if (ExpCheckValue1 < DataPrecisionGlobals::EXP_LowerLimit) {
1521 0 : if (ExpCheckValue2 >= DataPrecisionGlobals::EXP_LowerLimit) {
1522 0 : this->Effectiveness = 1.0 - std::exp(-NTU);
1523 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1524 : } else {
1525 0 : this->Effectiveness = 1.0;
1526 : }
1527 0 : } else if (ExpCheckValue2 < DataPrecisionGlobals::EXP_LowerLimit) {
1528 0 : this->Effectiveness = 1.0;
1529 0 : } else if ((std::exp(-NTU) == 1.0) || (NTU == 0.0) || (std::exp(-CapRatio * NTU) == 1.0)) { // don't div by zero
1530 :
1531 0 : this->Effectiveness = 0.0;
1532 : } else {
1533 0 : this->Effectiveness = 1.0 / ((1.0 / (1.0 - std::exp(-NTU))) + (CapRatio / (1.0 - std::exp(-CapRatio * NTU))) - (1.0 / NTU));
1534 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1535 : }
1536 :
1537 0 : break;
1538 : }
1539 0 : case FluidHXType::CrossFlowSupplyLoopMixedDemandLoopUnMixed:
1540 : case FluidHXType::CrossFlowSupplyLoopUnMixedDemandLoopMixed: {
1541 :
1542 : int CrossFlowEquation;
1543 0 : if (SupSideCapRate == MaxCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopMixedDemandLoopUnMixed) {
1544 0 : CrossFlowEquation = CmaxMixedCminUnmixed;
1545 0 : } else if (SupSideCapRate == MinCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopMixedDemandLoopUnMixed) {
1546 0 : CrossFlowEquation = CmaxUnMixedCminMixed;
1547 0 : } else if (DmdSideCapRate == MaxCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopUnMixedDemandLoopMixed) {
1548 0 : CrossFlowEquation = CmaxMixedCminUnmixed;
1549 0 : } else if (DmdSideCapRate == MinCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopUnMixedDemandLoopMixed) {
1550 0 : CrossFlowEquation = CmaxUnMixedCminMixed;
1551 : } else {
1552 0 : CrossFlowEquation = CmaxMixedCminUnmixed;
1553 : }
1554 :
1555 0 : Real64 NTU = this->UA / MinCapRate;
1556 0 : Real64 CapRatio = MinCapRate / MaxCapRate;
1557 0 : if (CrossFlowEquation == CmaxMixedCminUnmixed) {
1558 0 : Real64 ExpCheckValue1 = -NTU;
1559 0 : if (CapRatio == 0.0) { // protect div by zero
1560 0 : if (ExpCheckValue1 >= DataPrecisionGlobals::EXP_LowerLimit) {
1561 0 : this->Effectiveness = 1.0 - std::exp(-NTU);
1562 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1563 : } else {
1564 0 : this->Effectiveness = 1.0;
1565 : }
1566 0 : } else if (ExpCheckValue1 < DataPrecisionGlobals::EXP_LowerLimit) {
1567 0 : this->Effectiveness = 0.632 / CapRatio;
1568 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1569 : } else {
1570 0 : this->Effectiveness = (1.0 / CapRatio) * (1.0 - std::exp(CapRatio * std::exp(-NTU) - 1.0));
1571 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1572 : }
1573 0 : } else if (CrossFlowEquation == CmaxUnMixedCminMixed) {
1574 0 : Real64 ExpCheckValue1 = -CapRatio * NTU;
1575 0 : if (CapRatio == 0.0) {
1576 0 : if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
1577 0 : this->Effectiveness = 1.0 - std::exp(-NTU);
1578 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1579 : } else {
1580 0 : this->Effectiveness = 1.0;
1581 : }
1582 : } else {
1583 0 : if (ExpCheckValue1 >= DataPrecisionGlobals::EXP_LowerLimit) {
1584 0 : Real64 ExpCheckValue2 = -(1.0 / CapRatio) * (1.0 - std::exp(-CapRatio * NTU));
1585 0 : if (ExpCheckValue2 < DataPrecisionGlobals::EXP_LowerLimit) {
1586 0 : this->Effectiveness = 1.0;
1587 : } else {
1588 0 : this->Effectiveness = 1.0 - std::exp(ExpCheckValue2);
1589 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1590 : }
1591 : } else {
1592 0 : this->Effectiveness = 1.0;
1593 : }
1594 : }
1595 : } else {
1596 0 : assert(false);
1597 : }
1598 :
1599 0 : break;
1600 : }
1601 0 : case FluidHXType::CounterFlow: {
1602 0 : Real64 NTU = this->UA / MinCapRate;
1603 0 : Real64 CapRatio = MinCapRate / MaxCapRate;
1604 0 : Real64 ExpCheckValue1 = -NTU * (1.0 - CapRatio);
1605 0 : if (ExpCheckValue1 > DataPrecisionGlobals::EXP_UpperLimit) {
1606 0 : if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
1607 0 : this->Effectiveness = 1.0 - std::exp(-NTU);
1608 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1609 : } else {
1610 0 : this->Effectiveness = 1.0;
1611 : }
1612 0 : } else if (CapRatio * std::exp(-NTU * (1.0 - CapRatio)) == 1.0) {
1613 0 : if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
1614 0 : this->Effectiveness = 1.0 - std::exp(-NTU);
1615 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1616 : } else {
1617 0 : this->Effectiveness = 1.0;
1618 : }
1619 : } else {
1620 0 : this->Effectiveness = (1.0 - std::exp(-NTU * (1.0 - CapRatio))) / (1.0 - CapRatio * std::exp(-NTU * (1.0 - CapRatio)));
1621 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1622 : }
1623 :
1624 0 : break;
1625 : }
1626 0 : case FluidHXType::ParallelFlow: {
1627 0 : Real64 NTU = this->UA / MinCapRate;
1628 0 : Real64 CapRatio = MinCapRate / MaxCapRate;
1629 0 : Real64 ExpCheckValue1 = -NTU * (1.0 + CapRatio);
1630 0 : if (ExpCheckValue1 > DataPrecisionGlobals::EXP_UpperLimit) {
1631 0 : if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
1632 0 : this->Effectiveness = 1.0 - std::exp(-NTU);
1633 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1634 : } else {
1635 0 : this->Effectiveness = 1.0;
1636 : }
1637 : } else {
1638 0 : this->Effectiveness = (1.0 - std::exp(-NTU * (1.0 + CapRatio))) / (1.0 + CapRatio);
1639 0 : this->Effectiveness = min(1.0, this->Effectiveness);
1640 : }
1641 :
1642 0 : break;
1643 : }
1644 0 : case FluidHXType::Ideal: {
1645 0 : this->Effectiveness = 1.0;
1646 0 : break;
1647 : }
1648 0 : default:
1649 0 : assert(false);
1650 : break;
1651 : }
1652 :
1653 : } else { // no capacity
1654 46402 : this->Effectiveness = 0.0;
1655 : }
1656 :
1657 142906 : this->HeatTransferRate = this->Effectiveness * MinCapRate * (SupSideLoopInletTemp - DmdSideLoopInletTemp); // + means supply side is cooled
1658 :
1659 142906 : if (SupSideMdot > 0.0) {
1660 130998 : this->SupplySideLoop.OutletTemp = SupSideLoopInletTemp - this->HeatTransferRate / (SupSideLoopInletCp * SupSideMdot);
1661 : } else {
1662 11908 : this->SupplySideLoop.OutletTemp = SupSideLoopInletTemp;
1663 : }
1664 :
1665 142906 : if (DmdSideMdot > 0.0) {
1666 103486 : this->DemandSideLoop.OutletTemp = DmdSideLoopInletTemp + this->HeatTransferRate / (DmdSideLoopInletCp * DmdSideMdot);
1667 : } else {
1668 39420 : this->DemandSideLoop.OutletTemp = DmdSideLoopInletTemp;
1669 : }
1670 :
1671 142906 : this->SupplySideLoop.InletTemp = SupSideLoopInletTemp;
1672 142906 : this->SupplySideLoop.InletMassFlowRate = SupSideMdot;
1673 142906 : this->DemandSideLoop.InletTemp = DmdSideLoopInletTemp;
1674 142906 : this->DemandSideLoop.InletMassFlowRate = DmdSideMdot;
1675 :
1676 142906 : state.dataLoopNodes->Node(this->DemandSideLoop.outletNodeNum).Temp = this->DemandSideLoop.OutletTemp;
1677 142906 : state.dataLoopNodes->Node(this->SupplySideLoop.outletNodeNum).Temp = this->SupplySideLoop.OutletTemp;
1678 :
1679 142906 : this->HeatTransferEnergy = this->HeatTransferRate * state.dataHVACGlobal->TimeStepSysSec;
1680 :
1681 239410 : if ((std::abs(this->HeatTransferRate) > HVAC::SmallLoad) && (this->DemandSideLoop.InletMassFlowRate > 0.0) &&
1682 96504 : (this->SupplySideLoop.InletMassFlowRate > 0.0)) {
1683 96504 : this->OperationStatus = 1.0;
1684 : } else {
1685 46402 : this->OperationStatus = 0.0;
1686 : }
1687 142906 : }
1688 :
1689 22972 : void HeatExchangerStruct::findDemandSideLoopFlow(EnergyPlusData &state, Real64 const TargetSupplySideLoopLeavingTemp, HXAction const HXActionMode)
1690 : {
1691 :
1692 : // SUBROUTINE INFORMATION:
1693 : // AUTHOR B. Griffith
1694 : // DATE WRITTEN November 2012
1695 : // MODIFIED na
1696 : // RE-ENGINEERED na
1697 :
1698 : // PURPOSE OF THIS SUBROUTINE:
1699 : // modulate demand side flow rate to hit a target leaving temperature (within tolerance)
1700 :
1701 : // METHODOLOGY EMPLOYED:
1702 : // uses E+'s Regula Falsi numerical method
1703 :
1704 22972 : int constexpr MaxIte(500); // Maximum number of iterations for solver
1705 22972 : Real64 constexpr Acc(1.e-3); // Accuracy of solver result
1706 :
1707 : int SolFla; // Flag of solver
1708 :
1709 : // mass flow rate of fluid entering from supply side loop
1710 22972 : Real64 SupSideMdot = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).MassFlowRate;
1711 : // first see if root is bracketed
1712 : // min demand flow
1713 :
1714 : // mass flow rate of fluid entering from demand side loop
1715 22972 : Real64 DmdSideMdot = this->DemandSideLoop.MassFlowRateMin;
1716 22972 : this->calculate(state, SupSideMdot, DmdSideMdot);
1717 22972 : Real64 LeavingTempMinFlow = this->SupplySideLoop.OutletTemp;
1718 :
1719 : // full demand flow
1720 22972 : DmdSideMdot = this->DemandSideLoop.MassFlowRateMax;
1721 22972 : this->calculate(state, SupSideMdot, DmdSideMdot);
1722 22972 : Real64 LeavingTempFullFlow = this->SupplySideLoop.OutletTemp;
1723 :
1724 22972 : switch (HXActionMode) {
1725 :
1726 11486 : case HXAction::HeatingSupplySideLoop: {
1727 11486 : if ((LeavingTempFullFlow > TargetSupplySideLoopLeavingTemp) && (TargetSupplySideLoopLeavingTemp > LeavingTempMinFlow)) {
1728 31008 : auto f = [&state, this, TargetSupplySideLoopLeavingTemp](Real64 const DmdSideMassFlowRate) {
1729 31008 : Real64 SupSideMdot = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).MassFlowRate;
1730 31008 : this->calculate(state, SupSideMdot, DmdSideMassFlowRate);
1731 31008 : return TargetSupplySideLoopLeavingTemp - this->SupplySideLoop.OutletTemp;
1732 5750 : };
1733 5750 : General::SolveRoot(
1734 : state, Acc, MaxIte, SolFla, DmdSideMdot, f, this->DemandSideLoop.MassFlowRateMin, this->DemandSideLoop.MassFlowRateMax);
1735 :
1736 5750 : if (SolFla == -1) { // no convergence
1737 0 : if (!state.dataGlobal->WarmupFlag) {
1738 0 : if (this->DmdSideModulatSolvNoConvergeErrorCount < 1) {
1739 0 : ++this->DmdSideModulatSolvNoConvergeErrorCount;
1740 0 : ShowWarningError(
1741 : state,
1742 0 : format("{} named {} - Iteration Limit exceeded calculating demand side loop flow rate", ComponentClassName, this->Name));
1743 0 : ShowContinueError(state, format("Simulation continues with calculated demand side mass flow rate = {:.7R}", DmdSideMdot));
1744 : }
1745 0 : ShowRecurringWarningErrorAtEnd(state,
1746 0 : ComponentClassName + " named " + this->Name +
1747 : " - Iteration Limit exceeded calculating demand side loop flow rate continues.",
1748 0 : this->DmdSideModulatSolvNoConvergeErrorIndex,
1749 : DmdSideMdot,
1750 : DmdSideMdot);
1751 : }
1752 5750 : } else if (SolFla == -2) { // f(x0) and f(x1) have the same sign
1753 0 : DmdSideMdot = this->DemandSideLoop.MassFlowRateMax * (LeavingTempFullFlow - TargetSupplySideLoopLeavingTemp) /
1754 0 : (LeavingTempFullFlow - LeavingTempMinFlow);
1755 0 : if (!state.dataGlobal->WarmupFlag) {
1756 0 : if (this->DmdSideModulatSolvFailErrorCount < 1) {
1757 0 : ++this->DmdSideModulatSolvFailErrorCount;
1758 0 : ShowWarningError(
1759 0 : state, format("{} named {} - Solver failed to calculate demand side loop flow rate", ComponentClassName, this->Name));
1760 0 : ShowContinueError(state, format("Simulation continues with estimated demand side mass flow rate = {:.7R}", DmdSideMdot));
1761 : }
1762 0 : ShowRecurringWarningErrorAtEnd(state,
1763 0 : ComponentClassName + " named " + this->Name +
1764 : " - Solver failed to calculate demand side loop flow rate continues.",
1765 0 : this->DmdSideModulatSolvFailErrorIndex,
1766 : DmdSideMdot,
1767 : DmdSideMdot);
1768 : }
1769 : }
1770 5750 : PlantUtilities::SetComponentFlowRate(
1771 : state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1772 :
1773 11486 : } else if ((TargetSupplySideLoopLeavingTemp >= LeavingTempFullFlow) && (LeavingTempFullFlow > LeavingTempMinFlow)) {
1774 : // run at full flow
1775 5736 : DmdSideMdot = this->DemandSideLoop.MassFlowRateMax;
1776 5736 : PlantUtilities::SetComponentFlowRate(
1777 : state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1778 :
1779 0 : } else if (LeavingTempMinFlow >= TargetSupplySideLoopLeavingTemp) {
1780 :
1781 : // run at min flow
1782 0 : DmdSideMdot = this->DemandSideLoop.MassFlowRateMin;
1783 0 : PlantUtilities::SetComponentFlowRate(
1784 : state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1785 : }
1786 11486 : break;
1787 : }
1788 11486 : case HXAction::CoolingSupplySideLoop: {
1789 11486 : if ((LeavingTempFullFlow < TargetSupplySideLoopLeavingTemp) && (TargetSupplySideLoopLeavingTemp < LeavingTempMinFlow)) {
1790 31008 : auto f = [&state, this, TargetSupplySideLoopLeavingTemp](Real64 const DmdSideMassFlowRate) {
1791 31008 : Real64 SupSideMdot = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).MassFlowRate;
1792 31008 : this->calculate(state, SupSideMdot, DmdSideMassFlowRate);
1793 31008 : return TargetSupplySideLoopLeavingTemp - this->SupplySideLoop.OutletTemp;
1794 5750 : };
1795 5750 : General::SolveRoot(
1796 : state, Acc, MaxIte, SolFla, DmdSideMdot, f, this->DemandSideLoop.MassFlowRateMin, this->DemandSideLoop.MassFlowRateMax);
1797 :
1798 5750 : if (SolFla == -1) { // no convergence
1799 0 : if (!state.dataGlobal->WarmupFlag) {
1800 0 : if (this->DmdSideModulatSolvNoConvergeErrorCount < 1) {
1801 0 : ++this->DmdSideModulatSolvNoConvergeErrorCount;
1802 0 : ShowWarningError(
1803 : state,
1804 0 : format("{} named {} - Iteration Limit exceeded calculating demand side loop flow rate", ComponentClassName, this->Name));
1805 0 : ShowContinueError(state, format("Simulation continues with calculated demand side mass flow rate = {:.7R}", DmdSideMdot));
1806 : }
1807 0 : ShowRecurringWarningErrorAtEnd(state,
1808 0 : ComponentClassName + " named " + this->Name +
1809 : " - Iteration Limit exceeded calculating demand side loop flow rate continues.",
1810 0 : this->DmdSideModulatSolvNoConvergeErrorIndex,
1811 : DmdSideMdot,
1812 : DmdSideMdot);
1813 : }
1814 5750 : } else if (SolFla == -2) { // f(x0) and f(x1) have the same sign
1815 0 : DmdSideMdot = this->DemandSideLoop.MassFlowRateMax * (LeavingTempFullFlow - TargetSupplySideLoopLeavingTemp) /
1816 0 : (LeavingTempFullFlow - LeavingTempMinFlow);
1817 0 : if (!state.dataGlobal->WarmupFlag) {
1818 0 : if (this->DmdSideModulatSolvFailErrorCount < 1) {
1819 0 : ++this->DmdSideModulatSolvFailErrorCount;
1820 0 : ShowWarningError(
1821 0 : state, format("{} named {} - Solver failed to calculate demand side loop flow rate", ComponentClassName, this->Name));
1822 0 : ShowContinueError(state, format("Simulation continues with estimated demand side mass flow rate = {:.7R}", DmdSideMdot));
1823 : }
1824 0 : ShowRecurringWarningErrorAtEnd(state,
1825 0 : ComponentClassName + " named " + this->Name +
1826 : " - Solver failed to calculate demand side loop flow rate continues.",
1827 0 : this->DmdSideModulatSolvFailErrorIndex,
1828 : DmdSideMdot,
1829 : DmdSideMdot);
1830 : }
1831 : }
1832 5750 : PlantUtilities::SetComponentFlowRate(
1833 : state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1834 11486 : } else if ((TargetSupplySideLoopLeavingTemp <= LeavingTempFullFlow) && (LeavingTempFullFlow < LeavingTempMinFlow)) {
1835 : // run at full flow
1836 5736 : DmdSideMdot = this->DemandSideLoop.MassFlowRateMax;
1837 5736 : PlantUtilities::SetComponentFlowRate(
1838 : state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1839 0 : } else if (LeavingTempMinFlow <= TargetSupplySideLoopLeavingTemp) {
1840 :
1841 : // run at min flow
1842 0 : DmdSideMdot = this->DemandSideLoop.MassFlowRateMin;
1843 0 : PlantUtilities::SetComponentFlowRate(
1844 : state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
1845 : }
1846 11486 : break;
1847 : }
1848 0 : default:
1849 0 : break;
1850 : }
1851 22972 : }
1852 :
1853 35002 : void HeatExchangerStruct::oneTimeInit(EnergyPlusData &state)
1854 : {
1855 :
1856 : static constexpr std::string_view RoutineName("InitFluidHeatExchanger: ");
1857 :
1858 35002 : if (this->MyOneTimeFlag) {
1859 7 : this->setupOutputVars(state);
1860 7 : this->MyFlag = true;
1861 7 : this->MyEnvrnFlag = true;
1862 7 : this->MyOneTimeFlag = false;
1863 : }
1864 :
1865 35002 : if (this->MyFlag) {
1866 : // locate the main two connections to the plant loops
1867 7 : bool errFlag = false;
1868 14 : PlantUtilities::ScanPlantLoopsForObject(state,
1869 : this->Name,
1870 : DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg,
1871 : this->DemandSideLoop,
1872 : errFlag,
1873 : _,
1874 : _,
1875 : _,
1876 7 : this->DemandSideLoop.inletNodeNum,
1877 : _);
1878 :
1879 7 : if (this->DemandSideLoop.loopSideNum != DataPlant::LoopSideLocation::Demand) { // throw error
1880 0 : ShowSevereError(state,
1881 0 : format("{} Invalid connections for {} name = \"{}\"",
1882 : RoutineName,
1883 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg)],
1884 0 : this->Name));
1885 0 : ShowContinueError(state, "The \"Loop Demand Side\" connections are not on the Demand Side of a plant loop");
1886 0 : errFlag = true;
1887 : }
1888 :
1889 14 : PlantUtilities::ScanPlantLoopsForObject(state,
1890 : this->Name,
1891 : DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg,
1892 : this->SupplySideLoop,
1893 : errFlag,
1894 : _,
1895 : _,
1896 : _,
1897 7 : this->SupplySideLoop.inletNodeNum,
1898 : _);
1899 :
1900 7 : if (this->SupplySideLoop.loopSideNum != DataPlant::LoopSideLocation::Supply) { // throw error
1901 0 : ShowSevereError(state,
1902 0 : format("{} Invalid connections for {} name = \"{}\"",
1903 : RoutineName,
1904 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg)],
1905 0 : this->Name));
1906 0 : ShowContinueError(state, "The \"Loop Supply Side\" connections are not on the Supply Side of a plant loop");
1907 0 : errFlag = true;
1908 : }
1909 :
1910 : // make sure it is not the same loop on both sides.
1911 7 : if (this->SupplySideLoop.loopNum == this->DemandSideLoop.loopNum) { // user is being too tricky, don't allow
1912 0 : ShowSevereError(state,
1913 0 : format("{} Invalid connections for {} name = \"{}\"",
1914 : RoutineName,
1915 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg)],
1916 0 : this->Name));
1917 0 : ShowContinueError(state, R"(The "Loop Supply Side" and "Loop Demand Side" need to be on different loops.)");
1918 0 : errFlag = true;
1919 : } else {
1920 :
1921 7 : PlantUtilities::InterConnectTwoPlantLoopSides(
1922 : state, this->SupplySideLoop, this->DemandSideLoop, DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg, true);
1923 : }
1924 :
1925 : // find remote component if control mode is of that type.
1926 7 : if (this->controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride) {
1927 :
1928 1 : PlantUtilities::ScanPlantLoopsForNodeNum(
1929 1 : state, RoutineName, this->OtherCompSupplySideLoop.inletNodeNum, this->OtherCompSupplySideLoop, this->OtherCompSupplySideLoop.compNum);
1930 :
1931 1 : PlantUtilities::ScanPlantLoopsForNodeNum(
1932 1 : state, RoutineName, this->OtherCompDemandSideLoop.inletNodeNum, this->OtherCompDemandSideLoop, this->OtherCompDemandSideLoop.compNum);
1933 :
1934 : // revise how loads served category for other controlled equipment
1935 1 : switch (this->OtherCompSupplySideLoop.comp->HowLoadServed) {
1936 :
1937 1 : case DataPlant::HowMet::ByNominalCap: {
1938 1 : this->OtherCompSupplySideLoop.comp->HowLoadServed = DataPlant::HowMet::ByNominalCapFreeCoolCntrl;
1939 1 : break;
1940 : }
1941 0 : case DataPlant::HowMet::ByNominalCapLowOutLimit: {
1942 0 : this->OtherCompSupplySideLoop.comp->HowLoadServed = DataPlant::HowMet::ByNominalCapLowOutLimitFreeCoolCntrl;
1943 0 : break;
1944 : }
1945 0 : default:
1946 0 : break;
1947 : }
1948 :
1949 1 : switch (this->ControlSignalTemp) {
1950 0 : case CtrlTempType::WetBulbTemperature: {
1951 0 : this->OtherCompSupplySideLoop.comp->FreeCoolCntrlMode = DataPlant::FreeCoolControlMode::WetBulb;
1952 0 : break;
1953 : }
1954 1 : case CtrlTempType::DryBulbTemperature: {
1955 1 : this->OtherCompSupplySideLoop.comp->FreeCoolCntrlMode = DataPlant::FreeCoolControlMode::DryBulb;
1956 1 : break;
1957 : }
1958 0 : case CtrlTempType::LoopTemperature: {
1959 0 : this->OtherCompSupplySideLoop.comp->FreeCoolCntrlMode = DataPlant::FreeCoolControlMode::Loop;
1960 0 : this->OtherCompSupplySideLoop.comp->FreeCoolCntrlNodeNum = this->OtherCompDemandSideLoop.inletNodeNum;
1961 0 : break;
1962 : }
1963 0 : default:
1964 0 : break;
1965 : }
1966 : }
1967 7 : if (this->controlMode == ControlType::TrackComponentOnOff) {
1968 0 : if (this->OtherCompSupplySideLoop.inletNodeNum > 0) {
1969 0 : PlantUtilities::ScanPlantLoopsForObject(state,
1970 : this->ComponentUserName,
1971 : this->ComponentType,
1972 : this->OtherCompSupplySideLoop,
1973 : errFlag,
1974 : _,
1975 : _,
1976 : _,
1977 0 : this->OtherCompSupplySideLoop.inletNodeNum,
1978 : _);
1979 : }
1980 0 : if (this->OtherCompDemandSideLoop.inletNodeNum > 0) {
1981 0 : PlantUtilities::ScanPlantLoopsForObject(state,
1982 : this->ComponentUserName,
1983 : this->ComponentType,
1984 : this->OtherCompDemandSideLoop,
1985 : errFlag,
1986 : _,
1987 : _,
1988 : _,
1989 0 : this->OtherCompDemandSideLoop.inletNodeNum,
1990 : _);
1991 : }
1992 : }
1993 :
1994 7 : if (errFlag) {
1995 0 : ShowFatalError(state, format("{} Program terminated due to previous condition(s).", RoutineName));
1996 : }
1997 7 : this->MyFlag = false;
1998 : }
1999 35002 : }
2000 :
2001 : } // namespace EnergyPlus::PlantHeatExchangerFluidToFluid
|