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