Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : #include <EnergyPlus/Coils/CoilCoolingDXCurveFitPerformance.hh>
49 : #include <EnergyPlus/CurveManager.hh>
50 : #include <EnergyPlus/Data/EnergyPlusData.hh>
51 : #include <EnergyPlus/DataEnvironment.hh>
52 : #include <EnergyPlus/DataGlobalConstants.hh>
53 : #include <EnergyPlus/DataHVACGlobals.hh>
54 : #include <EnergyPlus/DataIPShortCuts.hh>
55 : #include <EnergyPlus/Fans.hh>
56 : #include <EnergyPlus/General.hh>
57 : #include <EnergyPlus/GeneralRoutines.hh>
58 : #include <EnergyPlus/HVACFan.hh>
59 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
60 : #include <EnergyPlus/OutputReportPredefined.hh>
61 : #include <EnergyPlus/Psychrometrics.hh>
62 : #include <EnergyPlus/ScheduleManager.hh>
63 : #include <EnergyPlus/UtilityRoutines.hh>
64 :
65 : using namespace EnergyPlus;
66 :
67 51 : void CoilCoolingDXCurveFitPerformance::instantiateFromInputSpec(EnergyPlus::EnergyPlusData &state,
68 : const CoilCoolingDXCurveFitPerformanceInputSpecification &input_data)
69 : {
70 : static constexpr std::string_view routineName("CoilCoolingDXCurveFitOperatingMode::instantiateFromInputSpec: ");
71 51 : bool errorsFound(false);
72 51 : this->original_input_specs = input_data;
73 51 : this->name = input_data.name;
74 51 : this->minOutdoorDrybulb = input_data.minimum_outdoor_dry_bulb_temperature_for_compressor_operation;
75 51 : this->maxOutdoorDrybulbForBasin = input_data.maximum_outdoor_dry_bulb_temperature_for_crankcase_heater_operation;
76 51 : this->crankcaseHeaterCap = input_data.crankcase_heater_capacity;
77 51 : this->normalMode = CoilCoolingDXCurveFitOperatingMode(state, input_data.base_operating_mode_name);
78 51 : this->normalMode.oneTimeInit(state); // oneTimeInit does not need to be delayed in this use case
79 51 : if (UtilityRoutines::SameString(input_data.capacity_control, "CONTINUOUS")) {
80 2 : this->capControlMethod = CapControlMethod::CONTINUOUS;
81 49 : } else if (UtilityRoutines::SameString(input_data.capacity_control, "DISCRETE")) {
82 49 : this->capControlMethod = CapControlMethod::DISCRETE;
83 : } else {
84 0 : ShowSevereError(state, std::string{routineName} + this->object_name + "=\"" + this->name + "\", invalid");
85 0 : ShowContinueError(state, "...Capacity Control Method=\"" + input_data.capacity_control + "\":");
86 0 : ShowContinueError(state, "...must be Discrete or Continuous.");
87 0 : errorsFound = true;
88 : }
89 51 : this->evapCondBasinHeatCap = input_data.basin_heater_capacity;
90 51 : this->evapCondBasinHeatSetpoint = input_data.basin_heater_setpoint_temperature;
91 51 : if (input_data.basin_heater_operating_schedule_name.empty()) {
92 51 : this->evapCondBasinHeatSchedulIndex = DataGlobalConstants::ScheduleAlwaysOn;
93 : } else {
94 0 : this->evapCondBasinHeatSchedulIndex = ScheduleManager::GetScheduleIndex(state, input_data.basin_heater_operating_schedule_name);
95 : }
96 51 : if (this->evapCondBasinHeatSchedulIndex == 0) {
97 0 : ShowSevereError(state, std::string{routineName} + this->object_name + "=\"" + this->name + "\", invalid");
98 0 : ShowContinueError(
99 0 : state, "...Evaporative Condenser Basin Heater Operating Schedule Name=\"" + input_data.basin_heater_operating_schedule_name + "\".");
100 0 : errorsFound = true;
101 : }
102 :
103 51 : if (!input_data.alternate_operating_mode_name.empty() && input_data.alternate_operating_mode2_name.empty()) {
104 5 : this->hasAlternateMode = DataHVACGlobals::coilEnhancedMode;
105 5 : this->alternateMode = CoilCoolingDXCurveFitOperatingMode(state, input_data.alternate_operating_mode_name);
106 5 : this->alternateMode.oneTimeInit(state); // oneTimeInit does not need to be delayed in this use case
107 : }
108 : // Validate fuel type input
109 51 : bool fuelTypeError(false);
110 51 : UtilityRoutines::ValidateFuelTypeWithAssignResourceTypeNum(
111 : input_data.compressor_fuel_type, this->compressorFuelTypeForOutput, this->compressorFuelType, fuelTypeError);
112 51 : if (fuelTypeError) {
113 0 : ShowSevereError(state, std::string{routineName} + this->object_name + "=\"" + this->name + "\", invalid");
114 0 : ShowContinueError(state, "...Compressor Fuel Type=\"" + input_data.compressor_fuel_type + "\".");
115 0 : errorsFound = true;
116 0 : fuelTypeError = false;
117 : }
118 :
119 51 : if (!input_data.alternate_operating_mode2_name.empty() && !input_data.alternate_operating_mode_name.empty()) {
120 1 : this->hasAlternateMode = DataHVACGlobals::coilSubcoolReheatMode;
121 1 : this->alternateMode = CoilCoolingDXCurveFitOperatingMode(state, input_data.alternate_operating_mode_name);
122 1 : this->alternateMode2 = CoilCoolingDXCurveFitOperatingMode(state, input_data.alternate_operating_mode2_name);
123 1 : setOperMode(state, this->normalMode, 1);
124 1 : setOperMode(state, this->alternateMode, 2);
125 1 : setOperMode(state, this->alternateMode2, 3);
126 : }
127 :
128 51 : if (errorsFound) {
129 0 : ShowFatalError(
130 0 : state, std::string{routineName} + "Errors found in getting " + this->object_name + " input. Preceding condition(s) causes termination.");
131 : }
132 51 : }
133 :
134 51 : CoilCoolingDXCurveFitPerformance::CoilCoolingDXCurveFitPerformance(EnergyPlus::EnergyPlusData &state, const std::string &name_to_find)
135 : {
136 51 : int numPerformances = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CoilCoolingDXCurveFitPerformance::object_name);
137 : if (numPerformances <= 0) {
138 : // error
139 : }
140 51 : bool found_it = false;
141 131 : for (int perfNum = 1; perfNum <= numPerformances; ++perfNum) {
142 : int NumAlphas; // Number of Alphas for each GetObjectItem call
143 : int NumNumbers; // Number of Numbers for each GetObjectItem call
144 : int IOStatus;
145 524 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
146 : CoilCoolingDXCurveFitPerformance::object_name,
147 : perfNum,
148 131 : state.dataIPShortCut->cAlphaArgs,
149 : NumAlphas,
150 131 : state.dataIPShortCut->rNumericArgs,
151 : NumNumbers,
152 : IOStatus,
153 : _,
154 131 : state.dataIPShortCut->lAlphaFieldBlanks);
155 131 : if (!UtilityRoutines::SameString(name_to_find, state.dataIPShortCut->cAlphaArgs(1))) {
156 80 : continue;
157 : }
158 51 : found_it = true;
159 :
160 102 : CoilCoolingDXCurveFitPerformanceInputSpecification input_specs;
161 :
162 51 : input_specs.name = state.dataIPShortCut->cAlphaArgs(1);
163 51 : input_specs.crankcase_heater_capacity = state.dataIPShortCut->rNumericArgs(1);
164 51 : input_specs.minimum_outdoor_dry_bulb_temperature_for_compressor_operation = state.dataIPShortCut->rNumericArgs(2);
165 51 : input_specs.maximum_outdoor_dry_bulb_temperature_for_crankcase_heater_operation = state.dataIPShortCut->rNumericArgs(3);
166 51 : if (state.dataIPShortCut->lNumericFieldBlanks(4)) {
167 49 : input_specs.unit_internal_static_air_pressure = 0.0;
168 : } else {
169 2 : input_specs.unit_internal_static_air_pressure = state.dataIPShortCut->rNumericArgs(4);
170 : }
171 51 : input_specs.capacity_control = state.dataIPShortCut->cAlphaArgs(2);
172 51 : input_specs.basin_heater_capacity = state.dataIPShortCut->rNumericArgs(5);
173 51 : input_specs.basin_heater_setpoint_temperature = state.dataIPShortCut->rNumericArgs(6);
174 51 : input_specs.basin_heater_operating_schedule_name = state.dataIPShortCut->cAlphaArgs(3);
175 51 : input_specs.compressor_fuel_type = state.dataIPShortCut->cAlphaArgs(4);
176 51 : input_specs.base_operating_mode_name = state.dataIPShortCut->cAlphaArgs(5);
177 51 : if (!state.dataIPShortCut->lAlphaFieldBlanks(6)) {
178 6 : input_specs.alternate_operating_mode_name = state.dataIPShortCut->cAlphaArgs(6);
179 : }
180 51 : if (!state.dataIPShortCut->lAlphaFieldBlanks(7)) {
181 1 : input_specs.alternate_operating_mode2_name = state.dataIPShortCut->cAlphaArgs(7);
182 : }
183 :
184 51 : this->instantiateFromInputSpec(state, input_specs);
185 51 : break;
186 : }
187 :
188 51 : if (!found_it) {
189 0 : ShowFatalError(state, "Could not find Coil:Cooling:DX:Performance object with name: " + name_to_find);
190 : }
191 51 : }
192 :
193 4511129 : void CoilCoolingDXCurveFitPerformance::simulate(EnergyPlus::EnergyPlusData &state,
194 : const DataLoopNode::NodeData &inletNode,
195 : DataLoopNode::NodeData &outletNode,
196 : int useAlternateMode,
197 : Real64 &PLR,
198 : int &speedNum,
199 : Real64 &speedRatio,
200 : int const fanOpMode,
201 : DataLoopNode::NodeData &condInletNode,
202 : DataLoopNode::NodeData &condOutletNode,
203 : bool const singleMode,
204 : Real64 LoadSHR)
205 : {
206 : static constexpr std::string_view RoutineName = "CoilCoolingDXCurveFitPerformance::simulate";
207 4511129 : Real64 reportingConstant = state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
208 4511129 : this->recoveredEnergyRate = 0.0;
209 4511129 : this->NormalSHR = 0.0;
210 :
211 4511129 : if (useAlternateMode == DataHVACGlobals::coilSubcoolReheatMode) {
212 : Real64 totalCoolingRate;
213 : Real64 sensNorRate;
214 : Real64 sensSubRate;
215 : Real64 sensRehRate;
216 : Real64 latRate;
217 : Real64 SysNorSHR;
218 : Real64 SysSubSHR;
219 : Real64 SysRehSHR;
220 : Real64 HumRatNorOut;
221 : Real64 TempNorOut;
222 : Real64 EnthalpyNorOut;
223 : Real64 modeRatio;
224 :
225 76768 : this->calculate(
226 : state, this->normalMode, inletNode, outletNode, PLR, speedNum, speedRatio, fanOpMode, condInletNode, condOutletNode, singleMode);
227 :
228 : // this->OperatingMode = 1;
229 153536 : CalcComponentSensibleLatentOutput(
230 76768 : outletNode.MassFlowRate, inletNode.Temp, inletNode.HumRat, outletNode.Temp, outletNode.HumRat, sensNorRate, latRate, totalCoolingRate);
231 76768 : if (totalCoolingRate > 1.0E-10) {
232 25544 : this->OperatingMode = 1;
233 25544 : this->NormalSHR = sensNorRate / totalCoolingRate;
234 25544 : this->powerUse = this->normalMode.OpModePower;
235 25544 : this->RTF = this->normalMode.OpModeRTF;
236 25544 : this->wasteHeatRate = this->normalMode.OpModeWasteHeat;
237 : }
238 :
239 76768 : if ((PLR != 0.0) && (LoadSHR != 0.0)) {
240 7680 : if (totalCoolingRate == 0.0) {
241 0 : SysNorSHR = 1.0;
242 : } else {
243 7680 : SysNorSHR = sensNorRate / totalCoolingRate;
244 : }
245 7680 : HumRatNorOut = outletNode.HumRat;
246 7680 : TempNorOut = outletNode.Temp;
247 7680 : EnthalpyNorOut = outletNode.Enthalpy;
248 7680 : this->recoveredEnergyRate = sensNorRate;
249 :
250 7680 : if (LoadSHR < SysNorSHR) {
251 4832 : outletNode.MassFlowRate = inletNode.MassFlowRate;
252 4832 : this->calculate(state,
253 : this->alternateMode,
254 : inletNode,
255 : outletNode,
256 : PLR,
257 : speedNum,
258 : speedRatio,
259 : fanOpMode,
260 : condInletNode,
261 : condOutletNode,
262 : singleMode);
263 9664 : CalcComponentSensibleLatentOutput(outletNode.MassFlowRate,
264 4832 : inletNode.Temp,
265 4832 : inletNode.HumRat,
266 : outletNode.Temp,
267 : outletNode.HumRat,
268 : sensSubRate,
269 : latRate,
270 : totalCoolingRate);
271 4832 : SysSubSHR = sensSubRate / totalCoolingRate;
272 4832 : if (LoadSHR < SysSubSHR) {
273 4832 : outletNode.MassFlowRate = inletNode.MassFlowRate;
274 4832 : this->calculate(state,
275 : this->alternateMode2,
276 : inletNode,
277 : outletNode,
278 : PLR,
279 : speedNum,
280 : speedRatio,
281 : fanOpMode,
282 : condInletNode,
283 : condOutletNode,
284 : singleMode);
285 9664 : CalcComponentSensibleLatentOutput(outletNode.MassFlowRate,
286 4832 : inletNode.Temp,
287 4832 : inletNode.HumRat,
288 : outletNode.Temp,
289 : outletNode.HumRat,
290 : sensRehRate,
291 : latRate,
292 : totalCoolingRate);
293 4832 : SysRehSHR = sensRehRate / totalCoolingRate;
294 4832 : if (LoadSHR > SysRehSHR) {
295 4096 : modeRatio = (LoadSHR - SysNorSHR) / (SysRehSHR - SysNorSHR);
296 4096 : this->OperatingMode = 3;
297 4096 : outletNode.HumRat = HumRatNorOut * (1.0 - modeRatio) + modeRatio * outletNode.HumRat;
298 4096 : outletNode.Enthalpy = EnthalpyNorOut * (1.0 - modeRatio) + modeRatio * outletNode.Enthalpy;
299 4096 : outletNode.Temp = Psychrometrics::PsyTdbFnHW(outletNode.Enthalpy, outletNode.HumRat);
300 4096 : this->ModeRatio = modeRatio;
301 : // update other reporting terms
302 4096 : this->powerUse = this->normalMode.OpModePower * (1.0 - modeRatio) + modeRatio * this->alternateMode2.OpModePower;
303 4096 : this->RTF = this->normalMode.OpModeRTF * (1.0 - modeRatio) + modeRatio * this->alternateMode2.OpModeRTF;
304 4096 : this->wasteHeatRate = this->normalMode.OpModeWasteHeat * (1.0 - modeRatio) + modeRatio * this->alternateMode2.OpModeWasteHeat;
305 4096 : this->recoveredEnergyRate = (this->recoveredEnergyRate - sensRehRate) * this->ModeRatio;
306 : } else {
307 736 : this->ModeRatio = 1.0;
308 736 : this->OperatingMode = 3;
309 736 : this->recoveredEnergyRate = (this->recoveredEnergyRate - sensRehRate) * this->ModeRatio;
310 : }
311 : } else {
312 0 : modeRatio = (LoadSHR - SysNorSHR) / (SysSubSHR - SysNorSHR);
313 0 : this->OperatingMode = 2;
314 : // process outlet conditions and total output
315 0 : outletNode.HumRat = HumRatNorOut * (1.0 - modeRatio) + modeRatio * outletNode.HumRat;
316 0 : outletNode.Enthalpy = EnthalpyNorOut * (1.0 - modeRatio) + modeRatio * outletNode.Enthalpy;
317 0 : outletNode.Temp = Psychrometrics::PsyTdbFnHW(outletNode.Enthalpy, outletNode.HumRat);
318 0 : this->ModeRatio = modeRatio;
319 : // update other reporting terms
320 0 : this->powerUse = this->normalMode.OpModePower * (1.0 - modeRatio) + modeRatio * this->alternateMode.OpModePower;
321 0 : this->RTF = this->normalMode.OpModeRTF * (1.0 - modeRatio) + modeRatio * this->alternateMode.OpModeRTF;
322 0 : this->wasteHeatRate = this->normalMode.OpModeWasteHeat * (1.0 - modeRatio) + modeRatio * this->alternateMode.OpModeWasteHeat;
323 0 : this->recoveredEnergyRate = (this->recoveredEnergyRate - sensSubRate) * this->ModeRatio;
324 : }
325 : } else {
326 2848 : this->ModeRatio = 0.0;
327 2848 : this->OperatingMode = 1;
328 2848 : this->recoveredEnergyRate = 0.0;
329 : }
330 : // Check for saturation error and modify temperature at constant enthalpy
331 7680 : Real64 tsat = Psychrometrics::PsyTsatFnHPb(state, outletNode.Enthalpy, inletNode.Press, RoutineName);
332 7680 : if (outletNode.Temp < tsat) {
333 0 : outletNode.Temp = tsat;
334 0 : outletNode.HumRat = Psychrometrics::PsyWFnTdbH(state, tsat, outletNode.Enthalpy);
335 : }
336 : }
337 4434361 : } else if (useAlternateMode == DataHVACGlobals::coilEnhancedMode) {
338 0 : this->calculate(
339 : state, this->alternateMode, inletNode, outletNode, PLR, speedNum, speedRatio, fanOpMode, condInletNode, condOutletNode, singleMode);
340 0 : this->OperatingMode = 2;
341 0 : this->powerUse = this->alternateMode.OpModePower;
342 0 : this->RTF = this->alternateMode.OpModeRTF;
343 0 : this->wasteHeatRate = this->alternateMode.OpModeWasteHeat;
344 : } else {
345 4434361 : this->calculate(
346 : state, this->normalMode, inletNode, outletNode, PLR, speedNum, speedRatio, fanOpMode, condInletNode, condOutletNode, singleMode);
347 4434361 : this->OperatingMode = 1;
348 4434361 : this->powerUse = this->normalMode.OpModePower;
349 4434361 : this->RTF = this->normalMode.OpModeRTF;
350 4434361 : this->wasteHeatRate = this->normalMode.OpModeWasteHeat;
351 : }
352 :
353 : // calculate crankcase heater operation
354 4511129 : if (state.dataEnvrn->OutDryBulbTemp < this->maxOutdoorDrybulbForBasin) {
355 1093704 : this->crankcaseHeaterPower = this->crankcaseHeaterCap;
356 : } else {
357 3417425 : this->crankcaseHeaterPower = 0.0;
358 : }
359 4511129 : this->crankcaseHeaterPower = this->crankcaseHeaterPower * (1.0 - this->RTF);
360 4511129 : this->crankcaseHeaterElectricityConsumption = this->crankcaseHeaterPower * reportingConstant;
361 :
362 : // basin heater
363 4511129 : if (this->evapCondBasinHeatSchedulIndex > 0) {
364 0 : Real64 currentBasinHeaterAvail = ScheduleManager::GetCurrentScheduleValue(state, this->evapCondBasinHeatSchedulIndex);
365 0 : if (this->evapCondBasinHeatCap > 0.0 && currentBasinHeaterAvail > 0.0) {
366 0 : this->basinHeaterPower = max(0.0, this->evapCondBasinHeatCap * (this->evapCondBasinHeatSetpoint - state.dataEnvrn->OutDryBulbTemp));
367 : }
368 : } else {
369 : // If schedule does not exist, basin heater operates anytime outdoor dry-bulb temp is below setpoint
370 4511129 : if (this->evapCondBasinHeatCap > 0.0) {
371 0 : this->basinHeaterPower = max(0.0, this->evapCondBasinHeatCap * (this->evapCondBasinHeatSetpoint - state.dataEnvrn->OutDryBulbTemp));
372 : }
373 : }
374 4511129 : this->basinHeaterPower *= (1.0 - this->RTF);
375 4511129 : this->electricityConsumption = this->powerUse * reportingConstant;
376 :
377 4511129 : if (this->compressorFuelType != DataGlobalConstants::ResourceType::Electricity) {
378 0 : this->compressorFuelRate = this->powerUse;
379 0 : this->compressorFuelConsumption = this->electricityConsumption;
380 :
381 : // check this after adding parasitic loads
382 0 : this->powerUse = 0.0;
383 0 : this->electricityConsumption = 0.0;
384 : }
385 4511129 : }
386 :
387 51 : void CoilCoolingDXCurveFitPerformance::size(EnergyPlus::EnergyPlusData &state)
388 : {
389 51 : if (!state.dataGlobal->SysSizingCalc && this->mySizeFlag) {
390 51 : this->normalMode.parentName = this->parentName;
391 51 : this->normalMode.size(state);
392 51 : if (this->hasAlternateMode == DataHVACGlobals::coilEnhancedMode) {
393 5 : this->alternateMode.size(state);
394 : }
395 51 : if (this->hasAlternateMode == DataHVACGlobals::coilSubcoolReheatMode) {
396 1 : this->alternateMode.size(state);
397 1 : this->alternateMode2.size(state);
398 : }
399 51 : this->mySizeFlag = false;
400 : }
401 51 : }
402 :
403 4520793 : void CoilCoolingDXCurveFitPerformance::calculate(EnergyPlus::EnergyPlusData &state,
404 : CoilCoolingDXCurveFitOperatingMode ¤tMode,
405 : const DataLoopNode::NodeData &inletNode,
406 : DataLoopNode::NodeData &outletNode,
407 : Real64 &PLR,
408 : int &speedNum,
409 : Real64 &speedRatio,
410 : int const fanOpMode,
411 : DataLoopNode::NodeData &condInletNode,
412 : DataLoopNode::NodeData &condOutletNode,
413 : bool const singleMode)
414 : {
415 :
416 : // calculate the performance at this mode/speed
417 4520793 : currentMode.CalcOperatingMode(state, inletNode, outletNode, PLR, speedNum, speedRatio, fanOpMode, condInletNode, condOutletNode, singleMode);
418 4520793 : }
419 :
420 51 : void CoilCoolingDXCurveFitPerformance::calcStandardRatings210240(EnergyPlus::EnergyPlusData &state)
421 : {
422 :
423 : // for now this will provide standard ratings for the coil at the normal mode at speed N
424 : // future iterations will extend the inputs to give the user the flexibility to select different standards to
425 : // apply and such
426 :
427 51 : int constexpr NumOfReducedCap(4); // Number of reduced capacity test conditions (100%,75%,50%,and 25%)
428 :
429 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
430 51 : Real64 TotCapFlowModFac(0.0); // Total capacity modifier f(actual flow vs rated flow) for each speed [-]
431 51 : Real64 EIRFlowModFac(0.0); // EIR modifier f(actual supply air flow vs rated flow) for each speed [-]
432 51 : Real64 TotCapTempModFac(0.0); // Total capacity modifier (function of entering wetbulb, outside drybulb) [-]
433 51 : Real64 EIRTempModFac(0.0); // EIR modifier (function of entering wetbulb, outside drybulb) [-]
434 51 : Real64 TotCoolingCapAHRI(0.0); // Total Cooling Coil capacity (gross) at AHRI test conditions [W]
435 51 : Real64 NetCoolingCapAHRI(0.0); // Net Cooling Coil capacity at AHRI TestB conditions, accounting for fan heat [W]
436 51 : Real64 NetCoolingCapAHRI2023(0.0); // Net Cooling Coil capacity at AHRI TestB conditions, accounting for fan heat [W]
437 51 : Real64 TotalElecPower(0.0); // Net power consumption (Cond Fan+Compressor+Indoor Fan) at AHRI test conditions [W]
438 51 : Real64 TotalElecPower2023(0.0); // Net power consumption (Cond Fan+Compressor+Indoor Fan) at AHRI test conditions [W]
439 51 : Real64 TotalElecPowerRated(0.0); // Net power consumption (Cond Fan+Compressor+Indoor Fan) at Rated test conditions [W]
440 51 : Real64 TotalElecPowerRated2023(0.0); // Net power consumption (Cond Fan+Compressor+Indoor Fan) at Rated test conditions [W]
441 51 : Real64 EIR(0.0); // Energy Efficiency Ratio at AHRI test conditions for SEER [-]
442 51 : Real64 PartLoadFactor(0.0); // Part load factor, accounts for thermal lag at compressor startup [-]
443 51 : Real64 EERReduced(0.0); // EER at reduced capacity test conditions (100%, 75%, 50%, and 25%)
444 51 : Real64 ElecPowerReducedCap(0.0); // Net power consumption (Cond Fan+Compressor) at reduced test condition [W]
445 51 : Real64 NetCoolingCapReduced(0.0); // Net Cooling Coil capacity at reduced conditions, accounting for supply fan heat [W]
446 51 : Real64 LoadFactor(0.0); // Fractional "on" time for last stage at the desired reduced capacity, (dimensionless)
447 51 : Real64 DegradationCoeff(0.0); // Degradation coeficient, (dimenssionless)
448 : Real64 OutdoorUnitInletAirDryBulbTempReduced; // Outdoor unit entering air dry-bulb temperature at reduced capacity [C]
449 : int RedCapNum; // Integer counter for reduced capacity
450 :
451 : // *** SOME CONSTANTS FROM THE STANDARD
452 : // The AHRI standard specifies a nominal/default fan electric power consumption per rated air
453 : // volume flow rate to account for indoor fan electric power consumption
454 : // when the standard tests are conducted on units that do not have an
455 : // indoor air circulating fan. Used if user doesn't enter a specific value.
456 51 : Real64 constexpr DefaultFanPowerPerEvapAirFlowRate(773.3); // 365 W/1000 scfm or 773.3 W/(m3/s).
457 51 : Real64 constexpr DefaultFanPowerPerEvapAirFlowRate2023(934.4); // 441 W/1000 scfm or 934.4 W/(m3/s).
458 : // AHRI Standard 210/240-2008 Performance Test Conditions for Unitary Air-to-Air Air-Conditioning and Heat Pump Equipment
459 51 : Real64 constexpr CoolingCoilInletAirWetBulbTempRated(19.44); // 19.44C (67F) Tests A and B
460 51 : Real64 constexpr OutdoorUnitInletAirDryBulbTemp(27.78); // 27.78C (82F) Test B (for SEER)
461 51 : Real64 constexpr OutdoorUnitInletAirDryBulbTempRated(35.0); // 35.00C (95F) Test A (rated capacity)
462 51 : Real64 constexpr AirMassFlowRatioRated(1.0); // AHRI test is at the design flow rate so AirMassFlowRatio is 1.0
463 51 : Real64 constexpr PLRforSEER(0.5); // Part-load ratio for SEER calculation (single speed DX cooling coils)
464 : static constexpr std::array<Real64, 4> ReducedPLR = {1.0, 0.75, 0.50, 0.25}; // Reduced Capacity part-load conditions
465 : static constexpr std::array<Real64, 4> IEERWeightingFactor = {0.020, 0.617, 0.238, 0.125}; // EER Weighting factors (IEER)
466 51 : Real64 constexpr OADBTempLowReducedCapacityTest(18.3); // Outdoor air dry-bulb temp in degrees C (65F)
467 :
468 : // For Single Stage Systems, if the optional CFull and DFull tests are not performed, a
469 : // default value of 0.20 shall be used for the cooling Degradation Coefficient
470 51 : Real64 constexpr CyclicDegradationCoefficient(0.20); // ANSI/AHRI 210/240 2023 Section 6.1.3.1
471 :
472 : // some conveniences
473 51 : auto &mode = this->normalMode;
474 51 : auto &speed = mode.speeds.back();
475 :
476 51 : Real64 FanPowerPerEvapAirFlowRate = DefaultFanPowerPerEvapAirFlowRate;
477 51 : if (speed.rated_evap_fan_power_per_volume_flow_rate > 0.0) {
478 51 : FanPowerPerEvapAirFlowRate = speed.rated_evap_fan_power_per_volume_flow_rate;
479 : }
480 :
481 51 : Real64 FanPowerPerEvapAirFlowRate2023 = DefaultFanPowerPerEvapAirFlowRate2023;
482 51 : if (speed.rated_evap_fan_power_per_volume_flow_rate_2023 > 0.0) {
483 51 : FanPowerPerEvapAirFlowRate2023 = speed.rated_evap_fan_power_per_volume_flow_rate_2023;
484 : }
485 :
486 51 : if (mode.ratedGrossTotalCap > 0.0) {
487 : // SEER calculations:
488 51 : TotCapFlowModFac = Curve::CurveValue(state, speed.indexCapFFF, AirMassFlowRatioRated);
489 51 : TotCapTempModFac = Curve::CurveValue(state, speed.indexCapFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTemp);
490 51 : TotCoolingCapAHRI = mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac;
491 51 : EIRTempModFac = Curve::CurveValue(state, speed.indexEIRFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTemp);
492 51 : EIRFlowModFac = Curve::CurveValue(state, speed.indexEIRFFF, AirMassFlowRatioRated);
493 51 : if (speed.ratedCOP > 0.0) { // RatedCOP <= 0.0 is trapped in GetInput, but keep this as "safety"
494 51 : EIR = EIRTempModFac * EIRFlowModFac / speed.ratedCOP;
495 : } else {
496 0 : EIR = 0.0;
497 : }
498 :
499 : // Calculate net cooling capacity
500 51 : NetCoolingCapAHRI = TotCoolingCapAHRI - FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
501 51 : TotalElecPower = EIR * TotCoolingCapAHRI + FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
502 :
503 51 : NetCoolingCapAHRI2023 = TotCoolingCapAHRI - FanPowerPerEvapAirFlowRate2023 * mode.ratedEvapAirFlowRate;
504 51 : TotalElecPower2023 = EIR * TotCoolingCapAHRI + FanPowerPerEvapAirFlowRate2023 * mode.ratedEvapAirFlowRate;
505 : // Calculate SEER value from the Energy Efficiency Ratio (EER) at the AHRI test conditions and the part load factor.
506 : // First evaluate the Part Load Factor curve at PLR = 0.5 (AHRI Standard 210/240)
507 51 : PartLoadFactor = Curve::CurveValue(state, speed.indexPLRFPLF, PLRforSEER);
508 51 : if (TotalElecPower > 0.0) {
509 51 : this->standardRatingSEER = (NetCoolingCapAHRI / TotalElecPower) * PartLoadFactor;
510 : } else {
511 0 : this->standardRatingSEER = 0.0;
512 : }
513 :
514 51 : Real64 PartLoadFactorStandard = 1.0 - (1 - PLRforSEER) * CyclicDegradationCoefficient;
515 51 : if (TotalElecPower2023 > 0.0) {
516 51 : this->standardRatingSEER2_User = (NetCoolingCapAHRI2023 / TotalElecPower2023) * PartLoadFactor;
517 51 : this->standardRatingSEER2_Standard = (NetCoolingCapAHRI2023 / TotalElecPower2023) * PartLoadFactorStandard;
518 : } else {
519 0 : this->standardRatingSEER2_User = 0.0;
520 0 : this->standardRatingSEER2_Standard = 0.0;
521 : }
522 :
523 : // EER calculations:
524 : // Calculate the net cooling capacity at the rated conditions (19.44C WB and 35.0C DB )
525 51 : TotCapTempModFac = Curve::CurveValue(state, speed.indexCapFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTempRated);
526 51 : this->standardRatingCoolingCapacity =
527 51 : mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac - FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
528 51 : this->standardRatingCoolingCapacity2023 =
529 51 : mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac - FanPowerPerEvapAirFlowRate2023 * mode.ratedEvapAirFlowRate;
530 : // Calculate Energy Efficiency Ratio (EER) at (19.44C WB and 35.0C DB ), ANSI/AHRI Std. 340/360
531 51 : EIRTempModFac = Curve::CurveValue(state, speed.indexEIRFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTempRated);
532 51 : if (speed.ratedCOP > 0.0) {
533 : // RatedCOP <= 0.0 is trapped in GetInput, but keep this as "safety"
534 51 : EIR = EIRTempModFac * EIRFlowModFac / speed.ratedCOP;
535 : } else {
536 0 : EIR = 0.0;
537 : }
538 51 : TotalElecPowerRated =
539 51 : EIR * (mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac) + FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
540 51 : if (TotalElecPowerRated > 0.0) {
541 51 : this->standardRatingEER = this->standardRatingCoolingCapacity / TotalElecPowerRated;
542 : } else {
543 0 : this->standardRatingEER = 0.0;
544 : }
545 51 : TotalElecPowerRated2023 =
546 51 : EIR * (mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac) + FanPowerPerEvapAirFlowRate2023 * mode.ratedEvapAirFlowRate;
547 51 : if (TotalElecPowerRated2023 > 0.0) {
548 51 : this->standardRatingEER2 = this->standardRatingCoolingCapacity2023 / TotalElecPowerRated2023;
549 : } else {
550 0 : this->standardRatingEER2 = 0.0;
551 : }
552 :
553 : // IEER calculations:
554 51 : this->standardRatingIEER = 0.0;
555 : // Calculate the net cooling capacity at the rated conditions (19.44C WB and 35.0C DB )
556 51 : TotCapTempModFac = Curve::CurveValue(state, speed.indexCapFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTempRated);
557 51 : this->standardRatingCoolingCapacity =
558 51 : mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac - FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
559 51 : this->standardRatingCoolingCapacity2023 =
560 51 : mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac - FanPowerPerEvapAirFlowRate2023 * mode.ratedEvapAirFlowRate;
561 255 : for (RedCapNum = 0; RedCapNum < NumOfReducedCap; ++RedCapNum) {
562 : // get the outdoor air dry bulb temperature for the reduced capacity test conditions
563 204 : if (ReducedPLR[RedCapNum] > 0.444) {
564 153 : OutdoorUnitInletAirDryBulbTempReduced = 5.0 + 30.0 * ReducedPLR[RedCapNum];
565 : } else {
566 51 : OutdoorUnitInletAirDryBulbTempReduced = OADBTempLowReducedCapacityTest;
567 : }
568 204 : TotCapTempModFac = Curve::CurveValue(state, speed.indexCapFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTempReduced);
569 204 : NetCoolingCapReduced =
570 204 : mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac - FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
571 204 : EIRTempModFac = Curve::CurveValue(state, speed.indexEIRFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTempReduced);
572 204 : if (speed.ratedCOP > 0.0) {
573 204 : EIR = EIRTempModFac * EIRFlowModFac / speed.ratedCOP;
574 : } else {
575 0 : EIR = 0.0;
576 : }
577 204 : if (NetCoolingCapReduced > 0.0) {
578 204 : LoadFactor = ReducedPLR[RedCapNum] * this->standardRatingCoolingCapacity / NetCoolingCapReduced;
579 : } else {
580 0 : LoadFactor = 1.0;
581 : }
582 204 : DegradationCoeff = 1.130 - 0.130 * LoadFactor;
583 204 : ElecPowerReducedCap = DegradationCoeff * EIR * (mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac);
584 204 : EERReduced =
585 204 : (LoadFactor * NetCoolingCapReduced) / (LoadFactor * ElecPowerReducedCap + FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate);
586 204 : this->standardRatingIEER += IEERWeightingFactor[RedCapNum] * EERReduced;
587 : }
588 :
589 : } else {
590 0 : ShowSevereError(state,
591 0 : "Standard Ratings: Coil:Cooling:DX " + this->name + // TODO: Use dynamic COIL TYPE and COIL INSTANCE name later
592 : " has zero rated total cooling capacity. Standard ratings cannot be calculated.");
593 : }
594 51 : }
595 :
596 3 : void CoilCoolingDXCurveFitPerformance::setOperMode(EnergyPlus::EnergyPlusData &state, CoilCoolingDXCurveFitOperatingMode ¤tMode, int const mode)
597 : {
598 : // set parent mode for each speed
599 : int numSpeeds;
600 3 : bool errorsFound = false;
601 :
602 3 : numSpeeds = (int)currentMode.speeds.size();
603 6 : for (int speedNum = 0; speedNum < numSpeeds; speedNum++) {
604 3 : currentMode.speeds[speedNum].parentOperatingMode = mode;
605 3 : if (mode == 2) {
606 1 : if (currentMode.speeds[speedNum].indexSHRFT == 0) {
607 0 : ShowSevereError(state, currentMode.speeds[speedNum].object_name + "=\"" + currentMode.speeds[speedNum].name + "\", Curve check:");
608 0 : ShowContinueError(state,
609 : "The input of Sensible Heat Ratio Modifier Function of Temperature Curve Name is required, but not available for "
610 : "SubcoolReheat mode. Please input");
611 0 : errorsFound = true;
612 : }
613 1 : if (currentMode.speeds[speedNum].indexSHRFFF == 0) {
614 0 : ShowSevereError(state, currentMode.speeds[speedNum].object_name + "=\"" + currentMode.speeds[speedNum].name + "\", Curve check:");
615 0 : ShowContinueError(state,
616 : "The input of Sensible Heat Ratio Modifier Function of Flow Fraction Curve Name is required, but not available for "
617 : "SubcoolReheat mode. Please input");
618 0 : errorsFound = true;
619 : }
620 : }
621 3 : if (mode == 3) {
622 1 : if (currentMode.speeds[speedNum].indexSHRFT == 0) {
623 0 : ShowSevereError(state, currentMode.speeds[speedNum].object_name + "=\"" + currentMode.speeds[speedNum].name + "\", Curve check:");
624 0 : ShowContinueError(state,
625 : "The input of Sensible Heat Ratio Modifier Function of Temperature Curve Name is required, but not available for "
626 : "SubcoolReheat mode. Please input");
627 0 : errorsFound = true;
628 : }
629 1 : if (currentMode.speeds[speedNum].indexSHRFFF == 0) {
630 0 : ShowSevereError(state, currentMode.speeds[speedNum].object_name + "=\"" + currentMode.speeds[speedNum].name + "\", Curve check:");
631 0 : ShowContinueError(state,
632 : "The input of Sensible Heat Ratio Modifier Function of Flow Fraction Curve Name is required, but not available for "
633 : "SubcoolReheat mode. Please input");
634 0 : errorsFound = true;
635 : }
636 : }
637 : }
638 3 : if (errorsFound) {
639 0 : ShowFatalError(state,
640 0 : "CoilCoolingDXCurveFitPerformance: Errors found in getting " + this->object_name +
641 : " input. Preceding condition(s) causes termination.");
642 : }
643 2316 : }
|