LCOV - code coverage report
Current view: top level - EnergyPlus/Coils - CoilCoolingDXCurveFitSpeed.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 312 412 75.7 %
Date: 2023-01-17 19:17:23 Functions: 9 9 100.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : #include <utility>
      49             : 
      50             : #include <EnergyPlus/Autosizing/CoolingAirFlowSizing.hh>
      51             : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
      52             : #include <EnergyPlus/Autosizing/CoolingSHRSizing.hh>
      53             : #include <EnergyPlus/Coils/CoilCoolingDXCurveFitSpeed.hh>
      54             : #include <EnergyPlus/CurveManager.hh>
      55             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      56             : #include <EnergyPlus/DataEnvironment.hh>
      57             : #include <EnergyPlus/DataHVACGlobals.hh>
      58             : #include <EnergyPlus/DataIPShortCuts.hh>
      59             : #include <EnergyPlus/DataPrecisionGlobals.hh>
      60             : #include <EnergyPlus/DataSizing.hh>
      61             : #include <EnergyPlus/General.hh>
      62             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      63             : #include <EnergyPlus/Psychrometrics.hh>
      64             : 
      65             : using namespace EnergyPlus;
      66             : 
      67         119 : void CoilCoolingDXCurveFitSpeed::instantiateFromInputSpec(EnergyPlus::EnergyPlusData &state,
      68             :                                                           const CoilCoolingDXCurveFitSpeedInputSpecification &input_data)
      69             : {
      70         119 :     bool errorsFound(false);
      71             :     static constexpr std::string_view routineName("CoilCoolingDXCurveFitSpeed::instantiateFromInputSpec: ");
      72         119 :     this->original_input_specs = input_data;
      73         119 :     this->name = input_data.name;
      74         119 :     this->active_fraction_of_face_coil_area = input_data.active_fraction_of_coil_face_area;
      75         119 :     if (this->active_fraction_of_face_coil_area < 1.0) this->adjustForFaceArea = true;
      76         119 :     this->rated_evap_fan_power_per_volume_flow_rate = input_data.rated_evaporator_fan_power_per_volume_flow_rate;
      77         119 :     this->rated_evap_fan_power_per_volume_flow_rate_2023 = input_data.rated_evaporator_fan_power_per_volume_flow_rate_2023;
      78         119 :     this->evap_condenser_pump_power_fraction = input_data.rated_evaporative_condenser_pump_power_fraction;
      79         119 :     this->evap_condenser_effectiveness = input_data.evaporative_condenser_effectiveness;
      80         119 :     this->ratedWasteHeatFractionOfPowerInput = input_data.rated_waste_heat_fraction_of_power_input;
      81         119 :     this->ratedCOP = input_data.gross_rated_cooling_COP;
      82         119 :     errorsFound |= this->processCurve(state,
      83             :                                       input_data.total_cooling_capacity_function_of_temperature_curve_name,
      84             :                                       this->indexCapFT,
      85             :                                       {1, 2},
      86             :                                       routineName,
      87             :                                       "Total Cooling Capacity Function of Temperature Curve Name",
      88             :                                       RatedInletWetBulbTemp,
      89             :                                       RatedOutdoorAirTemp);
      90             : 
      91         119 :     errorsFound |= this->processCurve(state,
      92             :                                       input_data.total_cooling_capacity_function_of_air_flow_fraction_curve_name,
      93             :                                       this->indexCapFFF,
      94             :                                       {1},
      95             :                                       routineName,
      96             :                                       "Total Cooling Capacity Function of Air Flow Fraction Curve Name",
      97             :                                       1.0);
      98             : 
      99         119 :     errorsFound |= this->processCurve(state,
     100             :                                       input_data.energy_input_ratio_function_of_temperature_curve_name,
     101             :                                       this->indexEIRFT,
     102             :                                       {1, 2},
     103             :                                       routineName,
     104             :                                       "Energy Input Ratio Function of Temperature Curve Name",
     105             :                                       RatedInletWetBulbTemp,
     106             :                                       RatedOutdoorAirTemp);
     107             : 
     108         119 :     errorsFound |= this->processCurve(state,
     109             :                                       input_data.energy_input_ratio_function_of_air_flow_fraction_curve_name,
     110             :                                       this->indexEIRFFF,
     111             :                                       {1},
     112             :                                       routineName,
     113             :                                       "Energy Input Ratio Function of Air Flow Fraction Curve Name",
     114             :                                       1.0);
     115             : 
     116         119 :     errorsFound |= this->processCurve(state,
     117             :                                       input_data.sensible_heat_ratio_modifier_function_of_temperature_curve_name,
     118             :                                       this->indexSHRFT,
     119             :                                       {2}, // Only allow bivariate functions since curve inputs are different from other f(Temp) functions
     120             :                                       routineName,
     121             :                                       "Sensible Heat Ratio Modifier Function of Temperature Curve Name",
     122             :                                       RatedInletWetBulbTemp,
     123             :                                       RatedOutdoorAirTemp);
     124             : 
     125         119 :     errorsFound |= this->processCurve(state,
     126             :                                       input_data.sensible_heat_ratio_modifier_function_of_flow_fraction_curve_name,
     127             :                                       this->indexSHRFFF,
     128             :                                       {1},
     129             :                                       routineName,
     130             :                                       "Sensible Heat Ratio Modifier Function of Air Flow Fraction Curve Name",
     131             :                                       1.0);
     132             : 
     133         119 :     errorsFound |= this->processCurve(state,
     134             :                                       input_data.waste_heat_function_of_temperature_curve_name,
     135             :                                       this->indexWHFT,
     136             :                                       {2},
     137             :                                       routineName,
     138             :                                       "Waste Heat Modifier Function of Temperature Curve Name",
     139             :                                       RatedOutdoorAirTemp,
     140             :                                       RatedInletAirTemp);
     141             : 
     142         119 :     if (!errorsFound && !input_data.waste_heat_function_of_temperature_curve_name.empty()) {
     143          57 :         Real64 CurveVal = Curve::CurveValue(state, this->indexWHFT, RatedOutdoorAirTemp, RatedInletAirTemp);
     144          57 :         if (CurveVal > 1.10 || CurveVal < 0.90) {
     145           0 :             ShowWarningError(state, std::string{routineName} + this->object_name + "=\"" + this->name + "\", curve values");
     146           0 :             ShowContinueError(state,
     147           0 :                               "Waste Heat Modifier Function of Temperature Curve Name = " + input_data.waste_heat_function_of_temperature_curve_name);
     148           0 :             ShowContinueError(
     149             :                 state, "...Waste Heat Modifier Function of Temperature Curve Name output is not equal to 1.0 (+ or - 10%) at rated conditions.");
     150           0 :             ShowContinueError(state, format("...Curve output at rated conditions = {:.3T}", CurveVal));
     151             :         }
     152             :     }
     153             : 
     154         238 :     std::string fieldName("Part Load Fraction Correlation Curve Name");
     155         238 :     std::string curveName(input_data.part_load_fraction_correlation_curve_name);
     156         119 :     errorsFound |= this->processCurve(state,
     157             :                                       input_data.part_load_fraction_correlation_curve_name,
     158             :                                       this->indexPLRFPLF,
     159             :                                       {1},
     160             :                                       routineName,
     161             :                                       "Part Load Fraction Correlation Curve Name",
     162             :                                       1.0);
     163             : 
     164         119 :     if (this->indexPLRFPLF > 0 && !errorsFound) {
     165             :         //     Test PLF curve minimum and maximum. Cap if less than 0.7 or greater than 1.0.
     166         119 :         Real64 MinCurveVal = 999.0;
     167         119 :         Real64 MaxCurveVal = -999.0;
     168         119 :         Real64 CurveInput = 0.0;
     169         119 :         Real64 MinCurvePLR = 0.0, MaxCurvePLR = 0.0;
     170       23919 :         while (CurveInput <= 1.0) {
     171       11900 :             Real64 CurveVal = Curve::CurveValue(state, this->indexPLRFPLF, CurveInput);
     172       11900 :             if (CurveVal < MinCurveVal) {
     173         119 :                 MinCurveVal = CurveVal;
     174         119 :                 MinCurvePLR = CurveInput;
     175             :             }
     176       11900 :             if (CurveVal > MaxCurveVal) {
     177       11801 :                 MaxCurveVal = CurveVal;
     178       11801 :                 MaxCurvePLR = CurveInput;
     179             :             }
     180       11900 :             CurveInput += 0.01;
     181             :         }
     182         119 :         if (MinCurveVal < 0.7) {
     183           0 :             ShowWarningError(state, std::string{routineName} + this->object_name + "=\"" + this->name + "\", invalid");
     184           0 :             ShowContinueError(state, "..." + fieldName + "=\"" + curveName + "\" has out of range values.");
     185           0 :             ShowContinueError(state, format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", MinCurvePLR, MinCurveVal));
     186           0 :             ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues.");
     187           0 :             Curve::SetCurveOutputMinMaxValues(state, this->indexPLRFPLF, errorsFound, 0.7, _);
     188             :         }
     189             : 
     190         119 :         if (MaxCurveVal > 1.0) {
     191           0 :             ShowWarningError(state, std::string{routineName} + this->object_name + "=\"" + this->name + "\", invalid");
     192           0 :             ShowContinueError(state, "..." + fieldName + " = " + curveName + " has out of range value.");
     193           0 :             ShowContinueError(state, format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", MaxCurvePLR, MaxCurveVal));
     194           0 :             ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues.");
     195           0 :             Curve::SetCurveOutputMinMaxValues(state, this->indexPLRFPLF, errorsFound, _, 1.0);
     196             :         }
     197             :     }
     198             : 
     199         119 :     if (errorsFound) {
     200           0 :         ShowFatalError(
     201           0 :             state, std::string{routineName} + "Errors found in getting " + this->object_name + " input. Preceding condition(s) causes termination.");
     202             :     }
     203         119 : }
     204             : 
     205         952 : bool CoilCoolingDXCurveFitSpeed::processCurve(EnergyPlus::EnergyPlusData &state,
     206             :                                               const std::string &curveName,
     207             :                                               int &curveIndex,
     208             :                                               std::vector<int> validDims,
     209             :                                               std::string_view const routineName,
     210             :                                               const std::string &fieldName,
     211             :                                               Real64 const Var1,           // required 1st independent variable
     212             :                                               Optional<Real64 const> Var2) // 2nd independent variable
     213             : {
     214         952 :     if (curveName.empty()) {
     215         294 :         return false;
     216             :     } else {
     217         658 :         curveIndex = Curve::GetCurveIndex(state, curveName);
     218         658 :         if (curveIndex == 0) {
     219           0 :             ShowSevereError(state, std::string{routineName} + this->object_name + "=\"" + this->name + "\", invalid");
     220           0 :             ShowContinueError(state, "...not found " + fieldName + "=\"" + curveName + "\".");
     221           0 :             return true;
     222             :         } else {
     223             :             // Verify Curve Object dimensions
     224        1974 :             bool errorFound = Curve::CheckCurveDims(state,
     225             :                                                     curveIndex,           // Curve index
     226         658 :                                                     std::move(validDims), // Valid dimensions
     227             :                                                     routineName,          // Routine name
     228             :                                                     this->object_name,    // Object Type
     229             :                                                     this->name,           // Object Name
     230         658 :                                                     fieldName);           // Field Name
     231         658 :             if (!errorFound) {
     232        1974 :                 Curve::checkCurveIsNormalizedToOne(
     233        1316 :                     state, std::string{routineName} + this->object_name, this->name, curveIndex, fieldName, curveName, Var1, Var2);
     234             :             }
     235         658 :             return errorFound;
     236             :         }
     237             :     }
     238             : }
     239             : 
     240         119 : CoilCoolingDXCurveFitSpeed::CoilCoolingDXCurveFitSpeed(EnergyPlus::EnergyPlusData &state, const std::string &name_to_find)
     241             :     : // model inputs
     242             :       indexCapFT(0), indexCapFFF(0), indexEIRFT(0), indexEIRFFF(0), indexPLRFPLF(0), indexWHFT(0), indexSHRFT(0), indexSHRFFF(0),
     243             : 
     244             :       // speed class inputs
     245             :       RatedAirMassFlowRate(0.0),     // rated air mass flow rate at speed {kg/s}
     246             :       RatedCondAirMassFlowRate(0.0), // condenser air mass flow rate at speed {kg/s}
     247             :       grossRatedSHR(0.0),            // rated sensible heat ratio at speed
     248             :       RatedCBF(0.0),                 // rated coil bypass factor at speed
     249             :       RatedEIR(0.0),                 // rated energy input ratio at speed {W/W}
     250             :       ratedCOP(0.0), rated_total_capacity(0.0), rated_evap_fan_power_per_volume_flow_rate(0.0),
     251             :       ratedWasteHeatFractionOfPowerInput(0.0), // rated waste heat fraction of power input
     252             :       evap_condenser_pump_power_fraction(0.0), evap_condenser_effectiveness(0.0),
     253             : 
     254             :       parentModeRatedGrossTotalCap(0.0), parentModeRatedEvapAirFlowRate(0.0), parentModeRatedCondAirFlowRate(0.0), parentOperatingMode(0),
     255             : 
     256             :       ambPressure(0.0), // outdoor pressure {Pa}
     257             :       PLR(0.0),         // coil operating part load ratio
     258             :       AirFF(0.0),       // ratio of air mass flow rate to rated air mass flow rate
     259             :                         // RatedTotCap( 0.0 ), // rated total capacity at speed {W}
     260             : 
     261             :       fullLoadPower(0.0),     // full load power at speed {W}
     262             :       fullLoadWasteHeat(0.0), // full load waste heat at speed {W}
     263             :       RTF(0.0),               // coil runtime fraction at speed
     264             :       AirMassFlow(0.0),       // coil inlet air mass flow rate {kg/s}
     265             : 
     266             :       // other data members
     267             :       evap_air_flow_rate(0.0), condenser_air_flow_rate(0.0), active_fraction_of_face_coil_area(0.0),
     268             :       ratedLatentCapacity(0.0), // Latent capacity at rated conditions {W}
     269             : 
     270             :       // rating data
     271             :       RatedInletAirTemp(26.6667),       // 26.6667C or 80F
     272             :       RatedInletWetBulbTemp(19.4444),   // 19.44 or 67F
     273             :       RatedInletAirHumRat(0.0111847),   // Humidity ratio corresponding to 80F dry bulb/67F wet bulb
     274             :       RatedOutdoorAirTemp(35.0),        // 35 C or 95F
     275         119 :       DryCoilOutletHumRatioMin(0.00001) // dry coil outlet minimum hum ratio kgH2O/kgdry air
     276             : 
     277             : {
     278         119 :     int numSpeeds = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CoilCoolingDXCurveFitSpeed::object_name);
     279             :     if (numSpeeds <= 0) {
     280             :         // error
     281             :     }
     282         119 :     bool found_it = false;
     283         846 :     for (int speedNum = 1; speedNum <= numSpeeds; ++speedNum) {
     284             :         int NumAlphas;  // Number of Alphas for each GetObjectItem call
     285             :         int NumNumbers; // Number of Numbers for each GetObjectItem call
     286             :         int IOStatus;
     287        2538 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     288             :                                                                  CoilCoolingDXCurveFitSpeed::object_name,
     289             :                                                                  speedNum,
     290         846 :                                                                  state.dataIPShortCut->cAlphaArgs,
     291             :                                                                  NumAlphas,
     292         846 :                                                                  state.dataIPShortCut->rNumericArgs,
     293             :                                                                  NumNumbers,
     294             :                                                                  IOStatus);
     295         846 :         if (!UtilityRoutines::SameString(name_to_find, state.dataIPShortCut->cAlphaArgs(1))) {
     296         727 :             continue;
     297             :         }
     298         119 :         found_it = true;
     299             : 
     300         238 :         CoilCoolingDXCurveFitSpeedInputSpecification input_specs;
     301             : 
     302         119 :         input_specs.name = state.dataIPShortCut->cAlphaArgs(1);
     303         119 :         input_specs.gross_rated_total_cooling_capacity_ratio_to_nominal = state.dataIPShortCut->rNumericArgs(1);
     304         119 :         input_specs.evaporator_air_flow_fraction = state.dataIPShortCut->rNumericArgs(2);
     305         119 :         input_specs.condenser_air_flow_fraction = state.dataIPShortCut->rNumericArgs(3);
     306         119 :         input_specs.gross_rated_sensible_heat_ratio = state.dataIPShortCut->rNumericArgs(4);
     307         119 :         input_specs.gross_rated_cooling_COP = state.dataIPShortCut->rNumericArgs(5);
     308         119 :         input_specs.active_fraction_of_coil_face_area = state.dataIPShortCut->rNumericArgs(6);
     309         119 :         input_specs.rated_evaporator_fan_power_per_volume_flow_rate = state.dataIPShortCut->rNumericArgs(7);
     310         119 :         input_specs.rated_evaporator_fan_power_per_volume_flow_rate_2023 = state.dataIPShortCut->rNumericArgs(8);
     311         119 :         input_specs.rated_evaporative_condenser_pump_power_fraction = state.dataIPShortCut->rNumericArgs(9);
     312         119 :         input_specs.evaporative_condenser_effectiveness = state.dataIPShortCut->rNumericArgs(10);
     313         119 :         input_specs.total_cooling_capacity_function_of_temperature_curve_name = state.dataIPShortCut->cAlphaArgs(2);
     314         119 :         input_specs.total_cooling_capacity_function_of_air_flow_fraction_curve_name = state.dataIPShortCut->cAlphaArgs(3);
     315         119 :         input_specs.energy_input_ratio_function_of_temperature_curve_name = state.dataIPShortCut->cAlphaArgs(4);
     316         119 :         input_specs.energy_input_ratio_function_of_air_flow_fraction_curve_name = state.dataIPShortCut->cAlphaArgs(5);
     317         119 :         input_specs.part_load_fraction_correlation_curve_name = state.dataIPShortCut->cAlphaArgs(6);
     318         119 :         input_specs.rated_waste_heat_fraction_of_power_input = state.dataIPShortCut->rNumericArgs(11);
     319         119 :         input_specs.waste_heat_function_of_temperature_curve_name = state.dataIPShortCut->cAlphaArgs(7);
     320         119 :         input_specs.sensible_heat_ratio_modifier_function_of_temperature_curve_name = state.dataIPShortCut->cAlphaArgs(8);
     321         119 :         input_specs.sensible_heat_ratio_modifier_function_of_flow_fraction_curve_name = state.dataIPShortCut->cAlphaArgs(9);
     322             : 
     323         119 :         this->instantiateFromInputSpec(state, input_specs);
     324         119 :         break;
     325             :     }
     326             : 
     327         119 :     if (!found_it) {
     328           0 :         ShowFatalError(state, "Could not find Coil:Cooling:DX:CurveFit:Speed object with name: " + name_to_find);
     329             :     }
     330         119 : }
     331             : 
     332         119 : void CoilCoolingDXCurveFitSpeed::size(EnergyPlus::EnergyPlusData &state)
     333             : {
     334             : 
     335             :     static constexpr std::string_view RoutineName = "sizeSpeed";
     336             : 
     337         119 :     this->rated_total_capacity = this->original_input_specs.gross_rated_total_cooling_capacity_ratio_to_nominal * this->parentModeRatedGrossTotalCap;
     338         119 :     this->evap_air_flow_rate = this->original_input_specs.evaporator_air_flow_fraction * this->parentModeRatedEvapAirFlowRate;
     339         119 :     this->condenser_air_flow_rate = this->original_input_specs.condenser_air_flow_fraction * this->parentModeRatedCondAirFlowRate;
     340         119 :     this->grossRatedSHR = this->original_input_specs.gross_rated_sensible_heat_ratio;
     341             : 
     342         119 :     this->RatedAirMassFlowRate =
     343         238 :         this->evap_air_flow_rate *
     344         119 :         Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, RatedInletAirTemp, RatedInletAirHumRat, RoutineName);
     345         119 :     this->RatedCondAirMassFlowRate =
     346         238 :         this->condenser_air_flow_rate *
     347         119 :         Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, RatedInletAirTemp, RatedInletAirHumRat, RoutineName);
     348             : 
     349         119 :     bool PrintFlag = true;
     350         119 :     bool errorsFound = false;
     351         238 :     std::string CompType = this->object_name;
     352         238 :     std::string CompName = this->name;
     353             : 
     354         238 :     CoolingAirFlowSizer sizingCoolingAirFlow;
     355         238 :     std::string stringOverride = "Rated Air Flow Rate [m3/s]";
     356         119 :     if (state.dataGlobal->isEpJSON) stringOverride = "rated_air_flow_rate [m3/s]";
     357         238 :     std::string preFixString;
     358             :     // if (maxSpeeds > 1) preFixString = "Speed " + std::to_string(speedNum + 1) + " ";
     359             :     // stringOverride = preFixString + stringOverride;
     360         119 :     sizingCoolingAirFlow.overrideSizingString(stringOverride);
     361         119 :     if (this->original_input_specs.evaporator_air_flow_fraction < 1.0) {
     362          61 :         state.dataSize->DataDXCoolsLowSpeedsAutozize = true;
     363          61 :         state.dataSize->DataFractionUsedForSizing = this->original_input_specs.evaporator_air_flow_fraction;
     364             :     }
     365         119 :     sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
     366         119 :     this->evap_air_flow_rate = sizingCoolingAirFlow.size(state, this->evap_air_flow_rate, errorsFound);
     367             : 
     368         238 :     std::string SizingString = preFixString + "Gross Cooling Capacity [W]";
     369         238 :     CoolingCapacitySizer sizerCoolingCapacity;
     370         119 :     sizerCoolingCapacity.overrideSizingString(SizingString);
     371         119 :     if (this->original_input_specs.gross_rated_total_cooling_capacity_ratio_to_nominal < 1.0) {
     372          61 :         state.dataSize->DataDXCoolsLowSpeedsAutozize = true;
     373          61 :         state.dataSize->DataConstantUsedForSizing = -999.0;
     374          61 :         state.dataSize->DataFlowUsedForSizing = this->parentModeRatedEvapAirFlowRate;
     375          61 :         state.dataSize->DataFractionUsedForSizing = this->original_input_specs.gross_rated_total_cooling_capacity_ratio_to_nominal;
     376             :     }
     377         119 :     sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
     378         119 :     this->rated_total_capacity = sizerCoolingCapacity.size(state, this->rated_total_capacity, errorsFound);
     379             : 
     380             :     //  DataSizing::DataEMSOverrideON = DXCoil( DXCoilNum ).RatedSHREMSOverrideOn( Mode );
     381             :     //  DataSizing::DataEMSOverride = DXCoil( DXCoilNum ).RatedSHREMSOverrideValue( Mode );
     382         119 :     state.dataSize->DataFlowUsedForSizing = this->evap_air_flow_rate;
     383         119 :     state.dataSize->DataCapacityUsedForSizing = this->rated_total_capacity;
     384         119 :     bool errorFound = false;
     385         238 :     CoolingSHRSizer sizerCoolingSHR;
     386         119 :     sizerCoolingSHR.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
     387         119 :     if (this->grossRatedSHR == DataSizing::AutoSize && this->parentOperatingMode == 2) {
     388           0 :         state.dataSize->DataSizingFraction = 0.667;
     389           0 :         this->grossRatedSHR = sizerCoolingSHR.size(state, this->grossRatedSHR, errorFound);
     390         119 :     } else if (this->grossRatedSHR == DataSizing::AutoSize && this->parentOperatingMode == 3) {
     391           0 :         state.dataSize->DataSizingFraction = 0.333;
     392           0 :         this->grossRatedSHR = sizerCoolingSHR.size(state, this->grossRatedSHR, errorFound);
     393             :     } else {
     394         119 :         this->grossRatedSHR = sizerCoolingSHR.size(state, this->grossRatedSHR, errorFound);
     395             :     }
     396         119 :     state.dataSize->DataFlowUsedForSizing = 0.0;
     397         119 :     state.dataSize->DataCapacityUsedForSizing = 0.0;
     398         119 :     state.dataSize->DataTotCapCurveIndex = 0;
     399         119 :     state.dataSize->DataSizingFraction = 1.0;
     400             :     //  DataSizing::DataEMSOverrideON = false;
     401             :     //  DataSizing::DataEMSOverride = 0.0;
     402             : 
     403         119 :     if (this->indexSHRFT > 0 && this->indexSHRFFF > 0) {
     404           3 :         this->RatedCBF = 0.001;
     405             :     } else {
     406             : 
     407         116 :         this->RatedCBF = CalcBypassFactor(state,
     408             :                                           RatedInletAirTemp,
     409             :                                           RatedInletAirHumRat,
     410             :                                           this->rated_total_capacity,
     411             :                                           this->grossRatedSHR,
     412             :                                           Psychrometrics::PsyHFnTdbW(RatedInletAirTemp, RatedInletAirHumRat),
     413             :                                           DataEnvironment::StdPressureSeaLevel);
     414             :     }
     415         119 :     this->RatedEIR = 1.0 / this->original_input_specs.gross_rated_cooling_COP;
     416         119 :     this->ratedLatentCapacity = this->rated_total_capacity * (1.0 - this->grossRatedSHR);
     417             : 
     418             :     // reset for next speed or coil
     419         119 :     state.dataSize->DataConstantUsedForSizing = 0.0;
     420         119 :     state.dataSize->DataDXCoolsLowSpeedsAutozize = false;
     421         119 : }
     422             : 
     423     4689333 : void CoilCoolingDXCurveFitSpeed::CalcSpeedOutput(EnergyPlus::EnergyPlusData &state,
     424             :                                                  const DataLoopNode::NodeData &inletNode,
     425             :                                                  DataLoopNode::NodeData &outletNode,
     426             :                                                  Real64 &_PLR,
     427             :                                                  int const fanOpMode,
     428             :                                                  const Real64 condInletTemp)
     429             : {
     430             : 
     431             :     // SUBROUTINE PARAMETER DEFINITIONS:
     432             :     static constexpr std::string_view RoutineName("CalcSpeedOutput: ");
     433             : 
     434     4689333 :     if ((_PLR == 0.0) || (AirMassFlow == 0.0)) {
     435     1945811 :         outletNode.Temp = inletNode.Temp;
     436     1945811 :         outletNode.HumRat = inletNode.HumRat;
     437     1945811 :         outletNode.Enthalpy = inletNode.Enthalpy;
     438     1945811 :         outletNode.Press = inletNode.Press;
     439     1945811 :         fullLoadPower = 0.0;
     440     1945811 :         fullLoadWasteHeat = 0.0;
     441     1945811 :         RTF = 0.0;
     442     1945811 :         return;
     443             :     }
     444             : 
     445             :     Real64 hDelta; // enthalpy difference across cooling coil
     446             :     Real64 A0;     // ratio of UA to Cp
     447             :     Real64 CBF;    // adjusted coil bypass factor
     448     2743522 :     if (RatedCBF > 0.0) {
     449     2743522 :         A0 = -std::log(RatedCBF) * RatedAirMassFlowRate;
     450             :     } else {
     451             :         // This is bad - results in CBF = 1.0 which results in divide by zero below: hADP = inletState.h - hDelta / (1.0 - CBF)
     452           0 :         ShowFatalError(state, format("{}Rated CBF={:.6R} is <= 0.0 for {}={}", RoutineName, RatedCBF, object_name, name));
     453           0 :         A0 = 0.0;
     454             :     }
     455     2743522 :     Real64 ADiff = -A0 / AirMassFlow;
     456     2743522 :     if (ADiff >= DataPrecisionGlobals::EXP_LowerLimit) {
     457     2735026 :         CBF = std::exp(ADiff);
     458             :     } else {
     459        8496 :         CBF = 0.0;
     460             :     }
     461             : 
     462     2743522 :     assert(ambPressure > 0.0);
     463     2743522 :     Real64 inletWetBulb = Psychrometrics::PsyTwbFnTdbWPb(state, inletNode.Temp, inletNode.HumRat, ambPressure);
     464     2743522 :     Real64 inletw = inletNode.HumRat;
     465             : 
     466     2743522 :     int Counter = 0;                  // iteration counter for dry coil condition
     467     2743522 :     int constexpr MaxIter(30);        // iteration limit
     468     2743522 :     Real64 constexpr Tolerance(0.01); // iteration convergence limit
     469     2743522 :     Real64 RF = 0.4;                  // relaxation factor for holding back changes in value during iteration
     470             :     Real64 TotCap;
     471             :     Real64 SHR;
     472             :     while (true) {
     473             : 
     474     2749949 :         Real64 TotCapTempModFac = 1.0;
     475     2749949 :         if (indexCapFT > 0) {
     476     2749949 :             if (state.dataCurveManager->PerfCurve(indexCapFT).numDims == 2) {
     477     2749949 :                 TotCapTempModFac = Curve::CurveValue(state, indexCapFT, inletWetBulb, condInletTemp);
     478             :             } else {
     479           0 :                 TotCapTempModFac = Curve::CurveValue(state, indexCapFT, condInletTemp);
     480             :             }
     481             :         }
     482     2749949 :         Real64 TotCapFlowModFac = 1.0;
     483     2749949 :         if (indexCapFFF > 0) {
     484     2749949 :             TotCapFlowModFac = Curve::CurveValue(state, indexCapFFF, AirFF);
     485             :         }
     486             : 
     487     2749949 :         TotCap = this->rated_total_capacity * TotCapFlowModFac * TotCapTempModFac;
     488     2749949 :         hDelta = TotCap / AirMassFlow;
     489             : 
     490     2749949 :         if (indexSHRFT > 0 && indexSHRFFF > 0) {
     491       35209 :             Real64 SHRTempModFrac = 1.0;
     492       35209 :             if (indexSHRFT > 0) {
     493       35209 :                 SHRTempModFrac = max(Curve::CurveValue(state, indexSHRFT, inletWetBulb, inletNode.Temp), 0.0);
     494             :             }
     495             : 
     496       35209 :             Real64 SHRFlowModFrac = 1.0;
     497       35209 :             if (indexSHRFFF > 0) {
     498       35209 :                 SHRFlowModFrac = max(Curve::CurveValue(state, indexSHRFFF, AirFF), 0.0);
     499             :             }
     500             : 
     501       35209 :             SHR = this->grossRatedSHR * SHRTempModFrac * SHRFlowModFrac;
     502       35209 :             SHR = max(min(SHR, 1.0), 0.0);
     503       35209 :             break;
     504             :         } else {
     505             :             // Calculate apparatus dew point conditions using TotCap and CBF
     506     2714740 :             Real64 hADP = inletNode.Enthalpy - hDelta / (1.0 - CBF);
     507     2714740 :             Real64 tADP = Psychrometrics::PsyTsatFnHPb(state, hADP, ambPressure, RoutineName);
     508     2714740 :             Real64 wADP = Psychrometrics::PsyWFnTdbH(state, tADP, hADP, RoutineName);
     509     2714740 :             Real64 hTinwADP = Psychrometrics::PsyHFnTdbW(inletNode.Temp, wADP);
     510     2714740 :             if ((inletNode.Enthalpy - hADP) > 1.e-10) {
     511     2714740 :                 SHR = min((hTinwADP - hADP) / (inletNode.Enthalpy - hADP), 1.0);
     512             :             } else {
     513           0 :                 SHR = 1.0;
     514             :             }
     515             :             // Check for dry evaporator conditions (win < wadp)
     516     2714740 :             if (wADP > inletw || (Counter >= 1 && Counter < MaxIter)) {
     517       11111 :                 if (inletw == 0.0) inletw = 0.00001;
     518       11111 :                 Real64 werror = (inletw - wADP) / inletw;
     519             :                 // Increase InletAirHumRatTemp at constant InletAirTemp to find coil dry-out point. Then use the
     520             :                 // capacity at the dry-out point to determine exiting conditions from coil. This is required
     521             :                 // since the TotCapTempModFac doesn't work properly with dry-coil conditions.
     522       11111 :                 inletw = RF * wADP + (1.0 - RF) * inletw;
     523       11111 :                 inletWetBulb = Psychrometrics::PsyTwbFnTdbWPb(state, inletNode.Temp, inletw, ambPressure);
     524       11111 :                 ++Counter;
     525       11111 :                 if (std::abs(werror) > Tolerance) continue; // Recalculate with modified inlet conditions
     526        4684 :                 break;
     527             :             } else {
     528             :                 break;
     529             :             }
     530             :         }
     531        6427 :     }
     532             : 
     533     2743522 :     assert(SHR >= 0.0);
     534             : 
     535     2743522 :     Real64 PLF = 1.0; // part load factor as a function of PLR, RTF = PLR / PLF
     536     2743522 :     if (indexPLRFPLF > 0) {
     537     2743522 :         PLF = Curve::CurveValue(state, indexPLRFPLF, _PLR); // Calculate part-load factor
     538             :     }
     539     2743522 :     if (fanOpMode == DataHVACGlobals::CycFanCycCoil) state.dataHVACGlobal->OnOffFanPartLoadFraction = PLF;
     540             : 
     541     2743522 :     Real64 EIRTempModFac = 1.0; // EIR as a function of temperature curve result
     542     2743522 :     if (indexEIRFT > 0) {
     543     2743522 :         if (state.dataCurveManager->PerfCurve(indexEIRFT).numDims == 2) {
     544     2743522 :             EIRTempModFac = Curve::CurveValue(state, indexEIRFT, inletWetBulb, condInletTemp);
     545             :         } else {
     546           0 :             EIRTempModFac = Curve::CurveValue(state, indexEIRFT, condInletTemp);
     547             :         }
     548             :     }
     549     2743522 :     Real64 EIRFlowModFac = 1.0; // EIR as a function of flow fraction curve result
     550     2743522 :     if (indexEIRFFF > 0) {
     551     2743522 :         EIRFlowModFac = Curve::CurveValue(state, indexEIRFFF, AirFF);
     552             :     }
     553             : 
     554     2743522 :     Real64 wasteHeatTempModFac = 1.0; // waste heat fraction as a function of temperature curve result
     555     2743522 :     if (indexWHFT > 0) {
     556     1044008 :         wasteHeatTempModFac = Curve::CurveValue(state, indexWHFT, condInletTemp, inletNode.Temp);
     557             :     }
     558             : 
     559     2743522 :     Real64 EIR = RatedEIR * EIRFlowModFac * EIRTempModFac;
     560     2743522 :     RTF = _PLR / PLF;
     561     2743522 :     fullLoadPower = TotCap * EIR;
     562     2743522 :     fullLoadWasteHeat = ratedWasteHeatFractionOfPowerInput * wasteHeatTempModFac * fullLoadPower;
     563             : 
     564     2743522 :     outletNode.Enthalpy = inletNode.Enthalpy - hDelta;
     565     2743522 :     Real64 hTinwout = inletNode.Enthalpy - ((1.0 - SHR) * hDelta);
     566     2743522 :     outletNode.HumRat = Psychrometrics::PsyWFnTdbH(state, inletNode.Temp, hTinwout);
     567     2743522 :     outletNode.Temp = Psychrometrics::PsyTdbFnHW(outletNode.Enthalpy, outletNode.HumRat);
     568             : 
     569             :     //  If constant fan with cycling compressor, call function to determine "effective SHR"
     570             :     //  which includes the part-load degradation on latent capacity
     571     2743522 :     if (this->doLatentDegradation && (fanOpMode == DataHVACGlobals::ContFanCycCoil)) {
     572       18878 :         Real64 QLatActual = TotCap * (1.0 - SHR);
     573             :         // TODO: Figure out HeatingRTF for this
     574       18878 :         Real64 HeatingRTF = 0.0;
     575       18878 :         SHR = calcEffectiveSHR(inletNode, inletWetBulb, SHR, RTF, ratedLatentCapacity, QLatActual, HeatingRTF);
     576             :         // Calculate full load output conditions
     577       18878 :         if (SHR > 1.0) SHR = 1.0;
     578       18878 :         hTinwout = inletNode.Enthalpy - (1.0 - SHR) * hDelta;
     579       18878 :         if (SHR < 1.0) {
     580        9784 :             outletNode.HumRat = Psychrometrics::PsyWFnTdbH(state, inletNode.Temp, hTinwout, RoutineName);
     581             :         } else {
     582        9094 :             outletNode.HumRat = inletNode.HumRat;
     583             :         }
     584       18878 :         outletNode.Temp = Psychrometrics::PsyTdbFnHW(outletNode.Enthalpy, outletNode.HumRat);
     585             :     }
     586             :     // Check for saturation error and modify temperature at constant enthalpy
     587     2743522 :     Real64 tsat = Psychrometrics::PsyTsatFnHPb(state, outletNode.Enthalpy, inletNode.Press, RoutineName);
     588     2743522 :     if (outletNode.Temp < tsat) {
     589      254391 :         outletNode.Temp = tsat;
     590      254391 :         outletNode.HumRat = Psychrometrics::PsyWFnTdbH(state, tsat, outletNode.Enthalpy);
     591             :     }
     592             : }
     593             : 
     594         116 : Real64 CoilCoolingDXCurveFitSpeed::CalcBypassFactor(EnergyPlus::EnergyPlusData &state,
     595             :                                                     Real64 const tdb, // Inlet dry-bulb temperature {C}
     596             :                                                     Real64 const w,   // Inlet humidity ratio {kg-H2O/kg-dryair}
     597             :                                                     Real64 const q,   // Total capacity {W}
     598             :                                                     Real64 const shr, // SHR
     599             :                                                     Real64 const h,   // Inlet enthalpy {J/kg-dryair}
     600             :                                                     Real64 const p)   // Outlet node pressure {Pa}
     601             : {
     602             : 
     603             :     static constexpr std::string_view RoutineName("CalcBypassFactor: ");
     604         116 :     Real64 constexpr SmallDifferenceTest(0.00000001);
     605             : 
     606             :     // Bypass factors are calculated at rated conditions at sea level (make sure in.p is Standard Pressure)
     607             :     Real64 calcCBF;
     608             : 
     609         116 :     Real64 airMassFlowRate = this->evap_air_flow_rate * Psychrometrics::PsyRhoAirFnPbTdbW(state, p, tdb, w);
     610         116 :     Real64 deltaH = q / airMassFlowRate;
     611         116 :     Real64 outp = p;
     612         116 :     Real64 outh = h - deltaH;
     613         116 :     Real64 outw = Psychrometrics::PsyWFnTdbH(state, tdb, h - (1.0 - shr) * deltaH); // enthalpy at Tdb,in and Wout
     614         116 :     Real64 outtdb = Psychrometrics::PsyTdbFnHW(outh, outw);
     615         116 :     Real64 outrh = Psychrometrics::PsyRhFnTdbWPb(state, outtdb, outw, outp);
     616             : 
     617         116 :     if (outrh >= 1.0) {
     618           0 :         ShowWarningError(state, std::string{RoutineName} + ": For object = " + this->object_name + ", name = \"" + this->name + "\"");
     619           0 :         ShowContinueError(state, "Calculated outlet air relative humidity greater than 1. The combination of");
     620           0 :         ShowContinueError(state, "rated air volume flow rate, total cooling capacity and sensible heat ratio yields coil exiting");
     621           0 :         ShowContinueError(state, "air conditions above the saturation curve. Possible fixes are to reduce the rated total cooling");
     622           0 :         ShowContinueError(state, "capacity, increase the rated air volume flow rate, or reduce the rated sensible heat ratio for this coil.");
     623           0 :         ShowContinueError(state, "If autosizing, it is recommended that all three of these values be autosized.");
     624           0 :         ShowContinueError(state, "...Inputs used for calculating cooling coil bypass factor.");
     625           0 :         ShowContinueError(state, format("...Inlet Air Temperature     = {:.2R} C", tdb));
     626           0 :         ShowContinueError(state, format("...Outlet Air Temperature    = {:.2R} C", outtdb));
     627           0 :         ShowContinueError(state, format("...Inlet Air Humidity Ratio  = {:.6R} kgWater/kgDryAir", w));
     628           0 :         ShowContinueError(state, format("...Outlet Air Humidity Ratio = {:.6R} kgWater/kgDryAir", outw));
     629           0 :         ShowContinueError(state, format("...Total Cooling Capacity used in calculation = {:.2R} W", q));
     630           0 :         ShowContinueError(state, format("...Air Mass Flow Rate used in calculation     = {:.6R} kg/s", airMassFlowRate));
     631           0 :         ShowContinueError(state, format("...Air Volume Flow Rate used in calculation   = {:.6R} m3/s", this->evap_air_flow_rate));
     632           0 :         if (q > 0.0) {
     633           0 :             if (((this->minRatedVolFlowPerRatedTotCap - this->evap_air_flow_rate / q) > SmallDifferenceTest) ||
     634           0 :                 ((this->evap_air_flow_rate / q - this->maxRatedVolFlowPerRatedTotCap) > SmallDifferenceTest)) {
     635           0 :                 ShowContinueError(state,
     636           0 :                                   format("...Air Volume Flow Rate per Watt of Rated Cooling Capacity is also out of bounds at = {:.7R} m3/s/W",
     637           0 :                                          this->evap_air_flow_rate / q));
     638             :             }
     639             :         }
     640           0 :         Real64 outletAirTempSat = Psychrometrics::PsyTsatFnHPb(state, outh, outp, RoutineName);
     641           0 :         if (outtdb < outletAirTempSat) { // Limit to saturated conditions at OutletAirEnthalpy
     642           0 :             outtdb = outletAirTempSat + 0.005;
     643           0 :             outw = Psychrometrics::PsyWFnTdbH(state, outtdb, outh, RoutineName);
     644           0 :             Real64 adjustedSHR = (Psychrometrics::PsyHFnTdbW(tdb, outw) - outh) / deltaH;
     645           0 :             ShowWarningError(state,
     646           0 :                              std::string{RoutineName} + object_name + " \"" + name +
     647             :                                  "\", SHR adjusted to achieve valid outlet air properties and the simulation continues.");
     648           0 :             ShowContinueError(state, format("Initial SHR = {:.5R}", this->grossRatedSHR));
     649           0 :             ShowContinueError(state, format("Adjusted SHR = {:.5R}", adjustedSHR));
     650             :         }
     651             :     }
     652             : 
     653             :     // ADP conditions
     654         116 :     Real64 adp_tdb = Psychrometrics::PsyTdpFnWPb(state, outw, outp);
     655             : 
     656         116 :     Real64 deltaT = tdb - outtdb;
     657         116 :     Real64 deltaHumRat = w - outw;
     658         116 :     Real64 slopeAtConds = 0.0;
     659         116 :     if (deltaT > 0.0) slopeAtConds = deltaHumRat / deltaT;
     660         116 :     if (slopeAtConds <= 0.0) {
     661           0 :         ShowSevereError(state, this->object_name + " \"" + this->name + "\"");
     662           0 :         ShowContinueError(state, "...Invalid slope or outlet air condition when calculating cooling coil bypass factor.");
     663           0 :         ShowContinueError(state, format("...Slope = {:.8R}", slopeAtConds));
     664           0 :         ShowContinueError(state, format("...Inlet Air Temperature     = {:.2R} C", tdb));
     665           0 :         ShowContinueError(state, format("...Outlet Air Temperature    = {:.2R} C", outtdb));
     666           0 :         ShowContinueError(state, format("...Inlet Air Humidity Ratio  = {:.6R} kgWater/kgDryAir", w));
     667           0 :         ShowContinueError(state, format("...Outlet Air Humidity Ratio = {:.6R} kgWater/kgDryAir", outw));
     668           0 :         ShowContinueError(state, format("...Total Cooling Capacity used in calculation = {:.2R} W", q));
     669           0 :         ShowContinueError(state, format("...Air Mass Flow Rate used in calculation     = {:.6R} kg/s", airMassFlowRate));
     670           0 :         ShowContinueError(state, format("...Air Volume Flow Rate used in calculation   = {:.6R} m3/s", this->evap_air_flow_rate));
     671           0 :         if (q > 0.0) {
     672           0 :             if (((this->minRatedVolFlowPerRatedTotCap - this->evap_air_flow_rate / q) > SmallDifferenceTest) ||
     673           0 :                 ((this->evap_air_flow_rate / q - this->maxRatedVolFlowPerRatedTotCap) > SmallDifferenceTest)) {
     674           0 :                 ShowContinueError(state,
     675           0 :                                   format("...Air Volume Flow Rate per Watt of Rated Cooling Capacity is also out of bounds at = {:.7R} m3/s/W",
     676           0 :                                          this->evap_air_flow_rate / q));
     677             :             }
     678             :         }
     679           0 :         ShowFatalError(state, "Errors found in calculating coil bypass factors");
     680             :     }
     681             : 
     682         116 :     Real64 adp_w = min(outw, Psychrometrics::PsyWFnTdpPb(state, adp_tdb, DataEnvironment::StdPressureSeaLevel));
     683             : 
     684         116 :     int iter = 0;
     685         116 :     int constexpr maxIter(50);
     686         116 :     Real64 errorLast = 100.0;
     687         116 :     Real64 deltaADPTemp = 5.0;
     688         116 :     Real64 tolerance = 1.0; // initial conditions for iteration
     689         116 :     bool cbfErrors = false;
     690        3256 :     while ((iter <= maxIter) && (tolerance > 0.001)) {
     691             : 
     692             :         // Do for IterMax iterations or until the error gets below .1%
     693        1570 :         if (iter > 0) adp_tdb += deltaADPTemp;
     694        1570 :         ++iter;
     695             :         //  Find new slope using guessed Tadp
     696        1570 :         adp_w = min(outw, Psychrometrics::PsyWFnTdpPb(state, adp_tdb, DataEnvironment::StdPressureSeaLevel));
     697        1570 :         Real64 slope = (w - adp_w) / max(0.001, (tdb - adp_tdb));
     698             :         //  check for convergence (slopes are equal to within error tolerance)
     699        1570 :         Real64 error = (slope - slopeAtConds) / slopeAtConds;
     700        1570 :         if ((error > 0.0) && (errorLast < 0.0)) {
     701         472 :             deltaADPTemp = -deltaADPTemp / 2.0;
     702        1098 :         } else if ((error < 0.0) && (errorLast > 0.0)) {
     703         564 :             deltaADPTemp = -deltaADPTemp / 2.0;
     704         534 :         } else if (std::abs(error) > std::abs(errorLast)) {
     705           0 :             deltaADPTemp = -deltaADPTemp / 2.0;
     706             :         }
     707        1570 :         errorLast = error;
     708        1570 :         tolerance = std::abs(error);
     709             :     }
     710             : 
     711             :     //   Calculate Bypass Factor from Enthalpies
     712         116 :     Real64 adp_h = Psychrometrics::PsyHFnTdbW(adp_tdb, adp_w);
     713         116 :     calcCBF = min(1.0, (outh - adp_h) / (h - adp_h));
     714             : 
     715         116 :     if (iter > maxIter) {
     716           0 :         ShowSevereError(state,
     717           0 :                         std::string{RoutineName} + object_name + " \"" + name +
     718             :                             "\" -- coil bypass factor calculation did not converge after max iterations.");
     719           0 :         ShowContinueError(state, format("The RatedSHR of [{:.3R}], entered by the user or autosized (see *.eio file),", this->grossRatedSHR));
     720           0 :         ShowContinueError(state, "may be causing this. The line defined by the coil rated inlet air conditions");
     721           0 :         ShowContinueError(state, "(26.7C drybulb and 19.4C wetbulb) and the RatedSHR (i.e., slope of the line) must intersect");
     722           0 :         ShowContinueError(state, "the saturation curve of the psychrometric chart. If the RatedSHR is too low, then this");
     723           0 :         ShowContinueError(state, "intersection may not occur and the coil bypass factor calculation will not converge.");
     724           0 :         ShowContinueError(state, "If autosizing the SHR, recheck the design supply air humidity ratio and design supply air");
     725           0 :         ShowContinueError(state, "temperature values in the Sizing:System and Sizing:Zone objects. In general, the temperatures");
     726           0 :         ShowContinueError(state, "and humidity ratios specified in these two objects should be the same for each system");
     727           0 :         ShowContinueError(state, "and the zones that it serves.");
     728           0 :         ShowContinueErrorTimeStamp(state, "");
     729           0 :         cbfErrors = true; // Didn't converge within MaxIter iterations
     730             :     }
     731         116 :     if (calcCBF < 0.0) {
     732           0 :         ShowSevereError(state, std::string{RoutineName} + object_name + " \"" + name + "\" -- negative coil bypass factor calculated.");
     733           0 :         ShowContinueErrorTimeStamp(state, "");
     734           0 :         cbfErrors = true; // Negative CBF not valid
     735             :     }
     736             :     // Show fatal error for specific coil that caused a CBF error
     737         116 :     if (cbfErrors) {
     738           0 :         ShowFatalError(state, std::string{RoutineName} + object_name + " \"" + name + "\" Errors found in calculating coil bypass factors");
     739             :     }
     740         116 :     return calcCBF;
     741             : }
     742             : 
     743       18878 : Real64 CoilCoolingDXCurveFitSpeed::calcEffectiveSHR(const DataLoopNode::NodeData &inletNode,
     744             :                                                     Real64 const inletWetBulb,
     745             :                                                     Real64 const SHRss,      // Steady-state sensible heat ratio
     746             :                                                     Real64 const RTF,        // Compressor run-time fraction
     747             :                                                     Real64 const QLatRated,  // Rated latent capacity
     748             :                                                     Real64 const QLatActual, // Actual latent capacity
     749             :                                                     Real64 const HeatingRTF  // Used to recalculate Toff for cycling fan systems
     750             : )
     751             : {
     752             :     // PURPOSE OF THIS FUNCTION:
     753             :     //    Adjust sensible heat ratio to account for degradation of DX coil latent
     754             :     //    capacity at part-load (cycling) conditions.
     755             : 
     756             :     // METHODOLOGY EMPLOYED:
     757             :     //    With model parameters entered by the user, the part-load latent performance
     758             :     //    of a DX cooling coil is determined for a constant air flow system with
     759             :     //    a cooling coil that cycles on/off. The model calculates the time
     760             :     //    required for condensate to begin falling from the cooling coil.
     761             :     //    Runtimes greater than this are integrated to a "part-load" latent
     762             :     //    capacity which is used to determine the "part-load" sensible heat ratio.
     763             :     //    See reference below for additional details (linear decay model, Eq. 8b).
     764             :     // REFERENCES:
     765             :     //   "A Model to Predict the Latent Capacity of Air Conditioners and
     766             :     //    Heat Pumps at Part-Load Conditions with Constant Fan Operation"
     767             :     //    1996 ASHRAE Transactions, Volume 102, Part 1, Pp. 266 - 274,
     768             :     //    Hugh I. Henderson, Jr., P.E., Kannan Rengarajan, P.E.
     769             : 
     770             :     // Return value
     771             :     Real64 SHReff; // Effective sensible heat ratio, includes degradation due to cycling effects
     772             : 
     773             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
     774             :     Real64 Twet; // Nominal time for condensate to begin leaving the coil's condensate drain line
     775             :     //   at the current operating conditions (sec)
     776             :     Real64 Gamma; // Initial moisture evaporation rate divided by steady-state AC latent capacity
     777             :     //   at the current operating conditions
     778             :     Real64 Twet_max; // Maximum allowed value for Twet
     779             :     Real64 Ton;      // Coil on time (sec)
     780             :     Real64 Toff;     // Coil off time (sec)
     781             :     Real64 Toffa;    // Actual coil off time (sec). Equations valid for Toff <= (2.0 * Twet/Gamma)
     782             :     Real64 aa;       // Intermediate variable
     783             :     Real64 To1;      // Intermediate variable (first guess at To). To = time to the start of moisture removal
     784             :     Real64 To2;      // Intermediate variable (second guess at To). To = time to the start of moisture removal
     785             :     Real64 Error;    // Error for iteration (DO) loop
     786             :     Real64 LHRmult;  // Latent Heat Ratio (LHR) multiplier. The effective latent heat ratio LHR = (1-SHRss)*LHRmult
     787             :     Real64 Ton_heating;
     788             :     Real64 Toff_heating;
     789             : 
     790       18878 :     Real64 Twet_Rated = parentModeTimeForCondensateRemoval; // Time wet at rated conditions (sec)
     791       18878 :     Real64 Gamma_Rated = parentModeEvapRateRatio;           // Gamma at rated conditions
     792       18878 :     Real64 Nmax = parentModeMaxCyclingRate;                 // Maximum ON/OFF cycles for the compressor (cycles/hr)
     793       18878 :     Real64 Tcl = parentModeLatentTimeConst;                 // Time constant for latent capacity to reach steady state after startup(sec)
     794             : 
     795             :     //  No moisture evaporation (latent degradation) occurs for runtime fraction of 1.0
     796             :     //  All latent degradation model parameters cause divide by 0.0 if not greater than 0.0
     797             :     //  Latent degradation model parameters initialize to 0.0 meaning no evaporation model used.
     798       18878 :     if (RTF >= 1.0) {
     799        8888 :         SHReff = SHRss;
     800        8888 :         return SHReff;
     801             :     }
     802             : 
     803        9990 :     Twet_max = 9999.0; // high limit for Twet
     804             : 
     805             :     //  Calculate the model parameters at the actual operating conditions
     806        9990 :     Twet = min(Twet_Rated * QLatRated / (QLatActual + 1.e-10), Twet_max);
     807        9990 :     Gamma = Gamma_Rated * QLatRated * (inletNode.Temp - inletWetBulb) / ((26.7 - 19.4) * QLatActual + 1.e-10);
     808             : 
     809             :     //  Calculate the compressor on and off times using a converntional thermostat curve
     810        9990 :     Ton = 3600.0 / (4.0 * Nmax * (1.0 - RTF)); // duration of cooling coil on-cycle (sec)
     811        9990 :     Toff = 3600.0 / (4.0 * Nmax * RTF);        // duration of cooling coil off-cycle (sec)
     812             : 
     813             :     //  Cap Toff to meet the equation restriction
     814        9990 :     if (Gamma > 0.0) {
     815        9990 :         Toffa = min(Toff, 2.0 * Twet / Gamma);
     816             :     } else {
     817           0 :         Toffa = Toff;
     818             :     }
     819             : 
     820             :     //  Need to include the reheat coil operation to account for actual fan run time. E+ uses a
     821             :     //  separate heating coil for heating and reheat (to separate the heating and reheat loads)
     822             :     //  and real world applications would use a single heating coil for both purposes, the actual
     823             :     //  fan operation is based on HeatingPLR + ReheatPLR. For cycling fan RH control, latent
     824             :     //  degradation only occurs when a heating load exists, in this case the reheat load is
     825             :     //  equal to and oposite in magnitude to the cooling coil sensible output but the reheat
     826             :     //  coil is not always active. This additional fan run time has not been accounted for at this time.
     827             :     //  Recalculate Toff for cycling fan systems when heating is active
     828        9990 :     if (HeatingRTF > 0.0) {
     829           0 :         if (HeatingRTF < 1.0 && HeatingRTF > RTF) {
     830           0 :             Ton_heating = 3600.0 / (4.0 * Nmax * (1.0 - HeatingRTF));
     831           0 :             Toff_heating = 3600.0 / (4.0 * Nmax * HeatingRTF);
     832             :             //    add additional heating coil operation during cooling coil off cycle (due to cycling rate difference of coils)
     833           0 :             Ton_heating += max(0.0, min(Ton_heating, (Ton + Toffa) - (Ton_heating + Toff_heating)));
     834           0 :             Toffa = min(Toffa, Ton_heating - Ton);
     835             :         }
     836             :     }
     837             : 
     838             :     //  Use sucessive substitution to solve for To
     839        9990 :     aa = (Gamma * Toffa) - (0.25 / Twet) * pow_2(Gamma) * pow_2(Toffa);
     840        9990 :     To1 = aa + Tcl;
     841        9990 :     Error = 1.0;
     842       41184 :     while (Error > 0.001) {
     843       15597 :         To2 = aa - Tcl * (std::exp(-To1 / Tcl) - 1.0);
     844       15597 :         Error = std::abs((To2 - To1) / To1);
     845       15597 :         To1 = To2;
     846             :     }
     847             : 
     848             :     //  Adjust Sensible Heat Ratio (SHR) using Latent Heat Ratio (LHR) multiplier
     849             :     //  Floating underflow errors occur when -Ton/Tcl is a large negative number.
     850             :     //  Cap lower limit at -700 to avoid the underflow errors.
     851        9990 :     aa = std::exp(max(-700.0, -Ton / Tcl));
     852             :     //  Calculate latent heat ratio multiplier
     853        9990 :     LHRmult = max(((Ton - To2) / (Ton + Tcl * (aa - 1.0))), 0.0);
     854             : 
     855             :     //  Calculate part-load or "effective" sensible heat ratio
     856        9990 :     SHReff = 1.0 - (1.0 - SHRss) * LHRmult;
     857             : 
     858        9990 :     if (SHReff < SHRss) SHReff = SHRss; // Effective SHR can be less than the steady-state SHR
     859        9990 :     if (SHReff > 1.0) SHReff = 1.0;     // Effective sensible heat ratio can't be greater than 1.0
     860             : 
     861        9990 :     return SHReff;
     862        2313 : }

Generated by: LCOV version 1.13