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 "rs0004_factory.h"
49 : #include <EnergyPlus/Coils/CoilCoolingDXAshrae205Performance.hh>
50 : #include <EnergyPlus/CurveManager.hh>
51 : #include <EnergyPlus/Data/EnergyPlusData.hh>
52 : #include <EnergyPlus/DataEnvironment.hh>
53 : #include <EnergyPlus/DataGlobalConstants.hh>
54 : #include <EnergyPlus/DataHVACGlobals.hh>
55 : #include <EnergyPlus/DataIPShortCuts.hh>
56 : #include <EnergyPlus/DataSystemVariables.hh>
57 : #include <EnergyPlus/EnergyPlusLogger.hh>
58 : #include <EnergyPlus/Fans.hh>
59 : #include <EnergyPlus/General.hh>
60 : #include <EnergyPlus/GeneralRoutines.hh>
61 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
62 : #include <EnergyPlus/OutputReportPredefined.hh>
63 : #include <EnergyPlus/Psychrometrics.hh>
64 : #include <EnergyPlus/ScheduleManager.hh>
65 : #include <EnergyPlus/UtilityRoutines.hh>
66 :
67 : using namespace EnergyPlus;
68 :
69 : static std::map<std::string, Btwxt::InterpolationMethod> InterpMethods = // NOLINT(cert-err58-cpp)
70 : {{"LINEAR", Btwxt::InterpolationMethod::linear}, {"CUBIC", Btwxt::InterpolationMethod::cubic}};
71 :
72 1 : CoilCoolingDX205Performance::CoilCoolingDX205Performance(EnergyPlus::EnergyPlusData &state, const std::string &name_to_find)
73 : {
74 : static constexpr std::string_view routineName("CoilCoolingDX205Performance::CoilCoolingDX205Performance");
75 : using namespace tk205;
76 3 : RSInstanceFactory::register_factory("RS0004", std::make_shared<RS0004Factory>());
77 :
78 1 : bool errorsFound(false);
79 1 : state.dataIPShortCut->cCurrentModuleObject = CoilCoolingDX205Performance::object_name;
80 1 : auto &ip = state.dataInputProcessing->inputProcessor;
81 1 : int numPerformances = ip->getNumObjectsFound(state, CoilCoolingDX205Performance::object_name);
82 1 : if (numPerformances <= 0) {
83 0 : ShowSevereError(state, format("No {} equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
84 0 : errorsFound = true;
85 : }
86 1 : auto const &Coil205PerformanceInstances = ip->epJSON.find(state.dataIPShortCut->cCurrentModuleObject).value();
87 1 : auto const &objectSchemaProps = ip->getObjectSchemaProps(state, state.dataIPShortCut->cCurrentModuleObject);
88 :
89 2 : for (auto &instance : Coil205PerformanceInstances.items()) {
90 1 : auto const &fields = instance.value();
91 1 : name = instance.key();
92 :
93 1 : if (!Util::SameString(name_to_find, name)) {
94 0 : ShowFatalError(state, format("Could not find Coil:Cooling:DX:Performance object with name: {}", name_to_find));
95 : }
96 :
97 3 : std::string const rep_file_name = ip->getAlphaFieldValue(fields, objectSchemaProps, "representation_file_name");
98 1 : fs::path rep_file_path = DataSystemVariables::CheckForActualFilePath(state, fs::path(rep_file_name), std::string(routineName));
99 1 : if (rep_file_path.empty()) {
100 0 : errorsFound = true;
101 : // Given that several of the following expressions require the representation file to be present, we'll just throw a fatal here.
102 : // The errorsFound flag is still set to true here so that in the future, if we defer the fatal until later in this routine, it will still
103 : // be set The CheckForActualFilePath function emits some nice information to the ERR file, so we just need a simple fatal here
104 0 : ShowFatalError(state, "Program terminates due to the missing ASHRAE 205 RS0004 representation file.");
105 : }
106 1 : std::shared_ptr<EnergyPlusLogger> coil_logger = std::make_shared<EnergyPlusLogger>();
107 1 : logger_context = {&state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, name)};
108 1 : coil_logger->set_message_context(&logger_context);
109 : representation =
110 3 : std::dynamic_pointer_cast<rs0004_ns::RS0004>(RSInstanceFactory::create("RS0004", rep_file_path.string().c_str(), coil_logger));
111 1 : if (nullptr == representation) {
112 0 : ShowSevereError(state, format("{} is not an instance of an ASHRAE205 Coil.", rep_file_path.string()));
113 0 : errorsFound = true;
114 : } else {
115 1 : representation->performance.performance_map_cooling.get_logger()->set_message_context(&logger_context);
116 1 : representation->performance.performance_map_standby.get_logger()->set_message_context(&logger_context);
117 : }
118 2 : interpolation_type = InterpMethods[Util::makeUPPER(ip->getAlphaFieldValue(fields, objectSchemaProps, "performance_interpolation_method"))];
119 1 : compressorFuelType = Constant::eFuel::Electricity;
120 : #if 0
121 : rated_total_cooling_capacity = fields.at("rated_total_cooling_capacity").get<Real64>();
122 : rated_steady_state_heating_capacity = fields.at("rated_steady_state_heating_capacity").get<Real64>();
123 : #endif
124 :
125 1 : rating_humidity_ratio = Psychrometrics::PsyWFnTdbTwbPb(state,
126 : indoor_coil_entering_dry_bulb_temperature_K - Constant::Kelvin,
127 : reference_wb_temperature - Constant::Kelvin,
128 : reference_pressure_sea_level);
129 1 : rating_indoor_coil_entering_relative_humidity = Psychrometrics::PsyRhFnTdbWPb(
130 : state, indoor_coil_entering_dry_bulb_temperature_K - Constant::Kelvin, rating_humidity_ratio, reference_pressure_sea_level);
131 1 : rating_rho_air = state.dataEnvrn->StdRhoAir;
132 :
133 1 : speeds.resize(representation->performance.performance_map_cooling.grid_variables.compressor_sequence_number.size());
134 1 : nominal_speed_index = speeds.size() - 1;
135 1 : rated_total_cooling_capacity = ratedTotalCapacityAtSpeedIndex(state, nominal_speed_index);
136 :
137 1 : if (errorsFound) {
138 0 : ShowFatalError(
139 : state,
140 0 : format("{} Errors found in getting {} input. Preceding condition(s) causes termination.", std::string{routineName}, object_name));
141 : }
142 2 : }
143 1 : }
144 :
145 2 : tk205::rs0004_ns::LookupVariablesCoolingStruct CoilCoolingDX205Performance::calculate_rated_capacities(EnergyPlus::EnergyPlusData &state,
146 : int speed_index) const
147 : {
148 2 : auto indoor_coil_entering_relative_humidity = Psychrometrics::PsyRhFnTdbWPb(
149 2 : state, indoor_coil_entering_dry_bulb_temperature_K - Constant::Kelvin, rating_humidity_ratio, reference_pressure_sea_level);
150 :
151 : // TODO: Should the capacity at every speed use the max flow rate?
152 2 : auto max_available_flow = representation->performance.performance_map_cooling.grid_variables.indoor_coil_air_mass_flow_rate.back();
153 4 : const auto lookup_variables = representation->performance.performance_map_cooling.calculate_performance(
154 : outdoor_coil_entering_dry_bulb_temperature_K,
155 : indoor_coil_entering_relative_humidity,
156 : indoor_coil_entering_dry_bulb_temperature_K,
157 : max_available_flow,
158 2 : representation->performance.performance_map_cooling.grid_variables.compressor_sequence_number[speed_index],
159 : reference_pressure_sea_level,
160 2 : interpolation_type);
161 2 : return lookup_variables;
162 : }
163 :
164 2 : void CoilCoolingDX205Performance::calculate_air_mass_flow(EnergyPlus::EnergyPlusData &state, int speed_index)
165 : {
166 2 : constexpr Real64 accuracy{0.0001};
167 2 : constexpr int maxIter{500};
168 2 : int solFla{0};
169 2 : const auto min_available_flow{representation->performance.performance_map_cooling.grid_variables.indoor_coil_air_mass_flow_rate.front()};
170 2 : const auto max_available_flow{representation->performance.performance_map_cooling.grid_variables.indoor_coil_air_mass_flow_rate.back()};
171 2 : auto iterated_mass_flow_rate = 1.0;
172 :
173 15 : auto f = [speed_index, this](Real64 available_mass_flow) {
174 : // Which mass flow gives us a capacity closest to the rating capacity?
175 : auto gross_capacity =
176 15 : representation->performance.performance_map_cooling
177 15 : .calculate_performance(outdoor_coil_entering_dry_bulb_temperature_K,
178 : rating_indoor_coil_entering_relative_humidity,
179 : indoor_coil_entering_dry_bulb_temperature_K,
180 : available_mass_flow,
181 15 : representation->performance.performance_map_cooling.grid_variables.compressor_sequence_number[speed_index],
182 : reference_pressure_sea_level,
183 : interpolation_type)
184 15 : .gross_total_capacity;
185 15 : const auto available_volumetric_flow_cfm = 2118.88 * available_mass_flow / rating_rho_air; // Conversion constant m3/s -> cfm
186 15 : const auto capacity_tons = gross_capacity * 0.00028; // Conversion constant for W -> tons
187 :
188 15 : return rating_flow - available_volumetric_flow_cfm / capacity_tons;
189 2 : };
190 2 : General::SolveRoot(state, accuracy, maxIter, solFla, iterated_mass_flow_rate, f, min_available_flow, max_available_flow);
191 :
192 2 : speeds[speed_index].evaporator_air_mass_flow = iterated_mass_flow_rate;
193 2 : speeds[speed_index].evaporator_air_volumetric_flow = iterated_mass_flow_rate / rating_rho_air;
194 2 : }
195 :
196 1 : void CoilCoolingDX205Performance::size(EnergyPlusData &state)
197 : {
198 3 : for (int index = 0; index < speeds.size(); index++) {
199 2 : calculate_air_mass_flow(state, index);
200 : }
201 1 : }
202 :
203 35114 : void CoilCoolingDX205Performance::simulate(EnergyPlus::EnergyPlusData &state,
204 : const DataLoopNode::NodeData &inletNode,
205 : DataLoopNode::NodeData &outletNode,
206 : HVAC::CoilMode,
207 : int const speedNum,
208 : Real64 const speedRatio,
209 : HVAC::FanOp const fanOpMode,
210 : DataLoopNode::NodeData &condInletNode,
211 : DataLoopNode::NodeData &condOutletNode,
212 : bool const, // singleMode,
213 : Real64) // LoadSHR)
214 : {
215 : static constexpr std::string_view RoutineName = "CoilCoolingDX205Performance::simulate";
216 35114 : Real64 reportingConstant = state.dataHVACGlobal->TimeStepSys * Constant::iSecsInHour;
217 35114 : recoveredEnergyRate = 0.0;
218 35114 : NormalSHR = 0.0;
219 :
220 35114 : calculate(state, inletNode, outletNode, speedNum, speedRatio, fanOpMode, condInletNode, condOutletNode);
221 35114 : OperatingMode = 1;
222 :
223 35114 : basinHeaterPower *= (1.0 - RTF);
224 35114 : electricityConsumption = powerUse * reportingConstant;
225 :
226 35114 : if (compressorFuelType != Constant::eFuel::Electricity) {
227 0 : compressorFuelRate = powerUse;
228 0 : compressorFuelConsumption = electricityConsumption;
229 :
230 : // check this after adding parasitic loads
231 0 : powerUse = 0.0;
232 0 : electricityConsumption = 0.0;
233 : }
234 35114 : }
235 :
236 35114 : void CoilCoolingDX205Performance::calculate(EnergyPlus::EnergyPlusData &state,
237 : const DataLoopNode::NodeData &inletNode,
238 : DataLoopNode::NodeData &outletNode,
239 : int const speedNum,
240 : Real64 const ratio,
241 : HVAC::FanOp const fanOpMode,
242 : DataLoopNode::NodeData &condInletNode,
243 : DataLoopNode::NodeData &) // condOutletNode)
244 : {
245 : // If cycling (discrete or continuous): compressor_sequence_number = 1
246 : // if not cycling (discrete): compressor_sequence_number = speed -1 & speed, MFR is different for each call to
247 : // performance. Results are interpolated between the 2 performance calls;
248 : // if not cycling (continuous): compressor_sequence_number = speed - 1 + ratio, MFR is scaled using the ratio
249 : static constexpr std::string_view RoutineName = "CoilCoolingDX205Performance::calculate";
250 :
251 35114 : const auto this_speed = max(speedNum, 1); // 1 for single-speed, speedNum for multispeed. Disallow speed = 0
252 :
253 35114 : wasteHeatRate = 0; // currently unused; set here for all cases
254 :
255 35114 : auto air_mass_flow_rate = inletNode.MassFlowRate;
256 :
257 35114 : if (fanOpMode == HVAC::FanOp::Cycling && this_speed == 1) {
258 : // Entire system, fan and coil, are on or off for portions of a timestep
259 29797 : if (ratio > 0.0) {
260 : // Inlet node mass flow rate is the time-averaged mass flow rate during cycling,
261 : // so we divide by PLR to calculate the instantaneous (on-cycle) flow rate.
262 : // Performance calculation depends on the on-cycle rate.
263 13903 : air_mass_flow_rate = inletNode.MassFlowRate / ratio;
264 : } else {
265 15894 : air_mass_flow_rate = 0.0;
266 : }
267 : }
268 :
269 : // Standby performance (Off)
270 35114 : if ((this_speed == 1 && ratio == 0.0) || inletNode.MassFlowRate == 0.0) {
271 15894 : const auto outdoor_coil_dry_bulb_temperature_K = condInletNode.Temp + Constant::Kelvin;
272 15894 : powerUse = representation->performance.performance_map_standby.calculate_performance(outdoor_coil_dry_bulb_temperature_K).gross_power;
273 15894 : RTF = 0;
274 15894 : set_output_node_conditions(state, inletNode, outletNode, 0.0, 0.0, air_mass_flow_rate);
275 15894 : return;
276 : }
277 :
278 19220 : bool is_continuous = representation->performance.compressor_speed_control_type == tk205::ashrae205_ns::SpeedControlType::CONTINUOUS;
279 19220 : auto outdoor_coil_entering_dry_bulb_temperature_K = condInletNode.Temp + Constant::Kelvin;
280 19220 : auto indoor_coil_entering_dry_bulb_temperature_K = inletNode.Temp + Constant::Kelvin;
281 19220 : auto ambient_pressure = state.dataEnvrn->OutBaroPress;
282 19220 : auto indoor_coil_entering_relative_humidity = Psychrometrics::PsyRhFnTdbWPb(state, inletNode.Temp, inletNode.HumRat, ambient_pressure);
283 :
284 19220 : if (this_speed == 1) {
285 :
286 : // In cycling operation (continuous or discrete) this_speed = 1; compressor_sequence_number = 1;
287 : const auto &[gross_total_capacity, gross_sensible_capacity, gross_power] =
288 13903 : representation->performance.performance_map_cooling.calculate_performance(outdoor_coil_entering_dry_bulb_temperature_K,
289 : indoor_coil_entering_relative_humidity,
290 : indoor_coil_entering_dry_bulb_temperature_K,
291 : air_mass_flow_rate,
292 : this_speed,
293 : ambient_pressure,
294 13903 : interpolation_type);
295 :
296 13903 : set_output_node_conditions(state, inletNode, outletNode, gross_total_capacity, gross_sensible_capacity, air_mass_flow_rate);
297 :
298 : // Calculate simple capacity (powerUse, RTF) at operating conditions
299 13903 : calculate_cycling_capcacity(state, inletNode, outletNode, gross_power, ratio, fanOpMode);
300 : } else {
301 5317 : RTF = 1.0; // if we are on greater than 1 speed, RTF *must* be 1
302 5317 : if (is_continuous) {
303 : // compressor_sequence_number = speed - 1 + ratio
304 : // For example, a speed number of 2 with a ratio between (0,1) indicates that the compressor is modulating between speeds 1 and 2 with the
305 : // given ratio. The ASHRAE205 model simply interpolates using a decimal fraction speed.
306 : const auto &[gross_total_capacity, gross_sensible_capacity, gross_power] =
307 0 : representation->performance.performance_map_cooling.calculate_performance(outdoor_coil_entering_dry_bulb_temperature_K,
308 : indoor_coil_entering_relative_humidity,
309 : indoor_coil_entering_dry_bulb_temperature_K,
310 : air_mass_flow_rate,
311 0 : this_speed - 1 + ratio,
312 : ambient_pressure,
313 0 : interpolation_type);
314 :
315 : } else {
316 : // In modulation, discrete mode, compressor_sequence_number = this_speed for the first part of the calculation;
317 : // this_speed - 1 for the residual part.
318 : // Calculate these two modes in common:
319 :
320 5317 : auto mass_flow_rate_upperspeed = speeds[this_speed - 1].evaporator_air_mass_flow;
321 :
322 : const auto &[gross_total_capacity, gross_sensible_capacity, gross_power] =
323 5317 : representation->performance.performance_map_cooling.calculate_performance(outdoor_coil_entering_dry_bulb_temperature_K,
324 : indoor_coil_entering_relative_humidity,
325 : indoor_coil_entering_dry_bulb_temperature_K,
326 : mass_flow_rate_upperspeed,
327 : this_speed,
328 : ambient_pressure,
329 5317 : interpolation_type);
330 5317 : set_output_node_conditions(state, inletNode, outletNode, gross_total_capacity, gross_sensible_capacity, mass_flow_rate_upperspeed);
331 :
332 : // If discrete and multispeed, evaluate next lower speed using PLR, then combine with input speed for final outlet conditions
333 5317 : if (ratio < 1.0) {
334 1621 : auto lowerspeed = this_speed - 1;
335 1621 : auto mass_flow_rate_lowerspeed = speeds[lowerspeed - 1].evaporator_air_mass_flow;
336 :
337 : const auto &[gross_capacity_lower_speed, gross_sensible_capacity_lower_speed, power_lower_speed] =
338 1621 : representation->performance.performance_map_cooling.calculate_performance(outdoor_coil_entering_dry_bulb_temperature_K,
339 : indoor_coil_entering_relative_humidity,
340 : indoor_coil_entering_dry_bulb_temperature_K,
341 : mass_flow_rate_lowerspeed,
342 : lowerspeed,
343 : ambient_pressure,
344 1621 : interpolation_type);
345 1621 : auto upperspeed_outlet_humrat = outletNode.HumRat;
346 1621 : auto upperspeed_outlet_enthalpy = outletNode.Enthalpy;
347 1621 : set_output_node_conditions(
348 : state, inletNode, outletNode, gross_capacity_lower_speed, gross_sensible_capacity_lower_speed, mass_flow_rate_lowerspeed);
349 :
350 : // Adjust outlet node with weighted high- and low-speed values, normalizing by the inlet's mfr (which is already correctly averaged).
351 1621 : outletNode.HumRat =
352 1621 : (upperspeed_outlet_humrat * ratio * mass_flow_rate_upperspeed + (1.0 - ratio) * outletNode.HumRat * mass_flow_rate_lowerspeed) /
353 1621 : inletNode.MassFlowRate;
354 1621 : outletNode.Enthalpy = (upperspeed_outlet_enthalpy * ratio * mass_flow_rate_upperspeed +
355 1621 : (1.0 - ratio) * outletNode.Enthalpy * mass_flow_rate_lowerspeed) /
356 1621 : inletNode.MassFlowRate;
357 1621 : outletNode.Temp = Psychrometrics::PsyTdbFnHW(outletNode.Enthalpy, outletNode.HumRat);
358 :
359 1621 : powerUse = ratio * gross_power + (1.0 - ratio) * power_lower_speed;
360 : } else {
361 3696 : powerUse = gross_power;
362 : }
363 : }
364 : }
365 : }
366 :
367 13903 : void CoilCoolingDX205Performance::calculate_cycling_capcacity(EnergyPlus::EnergyPlusData &state,
368 : const DataLoopNode::NodeData &inletNode,
369 : DataLoopNode::NodeData &outletNode,
370 : Real64 const gross_power,
371 : Real64 const ratio,
372 : HVAC::FanOp const fanOpMode)
373 : {
374 13903 : auto cd = representation->performance.cycling_degradation_coefficient;
375 13903 : auto part_load_factor = (1.0 - cd) + (cd * ratio);
376 13903 : RTF = ratio / part_load_factor;
377 13903 : powerUse = gross_power * RTF;
378 13903 : if (fanOpMode == HVAC::FanOp::Continuous) {
379 : // Fan on, compressor cycling
380 0 : outletNode.HumRat = outletNode.HumRat * ratio + (1.0 - ratio) * inletNode.HumRat;
381 0 : outletNode.Enthalpy = outletNode.Enthalpy * ratio + (1.0 - ratio) * inletNode.Enthalpy;
382 0 : outletNode.Temp = Psychrometrics::PsyTdbFnHW(outletNode.Enthalpy, outletNode.HumRat);
383 :
384 : // Check for saturation error and modify temperature at constant enthalpy
385 0 : Real64 tsat = Psychrometrics::PsyTsatFnHPb(state, outletNode.Enthalpy, inletNode.Press);
386 0 : if (outletNode.Temp < tsat) {
387 0 : outletNode.Temp = tsat;
388 0 : outletNode.HumRat = Psychrometrics::PsyWFnTdbH(state, tsat, outletNode.Enthalpy);
389 : }
390 : }
391 13903 : }
392 :
393 36735 : void CoilCoolingDX205Performance::set_output_node_conditions(EnergyPlusData &state,
394 : const DataLoopNode::NodeData &inletNode,
395 : DataLoopNode::NodeData &outletNode,
396 : Real64 gross_total_capacity,
397 : Real64 gross_sensible_capacity,
398 : Real64 air_mass_flow_rate) const
399 : {
400 36735 : auto delta_enthalpy = air_mass_flow_rate == 0.0 ? 0.0 : gross_total_capacity / air_mass_flow_rate;
401 36735 : outletNode.Enthalpy = inletNode.Enthalpy - delta_enthalpy;
402 :
403 : auto delta_temperature =
404 36735 : air_mass_flow_rate == 0.0 ? 0.0 : gross_sensible_capacity / air_mass_flow_rate / Psychrometrics::PsyCpAirFnW(inletNode.HumRat);
405 36735 : outletNode.Temp = inletNode.Temp - delta_temperature;
406 :
407 36735 : outletNode.HumRat = Psychrometrics::PsyWFnTdbH(state, outletNode.Temp, outletNode.Enthalpy);
408 :
409 36735 : outletNode.Press = inletNode.Press;
410 :
411 36735 : return;
412 : }
413 :
414 1 : Real64 CoilCoolingDX205Performance::grossRatedSHR(EnergyPlusData &state)
415 : {
416 1 : const auto &lookup_variables = calculate_rated_capacities(state, nominal_speed_index);
417 1 : return lookup_variables.gross_sensible_capacity / lookup_variables.gross_total_capacity;
418 : }
419 :
420 1 : Real64 CoilCoolingDX205Performance::ratedTotalCapacityAtSpeedIndex(EnergyPlusData &state, int index)
421 : {
422 1 : return calculate_rated_capacities(state, index).gross_total_capacity;
423 : }
|