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