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