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