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 : #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 54 : void CoilCoolingDXCurveFitPerformance::instantiateFromInputSpec(EnergyPlus::EnergyPlusData &state,
67 : const CoilCoolingDXCurveFitPerformanceInputSpecification &input_data)
68 : {
69 : static constexpr std::string_view routineName("CoilCoolingDXCurveFitOperatingMode::instantiateFromInputSpec: ");
70 54 : bool errorsFound(false);
71 54 : this->original_input_specs = input_data;
72 54 : this->name = input_data.name;
73 54 : this->minOutdoorDrybulb = input_data.minimum_outdoor_dry_bulb_temperature_for_compressor_operation;
74 54 : this->maxOutdoorDrybulbForBasin = input_data.maximum_outdoor_dry_bulb_temperature_for_crankcase_heater_operation;
75 54 : this->crankcaseHeaterCap = input_data.crankcase_heater_capacity;
76 54 : this->normalMode = CoilCoolingDXCurveFitOperatingMode(state, input_data.base_operating_mode_name);
77 54 : this->normalMode.oneTimeInit(state); // oneTimeInit does not need to be delayed in this use case
78 54 : if (Util::SameString(input_data.capacity_control, "CONTINUOUS")) {
79 2 : this->capControlMethod = CapControlMethod::CONTINUOUS;
80 52 : } else if (Util::SameString(input_data.capacity_control, "DISCRETE")) {
81 52 : this->capControlMethod = CapControlMethod::DISCRETE;
82 : } else {
83 0 : ShowSevereError(state, std::string{routineName} + this->object_name + "=\"" + this->name + "\", invalid");
84 0 : ShowContinueError(state, "...Capacity Control Method=\"" + input_data.capacity_control + "\":");
85 0 : ShowContinueError(state, "...must be Discrete or Continuous.");
86 0 : errorsFound = true;
87 : }
88 54 : this->evapCondBasinHeatCap = input_data.basin_heater_capacity;
89 54 : this->evapCondBasinHeatSetpoint = input_data.basin_heater_setpoint_temperature;
90 54 : if (input_data.basin_heater_operating_schedule_name.empty()) {
91 54 : this->evapCondBasinHeatSchedulIndex = ScheduleManager::ScheduleAlwaysOn;
92 : } else {
93 0 : this->evapCondBasinHeatSchedulIndex = ScheduleManager::GetScheduleIndex(state, input_data.basin_heater_operating_schedule_name);
94 : }
95 54 : if (this->evapCondBasinHeatSchedulIndex == 0) {
96 0 : ShowSevereError(state, std::string{routineName} + this->object_name + "=\"" + this->name + "\", invalid");
97 0 : ShowContinueError(
98 0 : state, "...Evaporative Condenser Basin Heater Operating Schedule Name=\"" + input_data.basin_heater_operating_schedule_name + "\".");
99 0 : errorsFound = true;
100 : }
101 :
102 54 : if (!input_data.alternate_operating_mode_name.empty() && input_data.alternate_operating_mode2_name.empty()) {
103 5 : this->maxAvailCoilMode = HVAC::CoilMode::Enhanced;
104 5 : this->alternateMode = CoilCoolingDXCurveFitOperatingMode(state, input_data.alternate_operating_mode_name);
105 5 : this->alternateMode.oneTimeInit(state); // oneTimeInit does not need to be delayed in this use case
106 : }
107 : // Validate fuel type input
108 54 : this->compressorFuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, Util::makeUPPER(input_data.compressor_fuel_type)));
109 54 : 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 54 : 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 54 : if (!input_data.outdoor_temperature_dependent_crankcase_heater_capacity_curve_name.empty()) {
125 0 : this->crankcaseHeaterCapacityCurveIndex =
126 0 : Curve::GetCurveIndex(state, input_data.outdoor_temperature_dependent_crankcase_heater_capacity_curve_name);
127 : // Verify Curve Object, only legal type is Quadratic and Cubic
128 0 : errorsFound |= Curve::CheckCurveDims(state,
129 : this->crankcaseHeaterCapacityCurveIndex, // Curve index
130 : {1}, // Valid dimensions
131 : routineName, // Routine name
132 : this->object_name, // Object Type
133 : this->name, // Object Name
134 : input_data.outdoor_temperature_dependent_crankcase_heater_capacity_curve_name); // Field Name
135 : }
136 54 : if (errorsFound) {
137 0 : ShowFatalError(
138 0 : state, std::string{routineName} + "Errors found in getting " + this->object_name + " input. Preceding condition(s) causes termination.");
139 : }
140 54 : }
141 :
142 54 : CoilCoolingDXCurveFitPerformance::CoilCoolingDXCurveFitPerformance(EnergyPlus::EnergyPlusData &state, const std::string &name_to_find)
143 : {
144 54 : int numPerformances = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CoilCoolingDXCurveFitPerformance::object_name);
145 : if (numPerformances <= 0) {
146 : // error
147 : }
148 54 : bool found_it = false;
149 137 : for (int perfNum = 1; perfNum <= numPerformances; ++perfNum) {
150 : int NumAlphas; // Number of Alphas for each GetObjectItem call
151 : int NumNumbers; // Number of Numbers for each GetObjectItem call
152 : int IOStatus;
153 411 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
154 : CoilCoolingDXCurveFitPerformance::object_name,
155 : perfNum,
156 137 : state.dataIPShortCut->cAlphaArgs,
157 : NumAlphas,
158 137 : state.dataIPShortCut->rNumericArgs,
159 : NumNumbers,
160 : IOStatus,
161 : _,
162 137 : state.dataIPShortCut->lAlphaFieldBlanks);
163 137 : if (!Util::SameString(name_to_find, state.dataIPShortCut->cAlphaArgs(1))) {
164 83 : continue;
165 : }
166 54 : found_it = true;
167 :
168 54 : CoilCoolingDXCurveFitPerformanceInputSpecification input_specs;
169 :
170 54 : input_specs.name = state.dataIPShortCut->cAlphaArgs(1);
171 54 : input_specs.crankcase_heater_capacity = state.dataIPShortCut->rNumericArgs(1);
172 54 : input_specs.minimum_outdoor_dry_bulb_temperature_for_compressor_operation = state.dataIPShortCut->rNumericArgs(2);
173 54 : input_specs.maximum_outdoor_dry_bulb_temperature_for_crankcase_heater_operation = state.dataIPShortCut->rNumericArgs(3);
174 54 : if (state.dataIPShortCut->lNumericFieldBlanks(4)) {
175 52 : input_specs.unit_internal_static_air_pressure = 0.0;
176 : } else {
177 2 : input_specs.unit_internal_static_air_pressure = state.dataIPShortCut->rNumericArgs(4);
178 : }
179 54 : if (!state.dataIPShortCut->lAlphaFieldBlanks(2)) {
180 0 : input_specs.outdoor_temperature_dependent_crankcase_heater_capacity_curve_name = state.dataIPShortCut->cAlphaArgs(2);
181 : }
182 54 : input_specs.capacity_control = state.dataIPShortCut->cAlphaArgs(3);
183 54 : input_specs.basin_heater_capacity = state.dataIPShortCut->rNumericArgs(5);
184 54 : input_specs.basin_heater_setpoint_temperature = state.dataIPShortCut->rNumericArgs(6);
185 54 : input_specs.basin_heater_operating_schedule_name = state.dataIPShortCut->cAlphaArgs(4);
186 54 : input_specs.compressor_fuel_type = state.dataIPShortCut->cAlphaArgs(5);
187 54 : input_specs.base_operating_mode_name = state.dataIPShortCut->cAlphaArgs(6);
188 54 : if (!state.dataIPShortCut->lAlphaFieldBlanks(6)) {
189 54 : input_specs.alternate_operating_mode_name = state.dataIPShortCut->cAlphaArgs(7);
190 : }
191 54 : if (!state.dataIPShortCut->lAlphaFieldBlanks(8)) {
192 1 : input_specs.alternate_operating_mode2_name = state.dataIPShortCut->cAlphaArgs(8);
193 : }
194 :
195 54 : this->instantiateFromInputSpec(state, input_specs);
196 54 : break;
197 54 : }
198 :
199 54 : if (!found_it) {
200 0 : ShowFatalError(state, "Could not find Coil:Cooling:DX:Performance object with name: " + name_to_find);
201 : }
202 54 : }
203 :
204 11256494 : void CoilCoolingDXCurveFitPerformance::simulate(EnergyPlus::EnergyPlusData &state,
205 : const DataLoopNode::NodeData &inletNode,
206 : DataLoopNode::NodeData &outletNode,
207 : HVAC::CoilMode currentCoilMode,
208 : Real64 &PLR,
209 : int &speedNum,
210 : Real64 &speedRatio,
211 : HVAC::FanOp const fanOp,
212 : DataLoopNode::NodeData &condInletNode,
213 : DataLoopNode::NodeData &condOutletNode,
214 : bool const singleMode,
215 : Real64 LoadSHR)
216 : {
217 : static constexpr std::string_view RoutineName = "CoilCoolingDXCurveFitPerformance::simulate";
218 11256494 : Real64 reportingConstant = state.dataHVACGlobal->TimeStepSys * Constant::SecInHour;
219 11256494 : this->recoveredEnergyRate = 0.0;
220 11256494 : this->NormalSHR = 0.0;
221 :
222 11256494 : if (currentCoilMode == HVAC::CoilMode::SubcoolReheat) {
223 : Real64 totalCoolingRate;
224 : Real64 sensNorRate;
225 : Real64 sensSubRate;
226 : Real64 sensRehRate;
227 : Real64 latRate;
228 : Real64 SysNorSHR;
229 : Real64 SysSubSHR;
230 : Real64 SysRehSHR;
231 : Real64 HumRatNorOut;
232 : Real64 TempNorOut;
233 : Real64 EnthalpyNorOut;
234 : Real64 modeRatio;
235 :
236 76864 : this->calculate(state, this->normalMode, inletNode, outletNode, PLR, speedNum, speedRatio, fanOp, condInletNode, condOutletNode, singleMode);
237 :
238 : // this->OperatingMode = 1;
239 76864 : CalcComponentSensibleLatentOutput(
240 76864 : outletNode.MassFlowRate, inletNode.Temp, inletNode.HumRat, outletNode.Temp, outletNode.HumRat, sensNorRate, latRate, totalCoolingRate);
241 76864 : if (totalCoolingRate > 1.0E-10) {
242 25616 : this->OperatingMode = 1;
243 25616 : this->NormalSHR = sensNorRate / totalCoolingRate;
244 25616 : this->powerUse = this->normalMode.OpModePower;
245 25616 : this->RTF = this->normalMode.OpModeRTF;
246 25616 : this->wasteHeatRate = this->normalMode.OpModeWasteHeat;
247 : }
248 :
249 76864 : if ((PLR != 0.0) && (LoadSHR != 0.0)) {
250 8184 : if (totalCoolingRate == 0.0) {
251 0 : SysNorSHR = 1.0;
252 : } else {
253 8184 : SysNorSHR = sensNorRate / totalCoolingRate;
254 : }
255 8184 : HumRatNorOut = outletNode.HumRat;
256 8184 : TempNorOut = outletNode.Temp;
257 8184 : EnthalpyNorOut = outletNode.Enthalpy;
258 8184 : this->recoveredEnergyRate = sensNorRate;
259 :
260 8184 : if (LoadSHR < SysNorSHR) {
261 5422 : outletNode.MassFlowRate = inletNode.MassFlowRate;
262 5422 : this->calculate(
263 5422 : state, this->alternateMode, inletNode, outletNode, PLR, speedNum, speedRatio, fanOp, condInletNode, condOutletNode, singleMode);
264 5422 : CalcComponentSensibleLatentOutput(outletNode.MassFlowRate,
265 5422 : inletNode.Temp,
266 5422 : inletNode.HumRat,
267 : outletNode.Temp,
268 : outletNode.HumRat,
269 : sensSubRate,
270 : latRate,
271 : totalCoolingRate);
272 5422 : SysSubSHR = sensSubRate / totalCoolingRate;
273 5422 : if (LoadSHR < SysSubSHR) {
274 5422 : outletNode.MassFlowRate = inletNode.MassFlowRate;
275 5422 : this->calculate(state,
276 5422 : this->alternateMode2,
277 : inletNode,
278 : outletNode,
279 : PLR,
280 : speedNum,
281 : speedRatio,
282 : fanOp,
283 : condInletNode,
284 : condOutletNode,
285 : singleMode);
286 5422 : CalcComponentSensibleLatentOutput(outletNode.MassFlowRate,
287 5422 : inletNode.Temp,
288 5422 : inletNode.HumRat,
289 : outletNode.Temp,
290 : outletNode.HumRat,
291 : sensRehRate,
292 : latRate,
293 : totalCoolingRate);
294 5422 : SysRehSHR = sensRehRate / totalCoolingRate;
295 5422 : if (LoadSHR > SysRehSHR) {
296 4686 : modeRatio = (LoadSHR - SysNorSHR) / (SysRehSHR - SysNorSHR);
297 4686 : this->OperatingMode = 3;
298 4686 : outletNode.HumRat = HumRatNorOut * (1.0 - modeRatio) + modeRatio * outletNode.HumRat;
299 4686 : outletNode.Enthalpy = EnthalpyNorOut * (1.0 - modeRatio) + modeRatio * outletNode.Enthalpy;
300 4686 : outletNode.Temp = Psychrometrics::PsyTdbFnHW(outletNode.Enthalpy, outletNode.HumRat);
301 4686 : this->ModeRatio = modeRatio;
302 : // update other reporting terms
303 4686 : this->powerUse = this->normalMode.OpModePower * (1.0 - modeRatio) + modeRatio * this->alternateMode2.OpModePower;
304 4686 : this->RTF = this->normalMode.OpModeRTF * (1.0 - modeRatio) + modeRatio * this->alternateMode2.OpModeRTF;
305 4686 : this->wasteHeatRate = this->normalMode.OpModeWasteHeat * (1.0 - modeRatio) + modeRatio * this->alternateMode2.OpModeWasteHeat;
306 4686 : this->recoveredEnergyRate = (this->recoveredEnergyRate - sensRehRate) * this->ModeRatio;
307 : } else {
308 736 : this->ModeRatio = 1.0;
309 736 : this->OperatingMode = 3;
310 736 : this->recoveredEnergyRate = (this->recoveredEnergyRate - sensRehRate) * this->ModeRatio;
311 : }
312 : } else {
313 0 : modeRatio = (LoadSHR - SysNorSHR) / (SysSubSHR - SysNorSHR);
314 0 : this->OperatingMode = 2;
315 : // process outlet conditions and total output
316 0 : outletNode.HumRat = HumRatNorOut * (1.0 - modeRatio) + modeRatio * outletNode.HumRat;
317 0 : outletNode.Enthalpy = EnthalpyNorOut * (1.0 - modeRatio) + modeRatio * outletNode.Enthalpy;
318 0 : outletNode.Temp = Psychrometrics::PsyTdbFnHW(outletNode.Enthalpy, outletNode.HumRat);
319 0 : this->ModeRatio = modeRatio;
320 : // update other reporting terms
321 0 : this->powerUse = this->normalMode.OpModePower * (1.0 - modeRatio) + modeRatio * this->alternateMode.OpModePower;
322 0 : this->RTF = this->normalMode.OpModeRTF * (1.0 - modeRatio) + modeRatio * this->alternateMode.OpModeRTF;
323 0 : this->wasteHeatRate = this->normalMode.OpModeWasteHeat * (1.0 - modeRatio) + modeRatio * this->alternateMode.OpModeWasteHeat;
324 0 : this->recoveredEnergyRate = (this->recoveredEnergyRate - sensSubRate) * this->ModeRatio;
325 : }
326 : } else {
327 2762 : this->ModeRatio = 0.0;
328 2762 : this->OperatingMode = 1;
329 2762 : this->recoveredEnergyRate = 0.0;
330 : }
331 : // Check for saturation error and modify temperature at constant enthalpy
332 8184 : Real64 tsat = Psychrometrics::PsyTsatFnHPb(state, outletNode.Enthalpy, inletNode.Press, RoutineName);
333 8184 : if (outletNode.Temp < tsat) {
334 0 : outletNode.Temp = tsat;
335 0 : outletNode.HumRat = Psychrometrics::PsyWFnTdbH(state, tsat, outletNode.Enthalpy);
336 : }
337 : }
338 11179630 : } else if (currentCoilMode == HVAC::CoilMode::Enhanced) {
339 0 : this->calculate(
340 0 : state, this->alternateMode, inletNode, outletNode, PLR, speedNum, speedRatio, fanOp, condInletNode, condOutletNode, singleMode);
341 0 : this->OperatingMode = 2;
342 0 : this->powerUse = this->alternateMode.OpModePower;
343 0 : this->RTF = this->alternateMode.OpModeRTF;
344 0 : this->wasteHeatRate = this->alternateMode.OpModeWasteHeat;
345 : } else {
346 11179630 : this->calculate(state, this->normalMode, inletNode, outletNode, PLR, speedNum, speedRatio, fanOp, condInletNode, condOutletNode, singleMode);
347 11179630 : this->OperatingMode = 1;
348 11179630 : this->powerUse = this->normalMode.OpModePower;
349 11179630 : this->RTF = this->normalMode.OpModeRTF;
350 11179630 : this->wasteHeatRate = this->normalMode.OpModeWasteHeat;
351 : }
352 :
353 : // calculate crankcase heater operation
354 11256494 : if (state.dataEnvrn->OutDryBulbTemp < this->maxOutdoorDrybulbForBasin) {
355 3722257 : this->crankcaseHeaterPower = this->crankcaseHeaterCap;
356 3722257 : if (this->crankcaseHeaterCapacityCurveIndex > 0) {
357 0 : this->crankcaseHeaterPower *= Curve::CurveValue(state, this->crankcaseHeaterCapacityCurveIndex, state.dataEnvrn->OutDryBulbTemp);
358 : }
359 : } else {
360 7534237 : this->crankcaseHeaterPower = 0.0;
361 : }
362 11256494 : this->crankcaseHeaterPower = this->crankcaseHeaterPower * (1.0 - this->RTF);
363 11256494 : this->crankcaseHeaterElectricityConsumption = this->crankcaseHeaterPower * reportingConstant;
364 :
365 : // basin heater
366 11256494 : if (this->evapCondBasinHeatSchedulIndex > 0) {
367 0 : Real64 currentBasinHeaterAvail = ScheduleManager::GetCurrentScheduleValue(state, this->evapCondBasinHeatSchedulIndex);
368 0 : 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 11256494 : if (this->evapCondBasinHeatCap > 0.0) {
374 0 : this->basinHeaterPower = max(0.0, this->evapCondBasinHeatCap * (this->evapCondBasinHeatSetpoint - state.dataEnvrn->OutDryBulbTemp));
375 : }
376 : }
377 11256494 : this->basinHeaterPower *= (1.0 - this->RTF);
378 11256494 : this->electricityConsumption = this->powerUse * reportingConstant;
379 :
380 11256494 : 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 11256494 : }
389 :
390 54 : void CoilCoolingDXCurveFitPerformance::size(EnergyPlus::EnergyPlusData &state)
391 : {
392 54 : if (!state.dataGlobal->SysSizingCalc && this->mySizeFlag) {
393 54 : this->normalMode.parentName = this->parentName;
394 54 : this->normalMode.size(state);
395 54 : if (this->maxAvailCoilMode == HVAC::CoilMode::Enhanced) {
396 5 : this->alternateMode.size(state);
397 : }
398 54 : if (this->maxAvailCoilMode == HVAC::CoilMode::SubcoolReheat) {
399 1 : this->alternateMode.size(state);
400 1 : this->alternateMode2.size(state);
401 : }
402 54 : this->mySizeFlag = false;
403 : }
404 54 : }
405 :
406 11267338 : void CoilCoolingDXCurveFitPerformance::calculate(EnergyPlus::EnergyPlusData &state,
407 : CoilCoolingDXCurveFitOperatingMode ¤tMode,
408 : const DataLoopNode::NodeData &inletNode,
409 : DataLoopNode::NodeData &outletNode,
410 : Real64 &PLR,
411 : int &speedNum,
412 : Real64 &speedRatio,
413 : HVAC::FanOp const fanOp,
414 : DataLoopNode::NodeData &condInletNode,
415 : DataLoopNode::NodeData &condOutletNode,
416 : bool const singleMode)
417 : {
418 :
419 : // calculate the performance at this mode/speed
420 11267338 : currentMode.CalcOperatingMode(state, inletNode, outletNode, PLR, speedNum, speedRatio, fanOp, condInletNode, condOutletNode, singleMode);
421 11267338 : }
422 :
423 54 : void CoilCoolingDXCurveFitPerformance::calcStandardRatings210240(EnergyPlus::EnergyPlusData &state)
424 : {
425 :
426 : // for now this will provide standard ratings for the coil at the normal mode at speed N
427 : // future iterations will extend the inputs to give the user the flexibility to select different standards to
428 : // apply and such
429 :
430 54 : int constexpr NumOfReducedCap(4); // Number of reduced capacity test conditions (100%,75%,50%,and 25%)
431 :
432 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
433 54 : Real64 TotCapFlowModFac(0.0); // Total capacity modifier f(actual flow vs rated flow) for each speed [-]
434 54 : Real64 EIRFlowModFac(0.0); // EIR modifier f(actual supply air flow vs rated flow) for each speed [-]
435 54 : Real64 TotCapTempModFac(0.0); // Total capacity modifier (function of entering wetbulb, outside drybulb) [-]
436 54 : Real64 EIRTempModFac(0.0); // EIR modifier (function of entering wetbulb, outside drybulb) [-]
437 54 : Real64 TotCoolingCapAHRI(0.0); // Total Cooling Coil capacity (gross) at AHRI test conditions [W]
438 54 : Real64 NetCoolingCapAHRI(0.0); // Net Cooling Coil capacity at AHRI TestB conditions, accounting for fan heat [W]
439 54 : Real64 NetCoolingCapAHRI2023(0.0); // Net Cooling Coil capacity at AHRI TestB conditions, accounting for fan heat [W]
440 54 : Real64 TotalElecPower(0.0); // Net power consumption (Cond Fan+Compressor+Indoor Fan) at AHRI test conditions [W]
441 54 : Real64 TotalElecPower2023(0.0); // Net power consumption (Cond Fan+Compressor+Indoor Fan) at AHRI test conditions [W]
442 54 : Real64 TotalElecPowerRated(0.0); // Net power consumption (Cond Fan+Compressor+Indoor Fan) at Rated test conditions [W]
443 54 : Real64 TotalElecPowerRated2023(0.0); // Net power consumption (Cond Fan+Compressor+Indoor Fan) at Rated test conditions [W]
444 54 : Real64 EIR(0.0); // Energy Efficiency Ratio at AHRI test conditions for SEER [-]
445 54 : Real64 PartLoadFactor(0.0); // Part load factor, accounts for thermal lag at compressor startup [-]
446 54 : Real64 EERReduced(0.0); // EER at reduced capacity test conditions (100%, 75%, 50%, and 25%)
447 54 : Real64 ElecPowerReducedCap(0.0); // Net power consumption (Cond Fan+Compressor) at reduced test condition [W]
448 54 : Real64 NetCoolingCapReduced(0.0); // Net Cooling Coil capacity at reduced conditions, accounting for supply fan heat [W]
449 54 : Real64 LoadFactor(0.0); // Fractional "on" time for last stage at the desired reduced capacity, (dimensionless)
450 54 : Real64 DegradationCoeff(0.0); // Degradation coeficient, (dimenssionless)
451 : Real64 OutdoorUnitInletAirDryBulbTempReduced; // Outdoor unit entering air dry-bulb temperature at reduced capacity [C]
452 :
453 : // *** SOME CONSTANTS FROM THE STANDARD
454 : // The AHRI standard specifies a nominal/default fan electric power consumption per rated air
455 : // volume flow rate to account for indoor fan electric power consumption
456 : // when the standard tests are conducted on units that do not have an
457 : // indoor air circulating fan. Used if user doesn't enter a specific value.
458 54 : Real64 constexpr DefaultFanPowerPerEvapAirFlowRate(773.3); // 365 W/1000 scfm or 773.3 W/(m3/s).
459 54 : Real64 constexpr DefaultFanPowerPerEvapAirFlowRate2023(934.4); // 441 W/1000 scfm or 934.4 W/(m3/s).
460 : // AHRI Standard 210/240-2008 Performance Test Conditions for Unitary Air-to-Air Air-Conditioning and Heat Pump Equipment
461 54 : Real64 constexpr CoolingCoilInletAirWetBulbTempRated(19.44); // 19.44C (67F) Tests A and B
462 54 : Real64 constexpr OutdoorUnitInletAirDryBulbTemp(27.78); // 27.78C (82F) Test B (for SEER)
463 54 : Real64 constexpr OutdoorUnitInletAirDryBulbTempRated(35.0); // 35.00C (95F) Test A (rated capacity)
464 54 : Real64 constexpr AirMassFlowRatioRated(1.0); // AHRI test is at the design flow rate so AirMassFlowRatio is 1.0
465 54 : Real64 constexpr PLRforSEER(0.5); // Part-load ratio for SEER calculation (single speed DX cooling coils)
466 : static constexpr std::array<Real64, 4> ReducedPLR = {1.0, 0.75, 0.50, 0.25}; // Reduced Capacity part-load conditions
467 : static constexpr std::array<Real64, 4> IEERWeightingFactor = {0.020, 0.617, 0.238, 0.125}; // EER Weighting factors (IEER)
468 54 : Real64 constexpr OADBTempLowReducedCapacityTest(18.3); // Outdoor air dry-bulb temp in degrees C (65F)
469 :
470 : // For Single Stage Systems, if the optional CFull and DFull tests are not performed, a
471 : // default value of 0.20 shall be used for the cooling Degradation Coefficient
472 54 : Real64 constexpr CyclicDegradationCoefficient(0.20); // ANSI/AHRI 210/240 2023 Section 6.1.3.1
473 :
474 : // some conveniences
475 54 : auto &mode = this->normalMode;
476 54 : auto &speed = mode.speeds.back();
477 :
478 54 : Real64 FanPowerPerEvapAirFlowRate = DefaultFanPowerPerEvapAirFlowRate;
479 54 : if (speed.rated_evap_fan_power_per_volume_flow_rate > 0.0) {
480 54 : FanPowerPerEvapAirFlowRate = speed.rated_evap_fan_power_per_volume_flow_rate;
481 : }
482 :
483 54 : Real64 FanPowerPerEvapAirFlowRate2023 = DefaultFanPowerPerEvapAirFlowRate2023;
484 54 : if (speed.rated_evap_fan_power_per_volume_flow_rate_2023 > 0.0) {
485 54 : FanPowerPerEvapAirFlowRate2023 = speed.rated_evap_fan_power_per_volume_flow_rate_2023;
486 : }
487 :
488 54 : if (mode.ratedGrossTotalCap > 0.0) {
489 54 : TotCapFlowModFac = Curve::CurveValue(state, speed.indexCapFFF, AirMassFlowRatioRated);
490 :
491 54 : TotCapTempModFac = Curve::CurveValue(state, speed.indexCapFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTemp);
492 54 : TotCoolingCapAHRI = mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac;
493 : // Calculate net cooling capacity | 2017
494 54 : this->standardRatingCoolingCapacity = TotCoolingCapAHRI - FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
495 : // Calculate net cooling capacity | 2023
496 54 : this->standardRatingCoolingCapacity2023 = TotCoolingCapAHRI - FanPowerPerEvapAirFlowRate2023 * mode.ratedEvapAirFlowRate;
497 : // TODO: Commercial and industrial unitary air-conditioning condensing units with a capacity greater than 135,000 Btu/h (39564.59445 Watts)
498 : // as defined in ANSI/AHRI Standard 365(I-P). | Scope 2.2.6 (ANSI/AHRI 340-360 2022)
499 :
500 : // SEER2 standard applies to factory-made Unitary Air-conditioners and Unitary Air-source Heat Pumps with
501 : // capacities less than 65,000 Btu/h (19049.61955 Watts) | Section 2.1 (ANSI/AHRI 210-240 2023)
502 : // Removal of water-cooled and evaporatively-cooled products from the scope | Foreword (ANSI/AHRI 210-240 2023)
503 :
504 : // SEER calculations:
505 54 : TotCapTempModFac = Curve::CurveValue(state, speed.indexCapFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTemp);
506 54 : TotCoolingCapAHRI = mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac;
507 54 : EIRTempModFac = Curve::CurveValue(state, speed.indexEIRFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTemp);
508 54 : EIRFlowModFac = Curve::CurveValue(state, speed.indexEIRFFF, AirMassFlowRatioRated);
509 54 : if (speed.ratedCOP > 0.0) { // RatedCOP <= 0.0 is trapped in GetInput, but keep this as "safety"
510 54 : EIR = EIRTempModFac * EIRFlowModFac / speed.ratedCOP;
511 : } else {
512 0 : EIR = 0.0;
513 : }
514 :
515 : // Calculate net cooling capacity
516 54 : NetCoolingCapAHRI = TotCoolingCapAHRI - FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
517 54 : TotalElecPower = EIR * TotCoolingCapAHRI + FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
518 :
519 54 : NetCoolingCapAHRI2023 = TotCoolingCapAHRI - FanPowerPerEvapAirFlowRate2023 * mode.ratedEvapAirFlowRate;
520 54 : TotalElecPower2023 = EIR * TotCoolingCapAHRI + FanPowerPerEvapAirFlowRate2023 * mode.ratedEvapAirFlowRate;
521 : // Calculate SEER value from the Energy Efficiency Ratio (EER) at the AHRI test conditions and the part load factor.
522 : // First evaluate the Part Load Factor curve at PLR = 0.5 (AHRI Standard 210/240)
523 54 : PartLoadFactor = Curve::CurveValue(state, speed.indexPLRFPLF, PLRforSEER);
524 54 : Real64 PartLoadFactorStandard = 1.0 - (1 - PLRforSEER) * CyclicDegradationCoefficient;
525 54 : if (TotalElecPower > 0.0) {
526 54 : this->standardRatingSEER = (NetCoolingCapAHRI / TotalElecPower) * PartLoadFactor;
527 54 : this->standardRatingSEER_Standard = (NetCoolingCapAHRI / TotalElecPower) * PartLoadFactorStandard;
528 : } else {
529 0 : this->standardRatingSEER = 0.0;
530 0 : this->standardRatingSEER2_Standard = 0.0;
531 : }
532 :
533 54 : if (TotalElecPower2023 > 0.0) {
534 54 : this->standardRatingSEER2_User = (NetCoolingCapAHRI2023 / TotalElecPower2023) * PartLoadFactor;
535 54 : this->standardRatingSEER2_Standard = (NetCoolingCapAHRI2023 / TotalElecPower2023) * PartLoadFactorStandard;
536 : } else {
537 0 : this->standardRatingSEER2_User = 0.0;
538 0 : this->standardRatingSEER2_Standard = 0.0;
539 : }
540 :
541 : // EER calculations:
542 : // Calculate the net cooling capacity at the rated conditions (19.44C WB and 35.0C DB )
543 54 : TotCapTempModFac = Curve::CurveValue(state, speed.indexCapFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTempRated);
544 54 : this->standardRatingCoolingCapacity =
545 54 : mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac - FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
546 54 : this->standardRatingCoolingCapacity2023 =
547 54 : mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac - FanPowerPerEvapAirFlowRate2023 * mode.ratedEvapAirFlowRate;
548 : // Calculate Energy Efficiency Ratio (EER) at (19.44C WB and 35.0C DB ), ANSI/AHRI Std. 340/360
549 54 : EIRTempModFac = Curve::CurveValue(state, speed.indexEIRFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTempRated);
550 54 : if (speed.ratedCOP > 0.0) {
551 : // RatedCOP <= 0.0 is trapped in GetInput, but keep this as "safety"
552 54 : EIR = EIRTempModFac * EIRFlowModFac / speed.ratedCOP;
553 : } else {
554 0 : EIR = 0.0;
555 : }
556 54 : TotalElecPowerRated =
557 54 : EIR * (mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac) + FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
558 54 : if (TotalElecPowerRated > 0.0) {
559 54 : this->standardRatingEER = this->standardRatingCoolingCapacity / TotalElecPowerRated;
560 : } else {
561 0 : this->standardRatingEER = 0.0;
562 : }
563 54 : TotalElecPowerRated2023 =
564 54 : EIR * (mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac) + FanPowerPerEvapAirFlowRate2023 * mode.ratedEvapAirFlowRate;
565 54 : if (TotalElecPowerRated2023 > 0.0) {
566 54 : this->standardRatingEER2 = this->standardRatingCoolingCapacity2023 / TotalElecPowerRated2023;
567 : } else {
568 0 : this->standardRatingEER2 = 0.0;
569 : }
570 :
571 54 : if (mode.condenserType == CoilCoolingDXCurveFitOperatingMode::CondenserType::AIRCOOLED) {
572 108 : std::tie(this->standardRatingCoolingCapacity2023,
573 54 : this->standardRatingSEER2_User,
574 54 : this->standardRatingSEER2_Standard,
575 54 : this->standardRatingEER2) = StandardRatings::SEER2CalulcationCurveFit(state, "Coil:Cooling:DX:CurveFit", this->normalMode);
576 : }
577 :
578 : // 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.
579 54 : this->standardRatingIEER = 0.0;
580 : // Calculate the net cooling capacity at the rated conditions (19.44C WB and 35.0C DB )
581 54 : TotCapTempModFac = Curve::CurveValue(state, speed.indexCapFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTempRated);
582 54 : this->standardRatingCoolingCapacity =
583 54 : mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac - FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
584 270 : for (int RedCapNum = 0; RedCapNum < NumOfReducedCap; ++RedCapNum) {
585 : // get the outdoor air dry bulb temperature for the reduced capacity test conditions
586 216 : if (ReducedPLR[RedCapNum] > 0.444) {
587 162 : OutdoorUnitInletAirDryBulbTempReduced = 5.0 + 30.0 * ReducedPLR[RedCapNum];
588 : } else {
589 54 : OutdoorUnitInletAirDryBulbTempReduced = OADBTempLowReducedCapacityTest;
590 : }
591 216 : TotCapTempModFac = Curve::CurveValue(state, speed.indexCapFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTempReduced);
592 216 : NetCoolingCapReduced =
593 216 : mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac - FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate;
594 216 : EIRTempModFac = Curve::CurveValue(state, speed.indexEIRFT, CoolingCoilInletAirWetBulbTempRated, OutdoorUnitInletAirDryBulbTempReduced);
595 216 : EIRFlowModFac = Curve::CurveValue(state, speed.indexEIRFFF, AirMassFlowRatioRated);
596 216 : if (speed.ratedCOP > 0.0) {
597 216 : EIR = EIRTempModFac * EIRFlowModFac / speed.ratedCOP;
598 : } else {
599 0 : EIR = 0.0;
600 : }
601 216 : if (NetCoolingCapReduced > 0.0) {
602 216 : LoadFactor = ReducedPLR[RedCapNum] * this->standardRatingCoolingCapacity / NetCoolingCapReduced;
603 : } else {
604 0 : LoadFactor = 1.0;
605 : }
606 216 : DegradationCoeff = 1.130 - 0.130 * LoadFactor;
607 216 : ElecPowerReducedCap = DegradationCoeff * EIR * (mode.ratedGrossTotalCap * TotCapTempModFac * TotCapFlowModFac);
608 216 : EERReduced =
609 216 : (LoadFactor * NetCoolingCapReduced) / (LoadFactor * ElecPowerReducedCap + FanPowerPerEvapAirFlowRate * mode.ratedEvapAirFlowRate);
610 216 : this->standardRatingIEER += IEERWeightingFactor[RedCapNum] * EERReduced;
611 : }
612 :
613 : // IEER 2022 -->
614 : // TODO: we can always decide and give precedence to Alternate Mode 1 or Alternate Mode 2 if present | Needs Discussion about the
615 : // applicability.
616 54 : std::tie(this->standardRatingIEER2, this->standardRatingCoolingCapacity2023, this->standardRatingEER2) =
617 108 : StandardRatings::IEERCalulcationCurveFit(state, "Coil:Cooling:DX:CurveFit", this->normalMode);
618 :
619 : } else {
620 0 : ShowSevereError(state,
621 0 : "Standard Ratings: Coil:Cooling:DX " + this->name +
622 : " has zero rated total cooling capacity. Standard ratings cannot be calculated.");
623 : }
624 54 : }
625 :
626 3 : void CoilCoolingDXCurveFitPerformance::setOperMode(EnergyPlus::EnergyPlusData &state, CoilCoolingDXCurveFitOperatingMode ¤tMode, int const mode)
627 : {
628 : // set parent mode for each speed
629 : int numSpeeds;
630 3 : bool errorsFound = false;
631 :
632 3 : numSpeeds = (int)currentMode.speeds.size();
633 6 : for (int speedNum = 0; speedNum < numSpeeds; speedNum++) {
634 3 : currentMode.speeds[speedNum].parentOperatingMode = mode;
635 3 : if (mode == 2) {
636 1 : if (currentMode.speeds[speedNum].indexSHRFT == 0) {
637 0 : ShowSevereError(state, currentMode.speeds[speedNum].object_name + "=\"" + currentMode.speeds[speedNum].name + "\", Curve check:");
638 0 : ShowContinueError(state,
639 : "The input of Sensible Heat Ratio Modifier Function of Temperature Curve Name is required, but not available for "
640 : "SubcoolReheat mode. Please input");
641 0 : errorsFound = true;
642 : }
643 1 : if (currentMode.speeds[speedNum].indexSHRFFF == 0) {
644 0 : ShowSevereError(state, currentMode.speeds[speedNum].object_name + "=\"" + currentMode.speeds[speedNum].name + "\", Curve check:");
645 0 : ShowContinueError(state,
646 : "The input of Sensible Heat Ratio Modifier Function of Flow Fraction Curve Name is required, but not available for "
647 : "SubcoolReheat mode. Please input");
648 0 : errorsFound = true;
649 : }
650 : }
651 3 : if (mode == 3) {
652 1 : if (currentMode.speeds[speedNum].indexSHRFT == 0) {
653 0 : ShowSevereError(state, currentMode.speeds[speedNum].object_name + "=\"" + currentMode.speeds[speedNum].name + "\", Curve check:");
654 0 : ShowContinueError(state,
655 : "The input of Sensible Heat Ratio Modifier Function of Temperature Curve Name is required, but not available for "
656 : "SubcoolReheat mode. Please input");
657 0 : errorsFound = true;
658 : }
659 1 : if (currentMode.speeds[speedNum].indexSHRFFF == 0) {
660 0 : ShowSevereError(state, currentMode.speeds[speedNum].object_name + "=\"" + currentMode.speeds[speedNum].name + "\", Curve check:");
661 0 : ShowContinueError(state,
662 : "The input of Sensible Heat Ratio Modifier Function of Flow Fraction Curve Name is required, but not available for "
663 : "SubcoolReheat mode. Please input");
664 0 : errorsFound = true;
665 : }
666 : }
667 : }
668 3 : if (errorsFound) {
669 0 : ShowFatalError(state,
670 0 : "CoilCoolingDXCurveFitPerformance: Errors found in getting " + this->object_name +
671 : " input. Preceding condition(s) causes termination.");
672 : }
673 3 : }
|