diff --git a/doc/input-output-reference/src/overview/group-zone-forced-air-units.tex b/doc/input-output-reference/src/overview/group-zone-forced-air-units.tex index 9aca5946c31..b7050808255 100644 --- a/doc/input-output-reference/src/overview/group-zone-forced-air-units.tex +++ b/doc/input-output-reference/src/overview/group-zone-forced-air-units.tex @@ -41,19 +41,19 @@ \subsubsection{Inputs}\label{inputs-056} \paragraph{Field: Maximum Heating Supply Air Temperature}\label{field-maximum-heating-supply-air-temperature-000} -The maximum air temperature (degrees C) of the air used for heating the zone. The default is 50C (122F). +The maximum air temperature (\si{\degreeCelsius}) of the air used for heating the zone. The default is 50\si{\degreeCelsius} (122F). \paragraph{Field: Minimum Cooling Supply Air Temperature}\label{field-minimum-cooling-supply-air-temperature-000} -The minimum air temperature (degrees C) of the air used for cooling the zone. The default is 13C (55.4F). +The minimum air temperature (\si{\degreeCelsius}) of the air used for cooling the zone. The default is 13\si{\degreeCelsius} (55.4F). \paragraph{Field: Maximum Heating Supply Air Humidity Ratio}\label{field-maximum-heating-supply-air-humidity-ratio-000} -The maximum humidity ratio (kg of water per kg of dry air) of the hot supply air. The default is 0.0156 kgWater/kgDryAir which corresponds to a 20\%RH at 50C (122F) dry bulb. +The maximum humidity ratio (kg of water per kg of dry air) of the hot supply air. The default is 0.0156 kgWater/kgDryAir which corresponds to a 20\%RH at 50\si{\degreeCelsius} (122F) dry bulb. \paragraph{Field: Minimum Cooling Supply Air Humidity Ratio}\label{field-minimum-cooling-supply-air-humidity-ratio-000} -The minimum humidity ratio (kg of water per kg of dry air) of the cool supply air. The default is 0.0077 kgWater/kgDryAir which corresponds to a 10C (50F) dew point. +The minimum humidity ratio (kg of water per kg of dry air) of the cool supply air. The default is 0.0077 kgWater/kgDryAir which corresponds to a 10\si{\degreeCelsius} (50F) dew point. \paragraph{Field: Heating Limit}\label{field-heating-limit-000} @@ -296,6 +296,14 @@ \subsubsection{Outputs}\label{outputs-043} HVAC,Average,Zone Ideal Loads Supply Air Mass Flow Rate {[}kg/s{]} \item HVAC,Average,Zone Ideal Loads Supply Air Standard Density Volume Flow Rate {[}m3/s{]} +\item + HVAC,Average,Zone Ideal Loads Supply Air Temperature {[}\si{\degreeCelsius}{]} +\item + HVAC,Average,Zone Ideal Loads Supply Air Humidity Ratio {[}kgWater/kgDryAir{]} +\item + HVAC,Average,Zone Ideal Loads Mixed Air Temperature {[}\si{\degreeCelsius}{]} +\item + HVAC,Average,Zone Ideal Loads Mixed Air Humidity Ratio {[}kgWater/kgDryAir{]} \end{itemize} \paragraph{Ideal Loads Output Variable Overview}\label{ideal-loads-output-variable-overview} @@ -476,7 +484,7 @@ \subsubsection{Outputs}\label{outputs-043} \paragraph{Zone Ideal Loads Outdoor Air Standard Density Volume Flow Rate {[}m3/s{]}}\label{zone-ideal-loads-outdoor-air-standard-density-volume-flow-rate-m3s} -The volume flow rate of the outdoor air stream in m3/s using the standard density. The standard density is determined for dry air at the standard barometric pressure for the location's elevation and a temperature of 20.0ºC. The standard density does not vary over time. +The volume flow rate of the outdoor air stream in m3/s using the standard density. The standard density is determined for dry air at the standard barometric pressure for the location's elevation and a temperature of 20.0\si{\degreeCelsius}. The standard density does not vary over time. \paragraph{Zone Ideal Loads Supply Air Mass Flow Rate {[}kg/s{]}}\label{zone-ideal-loads-supply-air-mass-flow-rate-kgs} @@ -484,7 +492,27 @@ \subsubsection{Outputs}\label{outputs-043} \paragraph{Zone Ideal Loads Supply Air Standard Density Volume Flow Rate {[}m3/s{]}}\label{zone-ideal-loads-supply-air-standard-density-volume-flow-rate-m3s} -The volume flow rate of the supply air stream in m3/s using the standard density. The standard density is determined for dry air at the standard barometric pressure for the location's elevation and a temperature of 20.0ºC. The standard density does not vary over time. +The volume flow rate of the supply air stream in m3/s using the standard density. The standard density is determined for dry air at the standard barometric pressure for the location's elevation and a temperature of 20.0\si{\degreeCelsius}. The standard density does not vary over time. + +\paragraph{Zone Ideal Loads Supply Air Temperature {[}\si{\degreeCelsius}{]}}\label{zone-ideal-loads-supply-air-temperature-c} + +The dry bulb temperature of the supply air stream in \si{\degreeCelsius}. + + +\paragraph{Zone Ideal Loads Supply Air Humidity Ratio {[}kgWater/kgDryAir{]}}\label{zone-ideal-loads-supply-air-humidity-ratio-kgWaterkgDryAir} + +The humidity ratio of the supply air stream in kgWater/kgDryAir. + + +\paragraph{Zone Ideal Loads Mixed Air Temperature {[}\si{\degreeCelsius}{]}}\label{zone-ideal-loads-mixed-air-temperature-c} + +The dry bulb temperature of the mixed air stream after mixing the recirculation air stream and outdoor air stream (if present), in \si{\degreeCelsius}. + + +\paragraph{Zone Ideal Loads Mixed Air Humidity Ratio {[}kgWater/kgDryAir{]}}\label{zone-ideal-loads-mixed-air-humidity-ratio-kgWaterkgDryAir} + +The humidity ratio of the mixed air stream after mixing the recirculation air stream and outdoor air stream (if present) in kgWater/kgDryAir. + \subsection{ZoneHVAC:FourPipeFanCoil}\label{zonehvacfourpipefancoil} @@ -1493,7 +1521,7 @@ \subsubsection{Inputs}\label{inputs-4-040} \paragraph{Field: Throttling Range Temperature Difference {[}DeltaC{]}}\label{field-throttling-range-temperature-difference-deltac} -This numeric input field defines the throttling range to use for zone-temperature based control, in degrees Celsius. This value is used when the unit's control method is ZoneTemperatureDeadbandOnOffCycling.~ This temperature range is used for hysteresis thermostatic control.~ It is modeled as symmetric about the cooling setpoint. The default is 1.0°C. +This numeric input field defines the throttling range to use for zone-temperature based control, in degrees Celsius. This value is used when the unit's control method is ZoneTemperatureDeadbandOnOffCycling.~ This temperature range is used for hysteresis thermostatic control.~ It is modeled as symmetric about the cooling setpoint. The default is 1.0\si{\degreeCelsius}. \paragraph{Field: Cooling Load Control Threshold Heat Transfer Rate {[}W{]}}\label{field-cooling-load-control-threshold-heat-transfer-rate-w} @@ -2250,11 +2278,11 @@ \subsubsection{Inputs}\label{inputs-8-029} \paragraph{Field: Minimum Supply Air Temperature in Cooling Mode}\label{field-minimum-supply-air-temperature-in-cooling-mode-2} -When Capacity Control Method = SingleZoneVAV, enter the minimum air temperature limit for reduced fan speed in cooling mode. For SingleZoneVAV, this field's minimum supply air temperature is 0.0\(^{o}\)C. This field is autosizable and the default is autosize. +When Capacity Control Method = SingleZoneVAV, enter the minimum air temperature limit for reduced fan speed in cooling mode. For SingleZoneVAV, this field's minimum supply air temperature is 0.0\si{\degreeCelsius}. This field is autosizable and the default is autosize. \paragraph{Field: Maximum Supply Air Temperature in Heating Mode}\label{field-maximum-supply-air-temperature-in-heating-mode-2} -When Capacity Control Method = SingleZoneVAV, enter the maximum air temperature limit for reduced fan speed in heating mode. For SingleZoneVAV, this field's minimum supply air temperature is 0.0\(^{o}\)C. This field is autosizable and the default is autosize. +When Capacity Control Method = SingleZoneVAV, enter the maximum air temperature limit for reduced fan speed in heating mode. For SingleZoneVAV, this field's minimum supply air temperature is 0.0\si{\degreeCelsius}. This field is autosizable and the default is autosize. As shown in the example below, correct specification of the packaged terminal air conditioner requires the following objects in addition to the compound object itself: @@ -2610,7 +2638,7 @@ \subsubsection{Inputs}\label{inputs-9-026} \paragraph{Field: Maximum Outdoor Dry-Bulb Temperature for Supplemental Heater Operation}\label{field-maximum-outdoor-dry-bulb-temperature-for-supplemental-heater-operation-000} -This numeric field defines the maximum outdoor dry-bulb temperature in degrees Celsius for PTHP supplemental heater operation. The supplemental heater will not operate when the outdoor dry-bulb temperature is above this value. The maximum value must be less than or equal to 21°C. If this field is left blank, the default value is 21°C. +This numeric field defines the maximum outdoor dry-bulb temperature in degrees Celsius for PTHP supplemental heater operation. The supplemental heater will not operate when the outdoor dry-bulb temperature is above this value. The maximum value must be less than or equal to 21\si{\degreeCelsius}. If this field is left blank, the default value is 21\si{\degreeCelsius}. \paragraph{Field: Fan Placement}\label{field-fan-placement-4-000} @@ -2636,11 +2664,11 @@ \subsubsection{Inputs}\label{inputs-9-026} \paragraph{Field: Minimum Supply Air Temperature in Cooling Mode}\label{field-minimum-supply-air-temperature-in-cooling-mode-3} -When Capacity Control Method = SingleZoneVAV, enter the minimum air temperature limit for reduced fan speed in cooling mode. For SingleZoneVAV, this field's minimum supply air temperature is 0.0\(^{o}\)C. This field is autosizable and the default is autosize. +When Capacity Control Method = SingleZoneVAV, enter the minimum air temperature limit for reduced fan speed in cooling mode. For SingleZoneVAV, this field's minimum supply air temperature is 0.0\si{\degreeCelsius}. This field is autosizable and the default is autosize. \paragraph{Field: Maximum Supply Air Temperature in Heating Mode}\label{field-maximum-supply-air-temperature-in-heating-mode-3} -When Capacity Control Method = SingleZoneVAV, enter the maximum air temperature limit for reduced fan speed in heating mode. For SingleZoneVAV, this field's minimum supply air temperature is 0.0\(^{o}\)C. This field is autosizable and the default is autosize. +When Capacity Control Method = SingleZoneVAV, enter the maximum air temperature limit for reduced fan speed in heating mode. For SingleZoneVAV, this field's minimum supply air temperature is 0.0\si{\degreeCelsius}. This field is autosizable and the default is autosize. As shown in the example below, correct specification of the packaged terminal heat pump requires the following objects in addition to the compound object itself: @@ -3095,7 +3123,7 @@ \subsubsection{Inputs}\label{inputs-11-023} \paragraph{Field: Maximum Outdoor Dry-Bulb Temperature for Supplemental Heater Operation}\label{field-maximum-outdoor-dry-bulb-temperature-for-supplemental-heater-operation-1-000} -This numeric field defines the outdoor air dry-bulb temperature in degrees Celsius above which the heat pump supplemental heating coil is disabled. The temperature for this input field must be less than or equal to 21°C. If this input field is left blank, the default value is 21°C. +This numeric field defines the outdoor air dry-bulb temperature in degrees Celsius above which the heat pump supplemental heating coil is disabled. The temperature for this input field must be less than or equal to 21\si{\degreeCelsius}. If this input field is left blank, the default value is 21\si{\degreeCelsius}. \paragraph{Field: Outdoor Dry-Bulb Temperature Sensor Node Name}\label{field-outdoor-dry-bulb-temperature-sensor-node-name-000} @@ -3378,7 +3406,7 @@ \subsection{ZoneHVAC:Dehumidifier:DX}\label{zonehvacdehumidifierdx} \caption{Schematic of a mechanical dehumidifier \protect \label{fig:schematic-of-a-mechanical-dehumidifier}} \end{figure} -The model has inputs for water removal, energy factor and air flow rate at rated conditions (26.7°C, 60\% RH). Curve objects must be specified to describe performance at off-rated conditions. A part-load cycling curve input must also be specified to account for inefficiencies due to cycling. Other inputs including minimum and maximum operating temperatures for dehumidifier operation, off-cycle parasitic load, and an input to direct the removed water to a storage tank. +The model has inputs for water removal, energy factor and air flow rate at rated conditions (26.7\si{\degreeCelsius}, 60\% RH). Curve objects must be specified to describe performance at off-rated conditions. A part-load cycling curve input must also be specified to account for inefficiencies due to cycling. Other inputs including minimum and maximum operating temperatures for dehumidifier operation, off-cycle parasitic load, and an input to direct the removed water to a storage tank. The model assumes that this equipment dehumidifies and heats the air. If used in tandem with another system that cools and dehumidifies the zone air, then the zone dehumidifier should be specified as the lowest cooling priority in the \hyperref[zonehvacequipmentlist]{ZoneHVAC:EquipmentList} object for best control of zone temperature and humidity levels (e.g., if there are 3 pieces of equipment in \hyperref[zonehvacequipmentlist]{ZoneHVAC:EquipmentList}, then the zone dehumidifier should have Cooling Priority = 3). With this zone equipment prioritization, the other cooling and dehumidification system would operate first to meet the temperature setpoint (and possibly meet the high humidity setpoint as well). If additional dehumidification is needed, then the zone dehumidifier would operate. The sensible heat generated by the dehumidifier is carried over to the zone air heat balance for the next HVAC time step. @@ -3402,23 +3430,23 @@ \subsubsection{Inputs}\label{inputs-12-021} \paragraph{Field: Rated Water Removal}\label{field-rated-water-removal} -This numeric input is the full load water removal rate, in liters per day, at rated conditions (air entering the dehumidifier at 26.7°C {[}80°F{]} dry-bulb and 60\% relative humidity, and air flow rate as defined by field ``Rated Air Flow Rate'' below). This is a required input field and the entered value must be greater than zero. +This numeric input is the full load water removal rate, in liters per day, at rated conditions (air entering the dehumidifier at 26.7\si{\degreeCelsius} {[}80°F{]} dry-bulb and 60\% relative humidity, and air flow rate as defined by field ``Rated Air Flow Rate'' below). This is a required input field and the entered value must be greater than zero. \paragraph{Field: Rated Energy Factor}\label{field-rated-energy-factor} -This numeric input is the energy factor (liters of water removed per kWh of electricity consumed) at rated conditions (air entering the dehumidifier at 26.7°C {[}80°F{]} dry-bulb and 60\% relative humidity, and air flow rate as defined by field ``Rated Air Flow Rate'' below). This is a required input field and the entered value must be greater than zero. +This numeric input is the energy factor (liters of water removed per kWh of electricity consumed) at rated conditions (air entering the dehumidifier at 26.7\si{\degreeCelsius} {[}80°F{]} dry-bulb and 60\% relative humidity, and air flow rate as defined by field ``Rated Air Flow Rate'' below). This is a required input field and the entered value must be greater than zero. \paragraph{Field: Rated Air Flow Rate}\label{field-rated-air-flow-rate-001} -This numeric input is the volumetric air flow rate through the dehumidifier, in m\(^{3}\) per second, at rated conditions (air entering the dehumidifier at 26.7°C {[}80°F{]} dry-bulb and 60\% relative humidity). This is a required input field and the entered value must be greater than zero. +This numeric input is the volumetric air flow rate through the dehumidifier, in m\(^{3}\) per second, at rated conditions (air entering the dehumidifier at 26.7\si{\degreeCelsius} {[}80°F{]} dry-bulb and 60\% relative humidity). This is a required input field and the entered value must be greater than zero. \paragraph{Field: Water Removal Curve Name}\label{field-water-removal-curve-name} -This alpha field defines the name of a biquadratic performance curve (ref: Performance Curves) that parameterizes the variation of water removal as a function of the dry-bulb temperature (°C) and relative humidity (\%) of the air entering the dehumidifier. The output of this curve is multiplied by the Rated Water Removal to give the water removal of the dehumidifier at specific operating conditions (i.e., at temperatures and relative humidity levels different from the rating point conditions). The curve should be normalized to have the value of 1.0 at the rating point (air entering the dehumidifier at 26.7°C {[}80°F{]} dry-bulb and 60\% relative humidity, and air flow rate as defined by field ``Rated Air Flow Rate'' above). +This alpha field defines the name of a biquadratic performance curve (ref: Performance Curves) that parameterizes the variation of water removal as a function of the dry-bulb temperature (\si{\degreeCelsius}) and relative humidity (\%) of the air entering the dehumidifier. The output of this curve is multiplied by the Rated Water Removal to give the water removal of the dehumidifier at specific operating conditions (i.e., at temperatures and relative humidity levels different from the rating point conditions). The curve should be normalized to have the value of 1.0 at the rating point (air entering the dehumidifier at 26.7\si{\degreeCelsius} {[}80°F{]} dry-bulb and 60\% relative humidity, and air flow rate as defined by field ``Rated Air Flow Rate'' above). \paragraph{Field: Energy Factor Curve Name}\label{field-energy-factor-curve-name} -This alpha field defines the name of a biquadratic performance curve (ref: Performance Curves) that parameterizes the variation of the energy factor as a function of the dry-bulb temperature (°C) and relative humidity (\%) of the air entering the dehumidifier. The output of this curve is multiplied by the Rated Energy Factor to give the energy factor of the dehumidifier at specific operating conditions (i.e., at temperatures and relative humidity levels different from the rating point conditions). The curve should be normalized to have the value of 1.0 at the rating point (air entering the dehumidifier at 26.7°C {[}80°F{]} dry-bulb and 60\% relative humidity, and air flow rate as defined by field ``Rated Air Flow Rate'' above). +This alpha field defines the name of a biquadratic performance curve (ref: Performance Curves) that parameterizes the variation of the energy factor as a function of the dry-bulb temperature (\si{\degreeCelsius}) and relative humidity (\%) of the air entering the dehumidifier. The output of this curve is multiplied by the Rated Energy Factor to give the energy factor of the dehumidifier at specific operating conditions (i.e., at temperatures and relative humidity levels different from the rating point conditions). The curve should be normalized to have the value of 1.0 at the rating point (air entering the dehumidifier at 26.7\si{\degreeCelsius} {[}80°F{]} dry-bulb and 60\% relative humidity, and air flow rate as defined by field ``Rated Air Flow Rate'' above). \paragraph{Field: Part Load Fraction Correlation Curve Name}\label{field-part-load-fraction-correlation-curve-name-000} @@ -3440,11 +3468,11 @@ \subsubsection{Inputs}\label{inputs-12-021} \paragraph{Field: Minimum Dry-Bulb Temperature for Dehumidifier Operation}\label{field-minimum-dry-bulb-temperature-for-dehumidifier-operation} -This numeric field defines the minimum inlet air dry-bulb temperature for dehumidifier operation. The dehumidifier will not operate if the inlet air temperature is below this value. This input value must be less than the Maximum Dry-Bulb Temperature for Dehumidifier Operation, and the default value is 10°C. +This numeric field defines the minimum inlet air dry-bulb temperature for dehumidifier operation. The dehumidifier will not operate if the inlet air temperature is below this value. This input value must be less than the Maximum Dry-Bulb Temperature for Dehumidifier Operation, and the default value is 10\si{\degreeCelsius}. \paragraph{Field: Maximum Dry-Bulb Temperature for Dehumidifier Operation}\label{field-maximum-dry-bulb-temperature-for-dehumidifier-operation} -This numeric field defines the maximum inlet air dry-bulb temperature for dehumidifier operation. The dehumidifier will not operate if the inlet air temperature is above this value. This input value must be greater than the Minimum Dry-Bulb Temperature for Dehumidifier Operation, and the default value is 35°C. +This numeric field defines the maximum inlet air dry-bulb temperature for dehumidifier operation. The dehumidifier will not operate if the inlet air temperature is above this value. This input value must be greater than the Minimum Dry-Bulb Temperature for Dehumidifier Operation, and the default value is 35\si{\degreeCelsius}. \paragraph{Field: Off-Cycle Parasitic Electric Load}\label{field-off-cycle-parasitic-electric-load-001} @@ -3504,7 +3532,7 @@ \subsubsection{Outputs}\label{outputs-10-008} \item HVAC,Average,Zone Dehumidifier Runtime Fraction {[]} \item - HVAC,Average,Zone Dehumidifier Outlet Air Temperature {[}C{]} + HVAC,Average,Zone Dehumidifier Outlet Air Temperature {[}\si{\degreeCelsius}{]} \end{itemize} If Condensate Collection Water Storage Tank Name is specified: @@ -3552,7 +3580,7 @@ \subsubsection{Outputs}\label{outputs-10-008} This output field is the runtime fraction for the dehumidifier. This value is calculated for each HVAC system timestep, and the results are averaged for the timestep being reported. -\paragraph{Zone Dehumidifier Outlet Air Temperature {[}C{]}}\label{zone-dehumidifier-outlet-air-temperature-c} +\paragraph{Zone Dehumidifier Outlet Air Temperature {[}\si{\degreeCelsius}{]}}\label{zone-dehumidifier-outlet-air-temperature-c} This output field is dry-bulb temperature of the air leaving the dehumidifier in Celsius. This value represents the dry-bulb temperature of the air leaving the dehumidifier when it is operating. For periods when the dehumidifier is not operating, the outlet air temperature is set equal to the inlet air temperature. This value is calculated for each HVAC system timestep, and the results are averaged for the timestep being reported. @@ -3621,7 +3649,7 @@ \subsubsection{Inputs}\label{inputs-13-018} \paragraph{Field: Supply Air Flow Rate}\label{field-supply-air-flow-rate-000} -The supply air flow rate through the ERV unit in cubic meters per second at standard temperature and pressure (dry air at 20\(^{o}\) C drybulb). The program uses local barometric pressure to account for altitude using the equation for ``standard atmospheric'' pressure on p 6.1 of the ASHRAE 1997 HOF (SI edition) to initialize the air systems being simulated. +The supply air flow rate through the ERV unit in cubic meters per second at standard temperature and pressure (dry air at 20\si{\degreeCelsius} drybulb). The program uses local barometric pressure to account for altitude using the equation for ``standard atmospheric'' pressure on p 6.1 of the ASHRAE 1997 HOF (SI edition) to initialize the air systems being simulated. p = 101325*(1-2.25577E-05*Z)**5.2559 @@ -3633,7 +3661,7 @@ \subsubsection{Inputs}\label{inputs-13-018} \paragraph{Field: Exhaust Air Flow Rate}\label{field-exhaust-air-flow-rate-1} -The exhaust air flow rate through the ERV unit in cubic meters per second at standard temperature and pressure (dry air at 20\(^{o}\) C drybulb). The program uses local barometric pressure to account for altitude using the equation for ``standard atmospheric'' pressure on p 6.1 of the ASHRAE 1997 HOF (SI edition) to initialize the air systems being simulated. +The exhaust air flow rate through the ERV unit in cubic meters per second at standard temperature and pressure (dry air at 20\si{\degreeCelsius} drybulb). The program uses local barometric pressure to account for altitude using the equation for ``standard atmospheric'' pressure on p 6.1 of the ASHRAE 1997 HOF (SI edition) to initialize the air systems being simulated. p = 101325*(1-2.25577E-05*Z)**5.2559 @@ -3894,13 +3922,13 @@ \subsection{ZoneHVAC:TerminalUnit:VariableRefrigerantFlow}\label{zonehvactermina \begin{callout} Note: The terminal unit may be used in the air loop and/or outdoor air system, however, at this time only constant flow (or limited variation within the limits allowed for DX coils) through the unit is allowed. Using a wide range of outdoor air flow rates will cause the DX coil model to fail. For example, if the minimum outdoor air flow rate is allowed to fall near 0, the DX coil model will calculate very low, even very negative, coil outlet temperatures. This can cause psychrometric warnings to occur and cause the simulation to end prematurely. -\end{callout} +\end{callout} For zone equipment the terminal units are connected to a zone using the inlet and exhaust node names specified in a \hyperref[zonehvacequipmentconnections]{ZoneHVAC:EquipmentConnections} object. The zone exhaust node has the same name as the terminal unit air inlet node. The zone inlet node has the same name as the terminal unit air outlet node. The zone terminal unit is also listed in a zone's equipment list and will typically be the first equipment operating for both cooling and heating (i.e., Sequence = 1 in the \hyperref[zonehvacequipmentlist]{ZoneHVAC:EquipmentList}). Other ZoneHVAC equipment may be used in the same zone and should be sequenced to operate after the zone terminal units (i.e., sequence = 2 or higher). For air loop equipment and outdoor air system equipment the VRF terminal unit inlet and outlet nodes define the location of the system in the air loop and outdoor air system. The node names must define the path of the air stream in order from the beginning of the air loop or outdoor air system to the outlet of that system. -This VRF terminal unit can be controlled based on a load or set point. When the system is used as zone equipment load control is always used. When the VRF terminal unit is used in an air loop and the control zone name or thermostat location is specified, the system is controlled based on zone load. If the control zone name or thermostat location is not specified the VRF terminal unit will be controlled based on termninal unit or coil outlet node set point temperature. When set point based control is used the node temperature set points may be placed at the outlet of the terminal unit or at individual coil outlet nodes. If the VRF terminal unit is used in an air loop's outdoor air system, control is always based on a termninal unit or coil outlet node temperature set point. +This VRF terminal unit can be controlled based on a load or set point. When the system is used as zone equipment load control is always used. When the VRF terminal unit is used in an air loop and the control zone name or thermostat location is specified, the system is controlled based on zone load. If the control zone name or thermostat location is not specified the VRF terminal unit will be controlled based on termninal unit or coil outlet node set point temperature. When set point based control is used the node temperature set points may be placed at the outlet of the terminal unit or at individual coil outlet nodes. If the VRF terminal unit is used in an air loop's outdoor air system, control is always based on a termninal unit or coil outlet node temperature set point. The terminal units operate to satisfy a heating or cooling load in a zone based on a zone thermostat temperature set point. A direct-expansion (DX) cooling and/or DX heating coil is specified depending on the operating mode required. Both a DX cooling and DX heating coil will typically be installed in the terminal unit, however only one may be used if desired. An optional supplemental heating coil can also be added to the terminal unit to provide additional heating when the main DX heating coil could not meet the entire heating load of a zone during cold outdoor conditions. The Supplemental Heating Coil Object Type must be \hyperref[coilheatingelectric]{Coil:Heating:Electric}, \hyperref[coilheatinggas-000]{Coil:Heating:Fuel}, \hyperref[coilheatingwater]{Coil:Heating:Water}, or \hyperref[coilheatingsteam]{Coil:Heating:Steam}. Outdoor ventilation air is modeled with the use of an optional outside air mixer object. Outside air may be provided to the zone only when the coil is operating or can be supplied continuously even when the coil is not operating. @@ -4034,7 +4062,7 @@ \subsubsection{Inputs}\label{inputs-14-018} \paragraph{Field: Maximum Outdoor Dry-Bulb Temperature for Supplemental Heater Operation}\label{field-maximum-outdoor-dry-bulb-temperature-for-supplemental-heater-operation-2-000} -This numeric field defines the maximum outdoor dry-bulb temperature in degrees Celsius for this VRF terminal unit supplemental heating coil operation. The supplemental heater will not operate when the outdoor dry-bulb temperature is above this value. The maximum value must be less than or equal to 21°C. If this field is left blank, the default value of 21°C will be used. +This numeric field defines the maximum outdoor dry-bulb temperature in degrees Celsius for this VRF terminal unit supplemental heating coil operation. The supplemental heater will not operate when the outdoor dry-bulb temperature is above this value. The maximum value must be less than or equal to 21\si{\degreeCelsius}. If this field is left blank, the default value of 21\si{\degreeCelsius} will be used. \paragraph{Field: Controlling Zone or Thermostat Location}\label{controlling-zone-or-thermostat-location-2-110} @@ -4250,7 +4278,7 @@ \subsubsection{Inputs} This optional alpha input field specifies the name of an HVAC system node which can extract air from the zone to balance the air supplied to the zone by the unit. This node name would match the name of a zone exhaust air node. \paragraph{Field: System Maximum Supply Air Volume Flow Rate} -This numeric input field specifies the maximum standard density supply air volume flow rate among all operating modes. The field allows custom resizing of the hybrid unit. The values specified in each \hyperref[tablelookup]{Table:Lookup} object associated with a hybrid unit represent performance data for a specific product of a particular size, but the value output from each \hyperref[tablelookup]{Table:Lookup} object is augmented by a normalization reference (Ref: Group - Performance Tables \hyperref[tablelookup]{Table:Lookup}). The normalization reference specified for all \hyperref[tablelookup]{Table:Lookup} objects associated with a hybrid unit should be the maximum supply air mass flow rate for the real hybrid unit that was used to create the performance data included in each table object. The value in this field is used to rescale the normalized values output from tables for extensive dependent variables. If the standard density supply air volume flow rate input to this field is equivalent to the system maximum supply air mass flow rate used as the normalization reference – given appropriate unit conversions – then the resulting output from the model will exactly match the original performance data specified in each table. If the value in this field is larger or smaller, the values for extensive dependent variables will be scaled proportionally. The values of intensive dependent variables are rescaled by the normalization reference value, so will always match the original performance data specified in each table object. The value in this field should be specified as standard density volume flow rate. Standard density in EnergyPlus corresponds to dry air at 20ºC drybulb, and 101,325 Pa. +This numeric input field specifies the maximum standard density supply air volume flow rate among all operating modes. The field allows custom resizing of the hybrid unit. The values specified in each \hyperref[tablelookup]{Table:Lookup} object associated with a hybrid unit represent performance data for a specific product of a particular size, but the value output from each \hyperref[tablelookup]{Table:Lookup} object is augmented by a normalization reference (Ref: Group - Performance Tables \hyperref[tablelookup]{Table:Lookup}). The normalization reference specified for all \hyperref[tablelookup]{Table:Lookup} objects associated with a hybrid unit should be the maximum supply air mass flow rate for the real hybrid unit that was used to create the performance data included in each table object. The value in this field is used to rescale the normalized values output from tables for extensive dependent variables. If the standard density supply air volume flow rate input to this field is equivalent to the system maximum supply air mass flow rate used as the normalization reference – given appropriate unit conversions – then the resulting output from the model will exactly match the original performance data specified in each table. If the value in this field is larger or smaller, the values for extensive dependent variables will be scaled proportionally. The values of intensive dependent variables are rescaled by the normalization reference value, so will always match the original performance data specified in each table object. The value in this field should be specified as standard density volume flow rate. Standard density in EnergyPlus corresponds to dry air at 20\si{\degreeCelsius} drybulb, and 101,325 Pa. \paragraph{Field: External Static Pressure at System Maximum Supply Air Flow Rate} This optional numeric input field specifies the external static pressure at the system maximum supply air flow rate specified in the previous field. Fan affinity laws are used to scale supply fan power from the scenario used to create the performance data included in each \hyperref[tablelookup]{Table:Lookup} object, to a scenario that corresponds to the value specified in this field. The result is also used to adjust the system electric power accordingly. If this field is blank, the supply fan power is not scaled from the values specified in lookup tables. @@ -4560,17 +4588,17 @@ \subsubsection{Outputs} \paragraph{Zone Hybrid Unitary HVAC Predicted Moisture Load to Humidistat Setpoint Moisture Transfer Rate [kgWater/s]} This output reports the predicted moisture transfer rate required to meet the current zone humidistat setpoint. A positive value indicates a humidification load, a negative value indicates a dehumidification load. For a dual setpoint humidistat, the value is zero when the controlled zone’s relative humidity is between the defined humidifying and dehumidifying setpoints. See \hyperref[zonecontrolhumidistat]{ZoneControl:Humidistat} for further information. This value is used as a soft inequality constraint in the constrained optimization problem that determines system settings in each time step. The output is the average over the reporting period. -\paragraph{Zone Hybrid Unitary HVAC Supply Air Temperature [C]} -This output reports the supply air temperature. For each timestep the value is calculated as a supply air mass weighted average of the supply air temperature for each of the settings selected for the time step. For example, if the system operates for half of the timestep with supply air mass flow rate of 1 kg/s and supply air temperature of 16 °C, and for half of the timestep at 2 kg/s and 10 °C, the supply air temperature calculated for the time step would be 12 °C. The output is the average over the reporting period. +\paragraph{Zone Hybrid Unitary HVAC Supply Air Temperature [\si{\degreeCelsius}]} +This output reports the supply air temperature. For each timestep the value is calculated as a supply air mass weighted average of the supply air temperature for each of the settings selected for the time step. For example, if the system operates for half of the timestep with supply air mass flow rate of 1 kg/s and supply air temperature of 16\si{\degreeCelsius}, and for half of the timestep at 2 kg/s and 10\si{\degreeCelsius}, the supply air temperature calculated for the time step would be 12 \si{\degreeCelsius}. The output is the average over the reporting period. -\paragraph{Zone Hybrid Unitary HVAC Return Air Temperature [C]} +\paragraph{Zone Hybrid Unitary HVAC Return Air Temperature [\si{\degreeCelsius}]} This output reports the return air temperature. The return air temperature is inherited from the associated zone outlet node in each timestep. The output is the average over the reporting period. -\paragraph{Zone Hybrid Unitary HVAC Outdoor Air Temperature [C]} +\paragraph{Zone Hybrid Unitary HVAC Outdoor Air Temperature [\si{\degreeCelsius}]} This output reports the outdoor air temperature. The outdoor air temperature is inherited from the associated outdoor air node in each timestep. The output is the average over the reporting period. \paragraph{Zone Hybrid Unitary HVAC Supply Air Humidity Ratio [kgWater/kgDryAir]} -This output reports the supply air humidity ratio. For each timestep the value is calculated as a supply air mass weighted average of the supply air humidity ratio for each of the settings selected for the time step. For example, if the system operates for half of the timestep with supply air mass flow rate of 1 kg/s and supply air humidity ratio of 0.016 kg/kg, and for half of the timestep at 2 kg/s and 0.010 kg/kg, the supply air humidity ratio calculated for the time step would be 0.012 °C. The output is the average over the reporting period. +This output reports the supply air humidity ratio. For each timestep the value is calculated as a supply air mass weighted average of the supply air humidity ratio for each of the settings selected for the time step. For example, if the system operates for half of the timestep with supply air mass flow rate of 1 kg/s and supply air humidity ratio of 0.016 kgWater/kgDryAir, and for half of the timestep at 2 kg/s and 0.010 kgWater/kgDryAir, the supply air humidity ratio calculated for the time step would be 0.012 kgWater/kgDryAir. The output is the average over the reporting period. \paragraph{Zone Hybrid Unitary HVAC Return Air Humidity Ratio [kgWater/kgDryAir]} This output reports the return air humidity ratio. The return air humidity ratio is inherited from the associated zone outlet node in each timestep. The output is the average over the reporting period. @@ -4591,10 +4619,10 @@ \subsubsection{Outputs} This output reports the supply air mass flow rate. For each timestep the value is calculated as a time weighted average of the supply air mass flow rate for each of the settings selected for the time step. The output is the average over the reporting period. \paragraph{Zone Hybrid Unitary HVAC Supply Air Standard Density Volume Flow Rate [m3/s]} -This output reports the supply air flow as a standard density volume flow rate. Standard density in EnergyPlus corresponds to dry air at 20ºC drybulb, and 101,325 Pa. The output is the average over the reporting period. +This output reports the supply air flow as a standard density volume flow rate. Standard density in EnergyPlus corresponds to dry air at 20\si{\degreeCelsius} drybulb, and 101,325 Pa. The output is the average over the reporting period. \paragraph{Zone Hybrid Unitary HVAC Ventilation Air Standard Density Volume Flow Rate [m3/s]} -This output reports the outdoor air (ventilation) flow as a standard density volume flow rate. Standard density in EnergyPlus corresponds to dry air at 20ºC drybulb, and 101,325 Pa. The output is the average over the reporting period. +This output reports the outdoor air (ventilation) flow as a standard density volume flow rate. Standard density in EnergyPlus corresponds to dry air at 20\si{\degreeCelsius} drybulb, and 101,325 Pa. The output is the average over the reporting period. \paragraph{Zone Hybrid Unitary HVAC Electricity Rate [W]} This output reports the electric power input to the system. For each timestep the value is calculated as a time weighted average of the electric power for each of the settings selected for the time step. The output is the average over the reporting period. diff --git a/src/EnergyPlus/PurchasedAirManager.cc b/src/EnergyPlus/PurchasedAirManager.cc index 746701dfd5b..764274640b5 100644 --- a/src/EnergyPlus/PurchasedAirManager.cc +++ b/src/EnergyPlus/PurchasedAirManager.cc @@ -84,1672 +84,1531 @@ namespace EnergyPlus::PurchasedAirManager { - // Module containing data and routines dealing with Ideal Loads Air System (formerly PURCHASED AIR). - - // MODULE INFORMATION: +// Module containing data and routines dealing with Ideal Loads Air System (formerly PURCHASED AIR). + +// MODULE INFORMATION: +// AUTHOR Russ Taylor +// DATE WRITTEN May 1997 +// MODIFIED Fred Buhl Dec 1999 +// B. Griffith Dec 2006. added OA lookup function, moved getinputflag up to Module +// M. Witte June 2011, add new features including DCV, economizer, dehumidification and humidification +// NOTE: MJW Sep 13, 2011: Still need to review checks for negative loads and impossible supply temps??? +// There are no Deallocate statements in here - should there be? +// RE-ENGINEERED na + +// PURPOSE OF THIS MODULE: +// To encapsulate the data and algorithms required to simulate the +// Zone Ideal Loads Air System component. This component supplies hot or cold air +// at a fixed or variable temperature to a zone to meet the zone load. +// With the June 2011 enhancements it will also supply outdoor air with optional demand-controlled ventilation +// and economizer controls, plus new options for controlling zone humidity. + +// METHODOLOGY EMPLOYED: +// The user can choose via input the max/min hot and cold supply air +// temperature and humidity ratio. The air mass flow rate is chosen +// to meet the (remaining) zone load or based on the outdoor air flow requirement. +// If the outdoor air flow sets the flow rate, the supply air temperature and +// humidity ratio are adjusted to meet the zone load. + +// Using/Aliasing +using namespace DataHVACGlobals; +using DataHeatBalFanSys::ZoneAirHumRat; +using DataHeatBalFanSys::ZoneThermostatSetPointHi; +using DataHeatBalFanSys::ZoneThermostatSetPointLo; +using namespace ScheduleManager; +using Psychrometrics::PsyCpAirFnW; +using Psychrometrics::PsyHFnTdbW; +using Psychrometrics::PsyRhoAirFnPbTdbW; +using Psychrometrics::PsyTdbFnHW; +using Psychrometrics::PsyTsatFnHPb; +using Psychrometrics::PsyWFnTdbH; +using Psychrometrics::PsyWFnTdbRhPb; + +// Delta humidity ratio limit, 0.00025 equals delta between 45F dewpoint and 46F dewpoint +// used to prevent dividing by near zero +Real64 constexpr SmallDeltaHumRat(0.00025); + +void SimPurchasedAir(EnergyPlusData &state, + std::string const &PurchAirName, + Real64 &SysOutputProvided, + Real64 &MoistOutputProvided, // Moisture output provided (kg/s), dehumidification = negative + bool const FirstHVACIteration, + int const ControlledZoneNum, + int const ActualZoneNum, + int &CompIndex) +{ + + // SUBROUTINE INFORMATION: // AUTHOR Russ Taylor // DATE WRITTEN May 1997 - // MODIFIED Fred Buhl Dec 1999 - // B. Griffith Dec 2006. added OA lookup function, moved getinputflag up to Module - // M. Witte June 2011, add new features including DCV, economizer, dehumidification and humidification - // NOTE: MJW Sep 13, 2011: Still need to review checks for negative loads and impossible supply temps??? - // There are no Deallocate statements in here - should there be? + // MODIFIED Don Shirey, Aug 2009 (LatOutputProvided - now MoistOutputProvided) // RE-ENGINEERED na - // PURPOSE OF THIS MODULE: - // To encapsulate the data and algorithms required to simulate the - // Zone Ideal Loads Air System component. This component supplies hot or cold air - // at a fixed or variable temperature to a zone to meet the zone load. - // With the June 2011 enhancements it will also supply outdoor air with optional demand-controlled ventilation - // and economizer controls, plus new options for controlling zone humidity. + // PURPOSE OF THIS SUBROUTINE: + // This subroutine manages Purchased Air component simulation. + // It is called from SimZoneEquipment in the ZoneEquipmentManager + // at the system time step. - // METHODOLOGY EMPLOYED: - // The user can choose via input the max/min hot and cold supply air - // temperature and humidity ratio. The air mass flow rate is chosen - // to meet the (remaining) zone load or based on the outdoor air flow requirement. - // If the outdoor air flow sets the flow rate, the supply air temperature and - // humidity ratio are adjusted to meet the zone load. + int PurchAirNum; - // Using/Aliasing - using namespace DataHVACGlobals; - using DataHeatBalFanSys::ZoneAirHumRat; - using DataHeatBalFanSys::ZoneThermostatSetPointHi; - using DataHeatBalFanSys::ZoneThermostatSetPointLo; - using namespace ScheduleManager; - using Psychrometrics::PsyCpAirFnW; - using Psychrometrics::PsyHFnTdbW; - using Psychrometrics::PsyRhoAirFnPbTdbW; - using Psychrometrics::PsyTdbFnHW; - using Psychrometrics::PsyTsatFnHPb; - using Psychrometrics::PsyWFnTdbH; - using Psychrometrics::PsyWFnTdbRhPb; - - // Delta humidity ratio limit, 0.00025 equals delta between 45F dewpoint and 46F dewpoint - // used to prevent dividing by near zero - Real64 constexpr SmallDeltaHumRat(0.00025); - - void SimPurchasedAir(EnergyPlusData &state, - std::string const &PurchAirName, - Real64 &SysOutputProvided, - Real64 &MoistOutputProvided, // Moisture output provided (kg/s), dehumidification = negative - bool const FirstHVACIteration, - int const ControlledZoneNum, - int const ActualZoneNum, - int &CompIndex) - { - - // SUBROUTINE INFORMATION: - // AUTHOR Russ Taylor - // DATE WRITTEN May 1997 - // MODIFIED Don Shirey, Aug 2009 (LatOutputProvided - now MoistOutputProvided) - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // This subroutine manages Purchased Air component simulation. - // It is called from SimZoneEquipment in the ZoneEquipmentManager - // at the system time step. - - int PurchAirNum; - - if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { - GetPurchasedAir(state); - state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; - } + if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { + GetPurchasedAir(state); + state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; + } - // Find the correct PurchasedAir Equipment - if (CompIndex == 0) { - PurchAirNum = UtilityRoutines::FindItemInList(PurchAirName, state.dataPurchasedAirMgr->PurchAir); - if (PurchAirNum == 0) { - ShowFatalError(state, "SimPurchasedAir: Unit not found=" + PurchAirName); - } - CompIndex = PurchAirNum; - } else { - PurchAirNum = CompIndex; - if (PurchAirNum > state.dataPurchasedAirMgr->NumPurchAir || PurchAirNum < 1) { + // Find the correct PurchasedAir Equipment + if (CompIndex == 0) { + PurchAirNum = UtilityRoutines::FindItemInList(PurchAirName, state.dataPurchasedAirMgr->PurchAir); + if (PurchAirNum == 0) { + ShowFatalError(state, "SimPurchasedAir: Unit not found=" + PurchAirName); + } + CompIndex = PurchAirNum; + } else { + PurchAirNum = CompIndex; + if (PurchAirNum > state.dataPurchasedAirMgr->NumPurchAir || PurchAirNum < 1) { + ShowFatalError(state, + format("SimPurchasedAir: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}", + PurchAirNum, + state.dataPurchasedAirMgr->NumPurchAir, + PurchAirName)); + } + if (state.dataPurchasedAirMgr->CheckEquipName(PurchAirNum)) { + if (PurchAirName != state.dataPurchasedAirMgr->PurchAir(PurchAirNum).Name) { ShowFatalError(state, - format("SimPurchasedAir: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}", + format("SimPurchasedAir: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}", PurchAirNum, - state.dataPurchasedAirMgr->NumPurchAir, - PurchAirName)); - } - if (state.dataPurchasedAirMgr->CheckEquipName(PurchAirNum)) { - if (PurchAirName != state.dataPurchasedAirMgr->PurchAir(PurchAirNum).Name) { - ShowFatalError(state, - format("SimPurchasedAir: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}", - PurchAirNum, - PurchAirName, - state.dataPurchasedAirMgr->PurchAir(PurchAirNum).Name)); - } - state.dataPurchasedAirMgr->CheckEquipName(PurchAirNum) = false; + PurchAirName, + state.dataPurchasedAirMgr->PurchAir(PurchAirNum).Name)); } + state.dataPurchasedAirMgr->CheckEquipName(PurchAirNum) = false; } + } - InitPurchasedAir(state, PurchAirNum, FirstHVACIteration, ControlledZoneNum, ActualZoneNum); + InitPurchasedAir(state, PurchAirNum, FirstHVACIteration, ControlledZoneNum, ActualZoneNum); - CalcPurchAirLoads(state, PurchAirNum, SysOutputProvided, MoistOutputProvided, ControlledZoneNum, ActualZoneNum); + CalcPurchAirLoads(state, PurchAirNum, SysOutputProvided, MoistOutputProvided, ControlledZoneNum, ActualZoneNum); - UpdatePurchasedAir(state, PurchAirNum, FirstHVACIteration); + UpdatePurchasedAir(state, PurchAirNum, FirstHVACIteration); - ReportPurchasedAir(state, PurchAirNum); - } + ReportPurchasedAir(state, PurchAirNum); +} + +void GetPurchasedAir(EnergyPlusData &state) +{ - void GetPurchasedAir(EnergyPlusData &state) - { - - // SUBROUTINE INFORMATION: - // AUTHOR Russ Taylor - // DATE WRITTEN June 1997 - // MODIFIED M. Witte, June 2011, add new features including DCV, economizer, dehumidification - // and humidification controls - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // Get the input data for the Purchased Air objects. - // Set up output variables. - - // Using/Aliasing - using NodeInputManager::CheckUniqueNodes; - using NodeInputManager::EndUniqueNodeCheck; - using NodeInputManager::GetOnlySingleNode; - using NodeInputManager::InitUniqueNodeCheck; - using OutAirNodeManager::CheckAndAddAirNodeNumber; - using namespace DataLoopNode; - using namespace DataIPShortCuts; - using DataSizing::OARequirements; // to find DesignSpecification:OutdoorAir pointer - using DataSizing::ZoneHVACSizing; - using ZonePlenum::GetReturnPlenumIndex; - - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - int PurchAirNum; - int NumAlphas; - int NumNums; - int IOStat; - int CtrlZone; // zone index - int NodeNum; // node index - static std::string const RoutineName("GetPurchasedAir: "); // include trailing blank space - bool ErrorsFound(false); // If errors detected in input - bool IsOANodeListed; // Flag for OA node name listed in OutdoorAir:Node or Nodelist - bool UniqueNodeError; // Flag for non-unique node error(s) - - cCurrentModuleObject = "ZoneHVAC:IdealLoadsAirSystem"; - - auto & PurchAir(state.dataPurchasedAirMgr->PurchAir); - - state.dataPurchasedAirMgr->NumPurchAir = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject); - - PurchAir.allocate(state.dataPurchasedAirMgr->NumPurchAir); - state.dataPurchasedAirMgr->CheckEquipName.allocate(state.dataPurchasedAirMgr->NumPurchAir); - state.dataPurchasedAirMgr->PurchAirNumericFields.allocate(state.dataPurchasedAirMgr->NumPurchAir); - state.dataPurchasedAirMgr->CheckEquipName = true; - - if (state.dataPurchasedAirMgr->NumPurchAir > 0) { - InitUniqueNodeCheck(state, cCurrentModuleObject); - for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) { - PurchAir(PurchAirNum).cObjectName = cCurrentModuleObject; - - inputProcessor->getObjectItem(state, - cCurrentModuleObject, - PurchAirNum, - cAlphaArgs, - NumAlphas, - rNumericArgs, - NumNums, - IOStat, - lNumericFieldBlanks, - lAlphaFieldBlanks, - cAlphaFieldNames, - cNumericFieldNames); - - state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames.allocate(NumNums); - state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames = ""; - state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames = cNumericFieldNames; - UtilityRoutines::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound); - - PurchAir(PurchAirNum).Name = cAlphaArgs(1); - // get optional availability schedule - PurchAir(PurchAirNum).AvailSched = cAlphaArgs(2); - if (lAlphaFieldBlanks(2)) { - PurchAir(PurchAirNum).AvailSchedPtr = DataGlobalConstants::ScheduleAlwaysOn; + // SUBROUTINE INFORMATION: + // AUTHOR Russ Taylor + // DATE WRITTEN June 1997 + // MODIFIED M. Witte, June 2011, add new features including DCV, economizer, dehumidification + // and humidification controls + // RE-ENGINEERED na + + // PURPOSE OF THIS SUBROUTINE: + // Get the input data for the Purchased Air objects. + // Set up output variables. + + // Using/Aliasing + using NodeInputManager::CheckUniqueNodes; + using NodeInputManager::EndUniqueNodeCheck; + using NodeInputManager::GetOnlySingleNode; + using NodeInputManager::InitUniqueNodeCheck; + using OutAirNodeManager::CheckAndAddAirNodeNumber; + using namespace DataLoopNode; + using namespace DataIPShortCuts; + using DataSizing::OARequirements; // to find DesignSpecification:OutdoorAir pointer + using DataSizing::ZoneHVACSizing; + using ZonePlenum::GetReturnPlenumIndex; + + // SUBROUTINE LOCAL VARIABLE DECLARATIONS: + int PurchAirNum; + int NumAlphas; + int NumNums; + int IOStat; + int CtrlZone; // zone index + int NodeNum; // node index + static std::string const RoutineName("GetPurchasedAir: "); // include trailing blank space + bool ErrorsFound(false); // If errors detected in input + bool IsOANodeListed; // Flag for OA node name listed in OutdoorAir:Node or Nodelist + bool UniqueNodeError; // Flag for non-unique node error(s) + + cCurrentModuleObject = "ZoneHVAC:IdealLoadsAirSystem"; + + auto &PurchAir(state.dataPurchasedAirMgr->PurchAir); + + state.dataPurchasedAirMgr->NumPurchAir = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject); + + PurchAir.allocate(state.dataPurchasedAirMgr->NumPurchAir); + state.dataPurchasedAirMgr->CheckEquipName.allocate(state.dataPurchasedAirMgr->NumPurchAir); + state.dataPurchasedAirMgr->PurchAirNumericFields.allocate(state.dataPurchasedAirMgr->NumPurchAir); + state.dataPurchasedAirMgr->CheckEquipName = true; + + if (state.dataPurchasedAirMgr->NumPurchAir > 0) { + InitUniqueNodeCheck(state, cCurrentModuleObject); + for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) { + PurchAir(PurchAirNum).cObjectName = cCurrentModuleObject; + + inputProcessor->getObjectItem(state, + cCurrentModuleObject, + PurchAirNum, + cAlphaArgs, + NumAlphas, + rNumericArgs, + NumNums, + IOStat, + lNumericFieldBlanks, + lAlphaFieldBlanks, + cAlphaFieldNames, + cNumericFieldNames); + + state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames.allocate(NumNums); + state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames = ""; + state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames = cNumericFieldNames; + UtilityRoutines::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound); + + PurchAir(PurchAirNum).Name = cAlphaArgs(1); + // get optional availability schedule + PurchAir(PurchAirNum).AvailSched = cAlphaArgs(2); + if (lAlphaFieldBlanks(2)) { + PurchAir(PurchAirNum).AvailSchedPtr = DataGlobalConstants::ScheduleAlwaysOn; + } else { + PurchAir(PurchAirNum).AvailSchedPtr = GetScheduleIndex(state, cAlphaArgs(2)); + if (PurchAir(PurchAirNum).AvailSchedPtr == 0) { + ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); + ShowContinueError(state, "Invalid-not found " + cAlphaFieldNames(2) + "=\"" + cAlphaArgs(2) + "\"."); + ErrorsFound = true; + } + } + // Purchased air supply air node is an outlet node + PurchAir(PurchAirNum).ZoneSupplyAirNodeNum = GetOnlySingleNode(state, + cAlphaArgs(3), + ErrorsFound, + cCurrentModuleObject, + cAlphaArgs(1), + NodeType_Air, + NodeConnectionType_Outlet, + 1, + ObjectIsNotParent); + UniqueNodeError = false; + CheckUniqueNodes(state, cAlphaFieldNames(3), "NodeName", UniqueNodeError, cAlphaArgs(3), _, cAlphaArgs(1)); + if (UniqueNodeError) ErrorsFound = true; + // If new (optional) exhaust air node name is present, then register it as inlet + if (!lAlphaFieldBlanks(4)) { + if (lAlphaFieldBlanks(5)) { + PurchAir(PurchAirNum).ZoneExhaustAirNodeNum = GetOnlySingleNode(state, + cAlphaArgs(4), + ErrorsFound, + cCurrentModuleObject, + cAlphaArgs(1), + NodeType_Air, + NodeConnectionType_Inlet, + 1, + ObjectIsNotParent); } else { - PurchAir(PurchAirNum).AvailSchedPtr = GetScheduleIndex(state, cAlphaArgs(2)); - if (PurchAir(PurchAirNum).AvailSchedPtr == 0) { - ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, "Invalid-not found " + cAlphaFieldNames(2) + "=\"" + cAlphaArgs(2) + "\"."); - ErrorsFound = true; - } + PurchAir(PurchAirNum).ZoneExhaustAirNodeNum = GetOnlySingleNode(state, + cAlphaArgs(4), + ErrorsFound, + cCurrentModuleObject, + cAlphaArgs(1), + NodeType_Air, + NodeConnectionType_Outlet, + 1, + ObjectIsNotParent); } - // Purchased air supply air node is an outlet node - PurchAir(PurchAirNum).ZoneSupplyAirNodeNum = GetOnlySingleNode(state, - cAlphaArgs(3), ErrorsFound, cCurrentModuleObject, cAlphaArgs(1), NodeType_Air, NodeConnectionType_Outlet, 1, ObjectIsNotParent); UniqueNodeError = false; - CheckUniqueNodes(state, cAlphaFieldNames(3), "NodeName", UniqueNodeError, cAlphaArgs(3), _, cAlphaArgs(1)); + CheckUniqueNodes(state, cAlphaFieldNames(4), "NodeName", UniqueNodeError, cAlphaArgs(4), _, cAlphaArgs(1)); if (UniqueNodeError) ErrorsFound = true; - // If new (optional) exhaust air node name is present, then register it as inlet - if (!lAlphaFieldBlanks(4)) { - if (lAlphaFieldBlanks(5)) { - PurchAir(PurchAirNum).ZoneExhaustAirNodeNum = GetOnlySingleNode(state, cAlphaArgs(4), - ErrorsFound, - cCurrentModuleObject, - cAlphaArgs(1), - NodeType_Air, - NodeConnectionType_Inlet, - 1, - ObjectIsNotParent); - } else { - PurchAir(PurchAirNum).ZoneExhaustAirNodeNum = GetOnlySingleNode(state, cAlphaArgs(4), - ErrorsFound, - cCurrentModuleObject, - cAlphaArgs(1), - NodeType_Air, - NodeConnectionType_Outlet, - 1, - ObjectIsNotParent); - } - UniqueNodeError = false; - CheckUniqueNodes(state, cAlphaFieldNames(4), "NodeName", UniqueNodeError, cAlphaArgs(4), _, cAlphaArgs(1)); - if (UniqueNodeError) ErrorsFound = true; + } + if (!lAlphaFieldBlanks(5)) { + PurchAir(PurchAirNum).PlenumExhaustAirNodeNum = GetOnlySingleNode(state, + cAlphaArgs(5), + ErrorsFound, + cCurrentModuleObject, + cAlphaArgs(1), + NodeType_Air, + NodeConnectionType_Inlet, + 1, + ObjectIsNotParent); + } + PurchAir(PurchAirNum).MaxHeatSuppAirTemp = rNumericArgs(1); + PurchAir(PurchAirNum).MinCoolSuppAirTemp = rNumericArgs(2); + PurchAir(PurchAirNum).MaxHeatSuppAirHumRat = rNumericArgs(3); + PurchAir(PurchAirNum).MinCoolSuppAirHumRat = rNumericArgs(4); + + if (UtilityRoutines::SameString(cAlphaArgs(6), "NoLimit")) { + PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit; + } else if (UtilityRoutines::SameString(cAlphaArgs(6), "LimitFlowRate")) { + if (lNumericFieldBlanks(5)) { + PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit; + } else { + PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRate; } - if (!lAlphaFieldBlanks(5)) { - PurchAir(PurchAirNum).PlenumExhaustAirNodeNum = GetOnlySingleNode(state, cAlphaArgs(5), - ErrorsFound, - cCurrentModuleObject, - cAlphaArgs(1), - NodeType_Air, - NodeConnectionType_Inlet, - 1, - ObjectIsNotParent); + } else if (UtilityRoutines::SameString(cAlphaArgs(6), "LimitCapacity")) { + if (lNumericFieldBlanks(6)) { + PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit; + } else { + PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitCapacity; } - PurchAir(PurchAirNum).MaxHeatSuppAirTemp = rNumericArgs(1); - PurchAir(PurchAirNum).MinCoolSuppAirTemp = rNumericArgs(2); - PurchAir(PurchAirNum).MaxHeatSuppAirHumRat = rNumericArgs(3); - PurchAir(PurchAirNum).MinCoolSuppAirHumRat = rNumericArgs(4); - - if (UtilityRoutines::SameString(cAlphaArgs(6), "NoLimit")) { + } else if (UtilityRoutines::SameString(cAlphaArgs(6), "LimitFlowRateAndCapacity")) { + if (lNumericFieldBlanks(5) && lNumericFieldBlanks(6)) { PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit; - } else if (UtilityRoutines::SameString(cAlphaArgs(6), "LimitFlowRate")) { - if (lNumericFieldBlanks(5)) { - PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit; - } else { - PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRate; - } - } else if (UtilityRoutines::SameString(cAlphaArgs(6), "LimitCapacity")) { - if (lNumericFieldBlanks(6)) { - PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit; - } else { - PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitCapacity; - } - } else if (UtilityRoutines::SameString(cAlphaArgs(6), "LimitFlowRateAndCapacity")) { - if (lNumericFieldBlanks(5) && lNumericFieldBlanks(6)) { - PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit; - } else if (lNumericFieldBlanks(5)) { - PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitCapacity; - } else if (lNumericFieldBlanks(6)) { - PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRate; - } else { - PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRateAndCapacity; - } + } else if (lNumericFieldBlanks(5)) { + PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitCapacity; + } else if (lNumericFieldBlanks(6)) { + PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRate; } else { - ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(6) + "=\"" + cAlphaArgs(6) + "\"."); - ShowContinueError(state, "Valid entries are NoLimit, LimitFlowRate, LimitCapacity, or LimitFlowRateAndCapacity"); - ErrorsFound = true; + PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRateAndCapacity; } - PurchAir(PurchAirNum).MaxHeatVolFlowRate = rNumericArgs(5); - PurchAir(PurchAirNum).MaxHeatSensCap = rNumericArgs(6); + } else { + ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); + ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(6) + "=\"" + cAlphaArgs(6) + "\"."); + ShowContinueError(state, "Valid entries are NoLimit, LimitFlowRate, LimitCapacity, or LimitFlowRateAndCapacity"); + ErrorsFound = true; + } + PurchAir(PurchAirNum).MaxHeatVolFlowRate = rNumericArgs(5); + PurchAir(PurchAirNum).MaxHeatSensCap = rNumericArgs(6); - if (UtilityRoutines::SameString(cAlphaArgs(7), "NoLimit")) { + if (UtilityRoutines::SameString(cAlphaArgs(7), "NoLimit")) { + PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit; + } else if (UtilityRoutines::SameString(cAlphaArgs(7), "LimitFlowRate")) { + if (lNumericFieldBlanks(7)) { PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit; - } else if (UtilityRoutines::SameString(cAlphaArgs(7), "LimitFlowRate")) { - if (lNumericFieldBlanks(7)) { - PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit; - } else { - PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRate; - } - } else if (UtilityRoutines::SameString(cAlphaArgs(7), "LimitCapacity")) { - if (lNumericFieldBlanks(8)) { - PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit; - } else { - PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitCapacity; - } - } else if (UtilityRoutines::SameString(cAlphaArgs(7), "LimitFlowRateAndCapacity")) { - if (lNumericFieldBlanks(7) && lNumericFieldBlanks(8)) { - PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit; - } else if (lNumericFieldBlanks(7)) { - PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitCapacity; - } else if (lNumericFieldBlanks(8)) { - PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRate; - } else { - PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRateAndCapacity; - } } else { - ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(7) + "=\"" + cAlphaArgs(7) + "\"."); - ShowContinueError(state, "Valid entries are NoLimit, LimitFlowRate, LimitCapacity, or LimitFlowRateAndCapacity"); - ErrorsFound = true; + PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRate; } - PurchAir(PurchAirNum).MaxCoolVolFlowRate = rNumericArgs(7); - PurchAir(PurchAirNum).MaxCoolTotCap = rNumericArgs(8); - - // get optional heating availability schedule - PurchAir(PurchAirNum).HeatSched = cAlphaArgs(8); - if (lAlphaFieldBlanks(8)) { - PurchAir(PurchAirNum).HeatSchedPtr = DataGlobalConstants::ScheduleAlwaysOn; + } else if (UtilityRoutines::SameString(cAlphaArgs(7), "LimitCapacity")) { + if (lNumericFieldBlanks(8)) { + PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit; } else { - PurchAir(PurchAirNum).HeatSchedPtr = GetScheduleIndex(state, cAlphaArgs(8)); - if (PurchAir(PurchAirNum).HeatSchedPtr == 0) { - ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, "Invalid-not found " + cAlphaFieldNames(8) + "=\"" + cAlphaArgs(8) + "\"."); - ErrorsFound = true; - } + PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitCapacity; } - // get optional cooling availability schedule - PurchAir(PurchAirNum).CoolSched = cAlphaArgs(9); - if (lAlphaFieldBlanks(9)) { - PurchAir(PurchAirNum).CoolSchedPtr = DataGlobalConstants::ScheduleAlwaysOn; + } else if (UtilityRoutines::SameString(cAlphaArgs(7), "LimitFlowRateAndCapacity")) { + if (lNumericFieldBlanks(7) && lNumericFieldBlanks(8)) { + PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit; + } else if (lNumericFieldBlanks(7)) { + PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitCapacity; + } else if (lNumericFieldBlanks(8)) { + PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRate; } else { - PurchAir(PurchAirNum).CoolSchedPtr = GetScheduleIndex(state, cAlphaArgs(9)); - if (PurchAir(PurchAirNum).CoolSchedPtr == 0) { - ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, "Invalid-not found " + cAlphaFieldNames(9) + "=\"" + cAlphaArgs(9) + "\"."); - ErrorsFound = true; - } + PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRateAndCapacity; } - // get Dehumidification control type - if (UtilityRoutines::SameString(cAlphaArgs(10), "None")) { - PurchAir(PurchAirNum).DehumidCtrlType = HumControl::None; - } else if (UtilityRoutines::SameString(cAlphaArgs(10), "ConstantSensibleHeatRatio")) { - PurchAir(PurchAirNum).DehumidCtrlType = HumControl::ConstantSensibleHeatRatio; - } else if (UtilityRoutines::SameString(cAlphaArgs(10), "Humidistat")) { - PurchAir(PurchAirNum).DehumidCtrlType = HumControl::Humidistat; - } else if (UtilityRoutines::SameString(cAlphaArgs(10), "ConstantSupplyHumidityRatio")) { - PurchAir(PurchAirNum).DehumidCtrlType = HumControl::ConstantSupplyHumidityRatio; - } else { + } else { + ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); + ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(7) + "=\"" + cAlphaArgs(7) + "\"."); + ShowContinueError(state, "Valid entries are NoLimit, LimitFlowRate, LimitCapacity, or LimitFlowRateAndCapacity"); + ErrorsFound = true; + } + PurchAir(PurchAirNum).MaxCoolVolFlowRate = rNumericArgs(7); + PurchAir(PurchAirNum).MaxCoolTotCap = rNumericArgs(8); + + // get optional heating availability schedule + PurchAir(PurchAirNum).HeatSched = cAlphaArgs(8); + if (lAlphaFieldBlanks(8)) { + PurchAir(PurchAirNum).HeatSchedPtr = DataGlobalConstants::ScheduleAlwaysOn; + } else { + PurchAir(PurchAirNum).HeatSchedPtr = GetScheduleIndex(state, cAlphaArgs(8)); + if (PurchAir(PurchAirNum).HeatSchedPtr == 0) { ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(10) + "=\"" + cAlphaArgs(10) + "\"."); - ShowContinueError(state, "Valid entries are ConstantSensibleHeatRatio, Humidistat, or ConstantSupplyHumidityRatio"); + ShowContinueError(state, "Invalid-not found " + cAlphaFieldNames(8) + "=\"" + cAlphaArgs(8) + "\"."); ErrorsFound = true; } - PurchAir(PurchAirNum).CoolSHR = rNumericArgs(9); - - // get Humidification control type - if (UtilityRoutines::SameString(cAlphaArgs(11), "None")) { - PurchAir(PurchAirNum).HumidCtrlType = HumControl::None; - } else if (UtilityRoutines::SameString(cAlphaArgs(11), "Humidistat")) { - PurchAir(PurchAirNum).HumidCtrlType = HumControl::Humidistat; - } else if (UtilityRoutines::SameString(cAlphaArgs(11), "ConstantSupplyHumidityRatio")) { - PurchAir(PurchAirNum).HumidCtrlType = HumControl::ConstantSupplyHumidityRatio; - } else { + } + // get optional cooling availability schedule + PurchAir(PurchAirNum).CoolSched = cAlphaArgs(9); + if (lAlphaFieldBlanks(9)) { + PurchAir(PurchAirNum).CoolSchedPtr = DataGlobalConstants::ScheduleAlwaysOn; + } else { + PurchAir(PurchAirNum).CoolSchedPtr = GetScheduleIndex(state, cAlphaArgs(9)); + if (PurchAir(PurchAirNum).CoolSchedPtr == 0) { ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(11) + "=\"" + cAlphaArgs(11) + "\"."); - ShowContinueError(state, "Valid entries are None, Humidistat, or ConstantSupplyHumidityRatio"); + ShowContinueError(state, "Invalid-not found " + cAlphaFieldNames(9) + "=\"" + cAlphaArgs(9) + "\"."); ErrorsFound = true; } + } + // get Dehumidification control type + if (UtilityRoutines::SameString(cAlphaArgs(10), "None")) { + PurchAir(PurchAirNum).DehumidCtrlType = HumControl::None; + } else if (UtilityRoutines::SameString(cAlphaArgs(10), "ConstantSensibleHeatRatio")) { + PurchAir(PurchAirNum).DehumidCtrlType = HumControl::ConstantSensibleHeatRatio; + } else if (UtilityRoutines::SameString(cAlphaArgs(10), "Humidistat")) { + PurchAir(PurchAirNum).DehumidCtrlType = HumControl::Humidistat; + } else if (UtilityRoutines::SameString(cAlphaArgs(10), "ConstantSupplyHumidityRatio")) { + PurchAir(PurchAirNum).DehumidCtrlType = HumControl::ConstantSupplyHumidityRatio; + } else { + ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); + ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(10) + "=\"" + cAlphaArgs(10) + "\"."); + ShowContinueError(state, "Valid entries are ConstantSensibleHeatRatio, Humidistat, or ConstantSupplyHumidityRatio"); + ErrorsFound = true; + } + PurchAir(PurchAirNum).CoolSHR = rNumericArgs(9); + + // get Humidification control type + if (UtilityRoutines::SameString(cAlphaArgs(11), "None")) { + PurchAir(PurchAirNum).HumidCtrlType = HumControl::None; + } else if (UtilityRoutines::SameString(cAlphaArgs(11), "Humidistat")) { + PurchAir(PurchAirNum).HumidCtrlType = HumControl::Humidistat; + } else if (UtilityRoutines::SameString(cAlphaArgs(11), "ConstantSupplyHumidityRatio")) { + PurchAir(PurchAirNum).HumidCtrlType = HumControl::ConstantSupplyHumidityRatio; + } else { + ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); + ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(11) + "=\"" + cAlphaArgs(11) + "\"."); + ShowContinueError(state, "Valid entries are None, Humidistat, or ConstantSupplyHumidityRatio"); + ErrorsFound = true; + } - // get Design specification outdoor air object - if (!lAlphaFieldBlanks(12)) { - PurchAir(PurchAirNum).OARequirementsPtr = UtilityRoutines::FindItemInList(cAlphaArgs(12), OARequirements); - if (PurchAir(PurchAirNum).OARequirementsPtr == 0) { - ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, "Invalid-not found" + cAlphaFieldNames(12) + "=\"" + cAlphaArgs(12) + "\"."); - ErrorsFound = true; - } else { - PurchAir(PurchAirNum).OutdoorAir = true; - } + // get Design specification outdoor air object + if (!lAlphaFieldBlanks(12)) { + PurchAir(PurchAirNum).OARequirementsPtr = UtilityRoutines::FindItemInList(cAlphaArgs(12), OARequirements); + if (PurchAir(PurchAirNum).OARequirementsPtr == 0) { + ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); + ShowContinueError(state, "Invalid-not found" + cAlphaFieldNames(12) + "=\"" + cAlphaArgs(12) + "\"."); + ErrorsFound = true; + } else { + PurchAir(PurchAirNum).OutdoorAir = true; } + } - // If outdoor air specified, then get Outdoor air inlet node and other outdoor air inputs - if (PurchAir(PurchAirNum).OutdoorAir) { - if (lAlphaFieldBlanks(13)) { - // If there is outdoor air and outdoor air inlet node is blank, then create one - if (len(cAlphaArgs(1)) < DataGlobalConstants::MaxNameLength - 23) { // protect against long name leading to > 100 chars - cAlphaArgs(13) = cAlphaArgs(1) + " OUTDOOR AIR INLET NODE"; - } else { - cAlphaArgs(13) = cAlphaArgs(1).substr(0, 75) + " OUTDOOR AIR INLET NODE"; - } - if (state.dataGlobal->DisplayExtraWarnings) { - ShowWarningError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " blank field"); - ShowContinueError(state, cAlphaFieldNames(13) + " is blank, but there is outdoor air requested for this system."); - ShowContinueError(state, "Creating node name =" + cAlphaArgs(13)); - } - } - // Register OA node - PurchAir(PurchAirNum).OutdoorAirNodeNum = GetOnlySingleNode(state, cAlphaArgs(13), - ErrorsFound, - cCurrentModuleObject, - cAlphaArgs(1), - NodeType_Air, - NodeConnectionType_Outlet, - 1, - ObjectIsNotParent); - // Check if OA node is initialized in OutdoorAir:Node or OutdoorAir:Nodelist - CheckAndAddAirNodeNumber(state, PurchAir(PurchAirNum).OutdoorAirNodeNum, IsOANodeListed); - if ((!IsOANodeListed) && state.dataGlobal->DisplayExtraWarnings) { - ShowWarningError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " missing data"); - ShowContinueError(state, cAlphaArgs(13) + " does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node."); - ShowContinueError(state, "Adding OutdoorAir:Node=" + cAlphaArgs(13)); - } - UniqueNodeError = false; - CheckUniqueNodes(state, cAlphaFieldNames(13), "NodeName", UniqueNodeError, cAlphaArgs(13), _, cAlphaArgs(1)); - if (UniqueNodeError) ErrorsFound = true; - - // get Demand controlled ventilation type - if (UtilityRoutines::SameString(cAlphaArgs(14), "None")) { - PurchAir(PurchAirNum).DCVType = DCV::NoDCV; - } else if (UtilityRoutines::SameString(cAlphaArgs(14), "OccupancySchedule")) { - PurchAir(PurchAirNum).DCVType = DCV::OccupancySchedule; - } else if (UtilityRoutines::SameString(cAlphaArgs(14), "CO2Setpoint")) { - if (state.dataContaminantBalance->Contaminant.CO2Simulation) { - PurchAir(PurchAirNum).DCVType = DCV::CO2SetPoint; - } else { - PurchAir(PurchAirNum).DCVType = DCV::NoDCV; - ShowWarningError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, cAlphaFieldNames(14) + '=' + cAlphaArgs(14) + " but CO2 simulation is not active."); - ShowContinueError(state, "Resetting " + cAlphaFieldNames(14) + " to NoDCV"); - ShowContinueError(state, "To activate CO2 simulation, use ZoneAirContaminantBalance object and specify \"Carbon Dioxide " - "Concentration\"=\"Yes\"."); - } + // If outdoor air specified, then get Outdoor air inlet node and other outdoor air inputs + if (PurchAir(PurchAirNum).OutdoorAir) { + if (lAlphaFieldBlanks(13)) { + // If there is outdoor air and outdoor air inlet node is blank, then create one + if (len(cAlphaArgs(1)) < DataGlobalConstants::MaxNameLength - 23) { // protect against long name leading to > 100 chars + cAlphaArgs(13) = cAlphaArgs(1) + " OUTDOOR AIR INLET NODE"; } else { - ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(14) + '=' + cAlphaArgs(14)); - ShowContinueError(state, "Valid entries are None, OccupancySchedule, or CO2Setpoint"); - ErrorsFound = true; + cAlphaArgs(13) = cAlphaArgs(1).substr(0, 75) + " OUTDOOR AIR INLET NODE"; } - // get Outdoor air economizer type - if (UtilityRoutines::SameString(cAlphaArgs(15), "NoEconomizer")) { - PurchAir(PurchAirNum).EconomizerType = Econ::NoEconomizer; - } else if (UtilityRoutines::SameString(cAlphaArgs(15), "DifferentialDryBulb")) { - PurchAir(PurchAirNum).EconomizerType = Econ::DifferentialDryBulb; - } else if (UtilityRoutines::SameString(cAlphaArgs(15), "DifferentialEnthalpy")) { - PurchAir(PurchAirNum).EconomizerType = Econ::DifferentialEnthalpy; - } else { - ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(15) + '=' + cAlphaArgs(15)); - ShowContinueError(state, "Valid entries are NoEconomizer, DifferentialDryBulb, or DifferentialEnthalpy"); - ErrorsFound = true; + if (state.dataGlobal->DisplayExtraWarnings) { + ShowWarningError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " blank field"); + ShowContinueError(state, cAlphaFieldNames(13) + " is blank, but there is outdoor air requested for this system."); + ShowContinueError(state, "Creating node name =" + cAlphaArgs(13)); } - // get Outdoor air heat recovery type and effectiveness - if (UtilityRoutines::SameString(cAlphaArgs(16), "None")) { - PurchAir(PurchAirNum).HtRecType = HeatRecovery::NoHeatRecovery; - } else if (UtilityRoutines::SameString(cAlphaArgs(16), "Sensible")) { - PurchAir(PurchAirNum).HtRecType = HeatRecovery::Sensible; - } else if (UtilityRoutines::SameString(cAlphaArgs(16), "Enthalpy")) { - PurchAir(PurchAirNum).HtRecType = HeatRecovery::Enthalpy; + } + // Register OA node + PurchAir(PurchAirNum).OutdoorAirNodeNum = GetOnlySingleNode(state, + cAlphaArgs(13), + ErrorsFound, + cCurrentModuleObject, + cAlphaArgs(1), + NodeType_Air, + NodeConnectionType_Outlet, + 1, + ObjectIsNotParent); + // Check if OA node is initialized in OutdoorAir:Node or OutdoorAir:Nodelist + CheckAndAddAirNodeNumber(state, PurchAir(PurchAirNum).OutdoorAirNodeNum, IsOANodeListed); + if ((!IsOANodeListed) && state.dataGlobal->DisplayExtraWarnings) { + ShowWarningError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " missing data"); + ShowContinueError(state, cAlphaArgs(13) + " does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node."); + ShowContinueError(state, "Adding OutdoorAir:Node=" + cAlphaArgs(13)); + } + UniqueNodeError = false; + CheckUniqueNodes(state, cAlphaFieldNames(13), "NodeName", UniqueNodeError, cAlphaArgs(13), _, cAlphaArgs(1)); + if (UniqueNodeError) ErrorsFound = true; + + // get Demand controlled ventilation type + if (UtilityRoutines::SameString(cAlphaArgs(14), "None")) { + PurchAir(PurchAirNum).DCVType = DCV::NoDCV; + } else if (UtilityRoutines::SameString(cAlphaArgs(14), "OccupancySchedule")) { + PurchAir(PurchAirNum).DCVType = DCV::OccupancySchedule; + } else if (UtilityRoutines::SameString(cAlphaArgs(14), "CO2Setpoint")) { + if (state.dataContaminantBalance->Contaminant.CO2Simulation) { + PurchAir(PurchAirNum).DCVType = DCV::CO2SetPoint; } else { - ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); - ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(16) + '=' + cAlphaArgs(16)); - ShowContinueError(state, "Valid entries are None, Sensible, or Enthalpy"); - ErrorsFound = true; + PurchAir(PurchAirNum).DCVType = DCV::NoDCV; + ShowWarningError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); + ShowContinueError(state, cAlphaFieldNames(14) + '=' + cAlphaArgs(14) + " but CO2 simulation is not active."); + ShowContinueError(state, "Resetting " + cAlphaFieldNames(14) + " to NoDCV"); + ShowContinueError(state, + "To activate CO2 simulation, use ZoneAirContaminantBalance object and specify \"Carbon Dioxide " + "Concentration\"=\"Yes\"."); } - } else { // No outdoorair - PurchAir(PurchAirNum).DCVType = DCV::NoDCV; + } else { + ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); + ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(14) + '=' + cAlphaArgs(14)); + ShowContinueError(state, "Valid entries are None, OccupancySchedule, or CO2Setpoint"); + ErrorsFound = true; + } + // get Outdoor air economizer type + if (UtilityRoutines::SameString(cAlphaArgs(15), "NoEconomizer")) { PurchAir(PurchAirNum).EconomizerType = Econ::NoEconomizer; + } else if (UtilityRoutines::SameString(cAlphaArgs(15), "DifferentialDryBulb")) { + PurchAir(PurchAirNum).EconomizerType = Econ::DifferentialDryBulb; + } else if (UtilityRoutines::SameString(cAlphaArgs(15), "DifferentialEnthalpy")) { + PurchAir(PurchAirNum).EconomizerType = Econ::DifferentialEnthalpy; + } else { + ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); + ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(15) + '=' + cAlphaArgs(15)); + ShowContinueError(state, "Valid entries are NoEconomizer, DifferentialDryBulb, or DifferentialEnthalpy"); + ErrorsFound = true; + } + // get Outdoor air heat recovery type and effectiveness + if (UtilityRoutines::SameString(cAlphaArgs(16), "None")) { PurchAir(PurchAirNum).HtRecType = HeatRecovery::NoHeatRecovery; + } else if (UtilityRoutines::SameString(cAlphaArgs(16), "Sensible")) { + PurchAir(PurchAirNum).HtRecType = HeatRecovery::Sensible; + } else if (UtilityRoutines::SameString(cAlphaArgs(16), "Enthalpy")) { + PurchAir(PurchAirNum).HtRecType = HeatRecovery::Enthalpy; + } else { + ShowSevereError(state, RoutineName + cCurrentModuleObject + "=\"" + cAlphaArgs(1) + " invalid data"); + ShowContinueError(state, "Invalid-entry " + cAlphaFieldNames(16) + '=' + cAlphaArgs(16)); + ShowContinueError(state, "Valid entries are None, Sensible, or Enthalpy"); + ErrorsFound = true; } + } else { // No outdoorair + PurchAir(PurchAirNum).DCVType = DCV::NoDCV; + PurchAir(PurchAirNum).EconomizerType = Econ::NoEconomizer; + PurchAir(PurchAirNum).HtRecType = HeatRecovery::NoHeatRecovery; + } - PurchAir(PurchAirNum).HtRecSenEff = rNumericArgs(10); - PurchAir(PurchAirNum).HtRecLatEff = rNumericArgs(11); + PurchAir(PurchAirNum).HtRecSenEff = rNumericArgs(10); + PurchAir(PurchAirNum).HtRecLatEff = rNumericArgs(11); - for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { - if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) continue; - for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++NodeNum) { - if (PurchAir(PurchAirNum).ZoneSupplyAirNodeNum == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(NodeNum)) { - PurchAir(PurchAirNum).ZonePtr = CtrlZone; - } + for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) { + if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) continue; + for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++NodeNum) { + if (PurchAir(PurchAirNum).ZoneSupplyAirNodeNum == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(NodeNum)) { + PurchAir(PurchAirNum).ZonePtr = CtrlZone; } } + } - PurchAir(PurchAirNum).HVACSizingIndex = 0; - if (!lAlphaFieldBlanks(17)) { - PurchAir(PurchAirNum).HVACSizingIndex = UtilityRoutines::FindItemInList(cAlphaArgs(17), ZoneHVACSizing); - if (PurchAir(PurchAirNum).HVACSizingIndex == 0) { - ShowSevereError(state, cAlphaFieldNames(17) + " = " + cAlphaArgs(17) + " not found."); - ShowContinueError(state, "Occurs in " + cCurrentModuleObject + " = " + PurchAir(PurchAirNum).Name); - ErrorsFound = true; - } + PurchAir(PurchAirNum).HVACSizingIndex = 0; + if (!lAlphaFieldBlanks(17)) { + PurchAir(PurchAirNum).HVACSizingIndex = UtilityRoutines::FindItemInList(cAlphaArgs(17), ZoneHVACSizing); + if (PurchAir(PurchAirNum).HVACSizingIndex == 0) { + ShowSevereError(state, cAlphaFieldNames(17) + " = " + cAlphaArgs(17) + " not found."); + ShowContinueError(state, "Occurs in " + cCurrentModuleObject + " = " + PurchAir(PurchAirNum).Name); + ErrorsFound = true; } + } - // initialize the calculated and report values - PurchAir(PurchAirNum).MaxHeatMassFlowRate = 0.0; - PurchAir(PurchAirNum).MaxCoolMassFlowRate = 0.0; - PurchAir(PurchAirNum).SenHeatEnergy = 0.0; - PurchAir(PurchAirNum).LatHeatEnergy = 0.0; - PurchAir(PurchAirNum).TotHeatEnergy = 0.0; - PurchAir(PurchAirNum).SenCoolEnergy = 0.0; - PurchAir(PurchAirNum).LatCoolEnergy = 0.0; - PurchAir(PurchAirNum).TotCoolEnergy = 0.0; - PurchAir(PurchAirNum).ZoneSenHeatEnergy = 0.0; - PurchAir(PurchAirNum).ZoneLatHeatEnergy = 0.0; - PurchAir(PurchAirNum).ZoneTotHeatEnergy = 0.0; - PurchAir(PurchAirNum).ZoneSenCoolEnergy = 0.0; - PurchAir(PurchAirNum).ZoneLatCoolEnergy = 0.0; - PurchAir(PurchAirNum).ZoneTotCoolEnergy = 0.0; - PurchAir(PurchAirNum).OASenHeatEnergy = 0.0; - PurchAir(PurchAirNum).OALatHeatEnergy = 0.0; - PurchAir(PurchAirNum).OATotHeatEnergy = 0.0; - PurchAir(PurchAirNum).OASenCoolEnergy = 0.0; - PurchAir(PurchAirNum).OALatCoolEnergy = 0.0; - PurchAir(PurchAirNum).OATotCoolEnergy = 0.0; - PurchAir(PurchAirNum).HtRecSenHeatEnergy = 0.0; - PurchAir(PurchAirNum).HtRecLatHeatEnergy = 0.0; - PurchAir(PurchAirNum).HtRecTotHeatEnergy = 0.0; - PurchAir(PurchAirNum).HtRecSenCoolEnergy = 0.0; - PurchAir(PurchAirNum).HtRecLatCoolEnergy = 0.0; - PurchAir(PurchAirNum).HtRecTotCoolEnergy = 0.0; - PurchAir(PurchAirNum).SenHeatRate = 0.0; - PurchAir(PurchAirNum).LatHeatRate = 0.0; - PurchAir(PurchAirNum).TotHeatRate = 0.0; - PurchAir(PurchAirNum).SenCoolRate = 0.0; - PurchAir(PurchAirNum).LatCoolRate = 0.0; - PurchAir(PurchAirNum).TotCoolRate = 0.0; - PurchAir(PurchAirNum).ZoneSenHeatRate = 0.0; - PurchAir(PurchAirNum).ZoneLatHeatRate = 0.0; - PurchAir(PurchAirNum).ZoneTotHeatRate = 0.0; - PurchAir(PurchAirNum).ZoneSenCoolRate = 0.0; - PurchAir(PurchAirNum).ZoneLatCoolRate = 0.0; - PurchAir(PurchAirNum).ZoneTotCoolRate = 0.0; - PurchAir(PurchAirNum).OASenHeatRate = 0.0; - PurchAir(PurchAirNum).OALatHeatRate = 0.0; - PurchAir(PurchAirNum).OATotHeatRate = 0.0; - PurchAir(PurchAirNum).OASenCoolRate = 0.0; - PurchAir(PurchAirNum).OALatCoolRate = 0.0; - PurchAir(PurchAirNum).OATotCoolRate = 0.0; - PurchAir(PurchAirNum).HtRecSenHeatRate = 0.0; - PurchAir(PurchAirNum).HtRecLatHeatRate = 0.0; - PurchAir(PurchAirNum).HtRecTotHeatRate = 0.0; - PurchAir(PurchAirNum).HtRecSenCoolRate = 0.0; - PurchAir(PurchAirNum).HtRecLatCoolRate = 0.0; - PurchAir(PurchAirNum).HtRecTotCoolRate = 0.0; - - PurchAir(PurchAirNum).OutdoorAirMassFlowRate = 0.0; - PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho = 0.0; - PurchAir(PurchAirNum).SupplyAirMassFlowRate = 0.0; - PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho = 0.0; - } - EndUniqueNodeCheck(state, cCurrentModuleObject); + // initialize the calculated and report values + PurchAir(PurchAirNum).MaxHeatMassFlowRate = 0.0; + PurchAir(PurchAirNum).MaxCoolMassFlowRate = 0.0; + PurchAir(PurchAirNum).SenHeatEnergy = 0.0; + PurchAir(PurchAirNum).LatHeatEnergy = 0.0; + PurchAir(PurchAirNum).TotHeatEnergy = 0.0; + PurchAir(PurchAirNum).SenCoolEnergy = 0.0; + PurchAir(PurchAirNum).LatCoolEnergy = 0.0; + PurchAir(PurchAirNum).TotCoolEnergy = 0.0; + PurchAir(PurchAirNum).ZoneSenHeatEnergy = 0.0; + PurchAir(PurchAirNum).ZoneLatHeatEnergy = 0.0; + PurchAir(PurchAirNum).ZoneTotHeatEnergy = 0.0; + PurchAir(PurchAirNum).ZoneSenCoolEnergy = 0.0; + PurchAir(PurchAirNum).ZoneLatCoolEnergy = 0.0; + PurchAir(PurchAirNum).ZoneTotCoolEnergy = 0.0; + PurchAir(PurchAirNum).OASenHeatEnergy = 0.0; + PurchAir(PurchAirNum).OALatHeatEnergy = 0.0; + PurchAir(PurchAirNum).OATotHeatEnergy = 0.0; + PurchAir(PurchAirNum).OASenCoolEnergy = 0.0; + PurchAir(PurchAirNum).OALatCoolEnergy = 0.0; + PurchAir(PurchAirNum).OATotCoolEnergy = 0.0; + PurchAir(PurchAirNum).HtRecSenHeatEnergy = 0.0; + PurchAir(PurchAirNum).HtRecLatHeatEnergy = 0.0; + PurchAir(PurchAirNum).HtRecTotHeatEnergy = 0.0; + PurchAir(PurchAirNum).HtRecSenCoolEnergy = 0.0; + PurchAir(PurchAirNum).HtRecLatCoolEnergy = 0.0; + PurchAir(PurchAirNum).HtRecTotCoolEnergy = 0.0; + PurchAir(PurchAirNum).SenHeatRate = 0.0; + PurchAir(PurchAirNum).LatHeatRate = 0.0; + PurchAir(PurchAirNum).TotHeatRate = 0.0; + PurchAir(PurchAirNum).SenCoolRate = 0.0; + PurchAir(PurchAirNum).LatCoolRate = 0.0; + PurchAir(PurchAirNum).TotCoolRate = 0.0; + PurchAir(PurchAirNum).ZoneSenHeatRate = 0.0; + PurchAir(PurchAirNum).ZoneLatHeatRate = 0.0; + PurchAir(PurchAirNum).ZoneTotHeatRate = 0.0; + PurchAir(PurchAirNum).ZoneSenCoolRate = 0.0; + PurchAir(PurchAirNum).ZoneLatCoolRate = 0.0; + PurchAir(PurchAirNum).ZoneTotCoolRate = 0.0; + PurchAir(PurchAirNum).OASenHeatRate = 0.0; + PurchAir(PurchAirNum).OALatHeatRate = 0.0; + PurchAir(PurchAirNum).OATotHeatRate = 0.0; + PurchAir(PurchAirNum).OASenCoolRate = 0.0; + PurchAir(PurchAirNum).OALatCoolRate = 0.0; + PurchAir(PurchAirNum).OATotCoolRate = 0.0; + PurchAir(PurchAirNum).HtRecSenHeatRate = 0.0; + PurchAir(PurchAirNum).HtRecLatHeatRate = 0.0; + PurchAir(PurchAirNum).HtRecTotHeatRate = 0.0; + PurchAir(PurchAirNum).HtRecSenCoolRate = 0.0; + PurchAir(PurchAirNum).HtRecLatCoolRate = 0.0; + PurchAir(PurchAirNum).HtRecTotCoolRate = 0.0; + + PurchAir(PurchAirNum).OutdoorAirMassFlowRate = 0.0; + PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho = 0.0; + PurchAir(PurchAirNum).SupplyAirMassFlowRate = 0.0; + PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho = 0.0; } + EndUniqueNodeCheck(state, cCurrentModuleObject); + } - for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) { - - // Setup Output variables - // energy variables - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Sensible Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).SenHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Latent Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).LatHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Total Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).TotHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name, - _, - "DISTRICTHEATING", - "Heating", - _, - "System"); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Sensible Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).SenCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Latent Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).LatCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Total Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).TotCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name, - _, - "DISTRICTCOOLING", - "Cooling", - _, - "System"); - SetupOutputVariable(state, "Zone Ideal Loads Zone Sensible Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).ZoneSenHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Zone Latent Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).ZoneLatHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Zone Total Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).ZoneTotHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Zone Sensible Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).ZoneSenCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Zone Latent Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).ZoneLatCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Zone Total Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).ZoneTotCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Sensible Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).OASenHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Latent Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).OALatHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Total Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).OATotHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Sensible Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).OASenCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Latent Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).OALatCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Total Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).OATotCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Sensible Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).HtRecSenHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Latent Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).HtRecLatHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Total Heating Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).HtRecTotHeatEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Sensible Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).HtRecSenCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Latent Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).HtRecLatCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Total Cooling Energy", - OutputProcessor::Unit::J, - PurchAir(PurchAirNum).HtRecTotCoolEnergy, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - - // rate variables - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Sensible Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).SenHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Latent Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).LatHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Total Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).TotHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Sensible Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).SenCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Latent Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).LatCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Total Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).TotCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Zone Sensible Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).ZoneSenHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Zone Latent Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).ZoneLatHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Zone Total Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).ZoneTotHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Zone Sensible Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).ZoneSenCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Zone Latent Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).ZoneLatCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Zone Total Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).ZoneTotCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Sensible Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).OASenHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Latent Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).OALatHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Total Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).OATotHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Sensible Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).OASenCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Latent Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).OALatCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Total Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).OATotCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Sensible Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).HtRecSenHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Latent Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).HtRecLatHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Total Heating Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).HtRecTotHeatRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Sensible Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).HtRecSenCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Latent Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).HtRecLatCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Total Cooling Rate", - OutputProcessor::Unit::W, - PurchAir(PurchAirNum).HtRecTotCoolRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - - SetupOutputVariable(state, "Zone Ideal Loads Economizer Active Time", - OutputProcessor::Unit::hr, - PurchAir(PurchAirNum).TimeEconoActive, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Heat Recovery Active Time", - OutputProcessor::Unit::hr, - PurchAir(PurchAirNum).TimeHtRecActive, - "System", - "Sum", - PurchAir(PurchAirNum).Name); - - SetupOutputVariable(state, "Zone Ideal Loads Hybrid Ventilation Available Status", - OutputProcessor::Unit::None, - PurchAir(PurchAirNum).AvailStatus, - "System", - "Average", - PurchAir(PurchAirNum).Name); - - // air flows - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Mass Flow Rate", - OutputProcessor::Unit::kg_s, - PurchAir(PurchAirNum).OutdoorAirMassFlowRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Outdoor Air Standard Density Volume Flow Rate", - OutputProcessor::Unit::m3_s, - PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Mass Flow Rate", - OutputProcessor::Unit::kg_s, - PurchAir(PurchAirNum).SupplyAirMassFlowRate, - "System", - "Average", - PurchAir(PurchAirNum).Name); - SetupOutputVariable(state, "Zone Ideal Loads Supply Air Standard Density Volume Flow Rate", - OutputProcessor::Unit::m3_s, - PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho, - "System", - "Average", - PurchAir(PurchAirNum).Name); - - if (state.dataGlobal->AnyEnergyManagementSystemInModel) { - SetupEMSActuator(state, "Ideal Loads Air System", - PurchAir(PurchAirNum).Name, - "Air Mass Flow Rate", - "[kg/s]", - PurchAir(PurchAirNum).EMSOverrideMdotOn, - PurchAir(PurchAirNum).EMSValueMassFlowRate); - SetupEMSActuator(state, "Ideal Loads Air System", - PurchAir(PurchAirNum).Name, - "Outdoor Air Mass Flow Rate", - "[kg/s]", - PurchAir(PurchAirNum).EMSOverrideOAMdotOn, - PurchAir(PurchAirNum).EMSValueOAMassFlowRate); - SetupEMSActuator(state, "Ideal Loads Air System", - PurchAir(PurchAirNum).Name, - "Air Temperature", - "[C]", - PurchAir(PurchAirNum).EMSOverrideSupplyTempOn, - PurchAir(PurchAirNum).EMSValueSupplyTemp); - SetupEMSActuator(state, "Ideal Loads Air System", - PurchAir(PurchAirNum).Name, - "Air Humidity Ratio", - "[kgWater/kgDryAir]", - PurchAir(PurchAirNum).EMSOverrideSupplyHumRatOn, - PurchAir(PurchAirNum).EMSValueSupplyHumRat); - } + for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) { + + // Setup Output variables + // energy variables + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Sensible Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).SenHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Latent Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).LatHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Total Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).TotHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name, + _, + "DISTRICTHEATING", + "Heating", + _, + "System"); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Sensible Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).SenCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Latent Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).LatCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Total Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).TotCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name, + _, + "DISTRICTCOOLING", + "Cooling", + _, + "System"); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Sensible Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).ZoneSenHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Latent Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).ZoneLatHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Total Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).ZoneTotHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Sensible Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).ZoneSenCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Latent Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).ZoneLatCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Total Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).ZoneTotCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Sensible Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).OASenHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Latent Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).OALatHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Total Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).OATotHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Sensible Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).OASenCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Latent Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).OALatCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Total Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).OATotCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Sensible Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).HtRecSenHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Latent Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).HtRecLatHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Total Heating Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).HtRecTotHeatEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Sensible Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).HtRecSenCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Latent Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).HtRecLatCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Total Cooling Energy", + OutputProcessor::Unit::J, + PurchAir(PurchAirNum).HtRecTotCoolEnergy, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + + // rate variables + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Sensible Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).SenHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Latent Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).LatHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Total Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).TotHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Sensible Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).SenCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Latent Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).LatCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Total Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).TotCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Sensible Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).ZoneSenHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Latent Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).ZoneLatHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Total Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).ZoneTotHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Sensible Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).ZoneSenCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Latent Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).ZoneLatCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Zone Total Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).ZoneTotCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Sensible Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).OASenHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Latent Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).OALatHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Total Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).OATotHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Sensible Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).OASenCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Latent Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).OALatCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Total Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).OATotCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Sensible Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).HtRecSenHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Latent Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).HtRecLatHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Total Heating Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).HtRecTotHeatRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Sensible Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).HtRecSenCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Latent Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).HtRecLatCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Total Cooling Rate", + OutputProcessor::Unit::W, + PurchAir(PurchAirNum).HtRecTotCoolRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + + SetupOutputVariable(state, + "Zone Ideal Loads Economizer Active Time", + OutputProcessor::Unit::hr, + PurchAir(PurchAirNum).TimeEconoActive, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Heat Recovery Active Time", + OutputProcessor::Unit::hr, + PurchAir(PurchAirNum).TimeHtRecActive, + "System", + "Sum", + PurchAir(PurchAirNum).Name); + + SetupOutputVariable(state, + "Zone Ideal Loads Hybrid Ventilation Available Status", + OutputProcessor::Unit::None, + PurchAir(PurchAirNum).AvailStatus, + "System", + "Average", + PurchAir(PurchAirNum).Name); + + // air flows + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Mass Flow Rate", + OutputProcessor::Unit::kg_s, + PurchAir(PurchAirNum).OutdoorAirMassFlowRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Outdoor Air Standard Density Volume Flow Rate", + OutputProcessor::Unit::m3_s, + PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Mass Flow Rate", + OutputProcessor::Unit::kg_s, + PurchAir(PurchAirNum).SupplyAirMassFlowRate, + "System", + "Average", + PurchAir(PurchAirNum).Name); + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Standard Density Volume Flow Rate", + OutputProcessor::Unit::m3_s, + PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho, + "System", + "Average", + PurchAir(PurchAirNum).Name); + + // Supply Air temperature + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Temperature", + OutputProcessor::Unit::C, + PurchAir(PurchAirNum).SupplyTemp, + "System", + "Average", + PurchAir(PurchAirNum).Name); + // Supply Air Humidity Ratio + SetupOutputVariable(state, + "Zone Ideal Loads Supply Air Humidity Ratio", + OutputProcessor::Unit::kgWater_kgDryAir, + PurchAir(PurchAirNum).SupplyHumRat, + "System", + "Average", + PurchAir(PurchAirNum).Name); + + // Mixed Air temperature + SetupOutputVariable(state, + "Zone Ideal Loads Mixed Air Temperature", + OutputProcessor::Unit::C, + PurchAir(PurchAirNum).MixedAirTemp, + "System", + "Average", + PurchAir(PurchAirNum).Name); + // Mixed Air Humidity Ratio + SetupOutputVariable(state, + "Zone Ideal Loads Mixed Air Humidity Ratio", + OutputProcessor::Unit::kgWater_kgDryAir, + PurchAir(PurchAirNum).MixedAirHumRat, + "System", + "Average", + PurchAir(PurchAirNum).Name); + + if (state.dataGlobal->AnyEnergyManagementSystemInModel) { + SetupEMSActuator(state, + "Ideal Loads Air System", + PurchAir(PurchAirNum).Name, + "Air Mass Flow Rate", + "[kg/s]", + PurchAir(PurchAirNum).EMSOverrideMdotOn, + PurchAir(PurchAirNum).EMSValueMassFlowRate); + SetupEMSActuator(state, + "Ideal Loads Air System", + PurchAir(PurchAirNum).Name, + "Outdoor Air Mass Flow Rate", + "[kg/s]", + PurchAir(PurchAirNum).EMSOverrideOAMdotOn, + PurchAir(PurchAirNum).EMSValueOAMassFlowRate); + SetupEMSActuator(state, + "Ideal Loads Air System", + PurchAir(PurchAirNum).Name, + "Air Temperature", + "[C]", + PurchAir(PurchAirNum).EMSOverrideSupplyTempOn, + PurchAir(PurchAirNum).EMSValueSupplyTemp); + SetupEMSActuator(state, + "Ideal Loads Air System", + PurchAir(PurchAirNum).Name, + "Air Humidity Ratio", + "[kgWater/kgDryAir]", + PurchAir(PurchAirNum).EMSOverrideSupplyHumRatOn, + PurchAir(PurchAirNum).EMSValueSupplyHumRat); } + } - if (ErrorsFound) { - ShowFatalError(state, RoutineName + "Errors found in input. Preceding conditions cause termination."); - } + if (ErrorsFound) { + ShowFatalError(state, RoutineName + "Errors found in input. Preceding conditions cause termination."); } +} - void InitPurchasedAir(EnergyPlusData &state, - int const PurchAirNum, - [[maybe_unused]] bool const FirstHVACIteration, // unused1208 - int const ControlledZoneNum, - int const ActualZoneNum) - { - - // SUBROUTINE INFORMATION: - // AUTHOR Russ Taylor - // DATE WRITTEN Nov 1997 - // MODIFIED na - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // Initialize the PurchAir data structure. - - // METHODOLOGY EMPLOYED: - // na - - // REFERENCES: - // na - - // Using/Aliasing - using DataHeatBalance::Zone; // to access zone area, volume, and multipliers - using DataLoopNode::NodeID; - using DataSizing::OARequirements; // to access DesignSpecification:OutdoorAir inputs - using DataZoneEquipment::CheckZoneEquipmentList; - using General::FindNumberInList; - - using ZonePlenum::GetReturnPlenumIndex; - using ZonePlenum::GetReturnPlenumName; - - // Locals - // SUBROUTINE ARGUMENT DEFINITIONS: - - // SUBROUTINE PARAMETER DEFINITIONS: - // na - - // INTERFACE BLOCK SPECIFICATIONS: - // na - - // DERIVED TYPE DEFINITIONS: - // na - - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - int Loop; - // LOGICAL :: ErrorsFound = .FALSE. ! If errors detected in input - bool UnitOn; // simple checks for error - bool CoolOn; // simple checks for error - bool HeatOn; // simple checks for error - int SupplyNodeNum; // Node number for ideal loads supply node - int ExhaustNodeNum; // Node number for ideal loads exhaust node - int NodeIndex; // Array index of zone inlet or zone exhaust node that matches ideal loads node - bool UseReturnNode; // simple checks for error - - auto & PurchAir(state.dataPurchasedAirMgr->PurchAir); - - // Do the Begin Simulation initializations - if (state.dataPurchasedAirMgr->InitPurchasedAirMyOneTimeFlag) { - state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag.allocate(state.dataPurchasedAirMgr->NumPurchAir); - state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag.allocate(state.dataPurchasedAirMgr->NumPurchAir); - state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone.allocate(state.dataPurchasedAirMgr->NumPurchAir); - state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag = true; - state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag = true; - state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone = false; - state.dataPurchasedAirMgr->InitPurchasedAirMyOneTimeFlag = false; - } +void InitPurchasedAir(EnergyPlusData &state, + int const PurchAirNum, + [[maybe_unused]] bool const FirstHVACIteration, // unused1208 + int const ControlledZoneNum, + int const ActualZoneNum) +{ - // need to check all units to see if they are on Zone Equipment List or issue warning - if (!state.dataPurchasedAirMgr->InitPurchasedAirZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) { - state.dataPurchasedAirMgr->InitPurchasedAirZoneEquipmentListChecked = true; - for (Loop = 1; Loop <= state.dataPurchasedAirMgr->NumPurchAir; ++Loop) { - - // link with return plenum if used (i.e., PlenumExhaustAirNodeNum will be non-zero) - if (PurchAir(Loop).PlenumExhaustAirNodeNum > 0) { - PurchAir(Loop).ReturnPlenumIndex = GetReturnPlenumIndex(state, PurchAir(Loop).PlenumExhaustAirNodeNum); - if (PurchAir(Loop).ReturnPlenumIndex > 0) { - GetReturnPlenumName(state, PurchAir(Loop).ReturnPlenumIndex, PurchAir(Loop).ReturnPlenumName); - InitializePlenumArrays(state, Loop); - } else { - ShowSevereError(state, "InitPurchasedAir: " + PurchAir(Loop).cObjectName + " = " + PurchAir(Loop).Name + + // SUBROUTINE INFORMATION: + // AUTHOR Russ Taylor + // DATE WRITTEN Nov 1997 + // MODIFIED na + // RE-ENGINEERED na + + // PURPOSE OF THIS SUBROUTINE: + // Initialize the PurchAir data structure. + + // METHODOLOGY EMPLOYED: + // na + + // REFERENCES: + // na + + // Using/Aliasing + using DataHeatBalance::Zone; // to access zone area, volume, and multipliers + using DataLoopNode::NodeID; + using DataSizing::OARequirements; // to access DesignSpecification:OutdoorAir inputs + using DataZoneEquipment::CheckZoneEquipmentList; + using General::FindNumberInList; + + using ZonePlenum::GetReturnPlenumIndex; + using ZonePlenum::GetReturnPlenumName; + + // Locals + // SUBROUTINE ARGUMENT DEFINITIONS: + + // SUBROUTINE PARAMETER DEFINITIONS: + // na + + // INTERFACE BLOCK SPECIFICATIONS: + // na + + // DERIVED TYPE DEFINITIONS: + // na + + // SUBROUTINE LOCAL VARIABLE DECLARATIONS: + int Loop; + // LOGICAL :: ErrorsFound = .FALSE. ! If errors detected in input + bool UnitOn; // simple checks for error + bool CoolOn; // simple checks for error + bool HeatOn; // simple checks for error + int SupplyNodeNum; // Node number for ideal loads supply node + int ExhaustNodeNum; // Node number for ideal loads exhaust node + int NodeIndex; // Array index of zone inlet or zone exhaust node that matches ideal loads node + bool UseReturnNode; // simple checks for error + + auto &PurchAir(state.dataPurchasedAirMgr->PurchAir); + + // Do the Begin Simulation initializations + if (state.dataPurchasedAirMgr->InitPurchasedAirMyOneTimeFlag) { + state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag.allocate(state.dataPurchasedAirMgr->NumPurchAir); + state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag.allocate(state.dataPurchasedAirMgr->NumPurchAir); + state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone.allocate(state.dataPurchasedAirMgr->NumPurchAir); + state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag = true; + state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag = true; + state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone = false; + state.dataPurchasedAirMgr->InitPurchasedAirMyOneTimeFlag = false; + } + + // need to check all units to see if they are on Zone Equipment List or issue warning + if (!state.dataPurchasedAirMgr->InitPurchasedAirZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) { + state.dataPurchasedAirMgr->InitPurchasedAirZoneEquipmentListChecked = true; + for (Loop = 1; Loop <= state.dataPurchasedAirMgr->NumPurchAir; ++Loop) { + + // link with return plenum if used (i.e., PlenumExhaustAirNodeNum will be non-zero) + if (PurchAir(Loop).PlenumExhaustAirNodeNum > 0) { + PurchAir(Loop).ReturnPlenumIndex = GetReturnPlenumIndex(state, PurchAir(Loop).PlenumExhaustAirNodeNum); + if (PurchAir(Loop).ReturnPlenumIndex > 0) { + GetReturnPlenumName(state, PurchAir(Loop).ReturnPlenumIndex, PurchAir(Loop).ReturnPlenumName); + InitializePlenumArrays(state, Loop); + } else { + ShowSevereError(state, + "InitPurchasedAir: " + PurchAir(Loop).cObjectName + " = " + PurchAir(Loop).Name + " cannot find ZoneHVAC:ReturnPlenum. It will not be simulated."); - } } + } - if (CheckZoneEquipmentList(state, PurchAir(Loop).cObjectName, PurchAir(Loop).Name)) continue; - ShowSevereError(state, "InitPurchasedAir: " + PurchAir(Loop).cObjectName + " = " + PurchAir(Loop).Name + + if (CheckZoneEquipmentList(state, PurchAir(Loop).cObjectName, PurchAir(Loop).Name)) continue; + ShowSevereError(state, + "InitPurchasedAir: " + PurchAir(Loop).cObjectName + " = " + PurchAir(Loop).Name + " is not on any ZoneHVAC:EquipmentList. It will not be simulated."); - } } + } - // one time inits for each unit - links PurchAirNum with static input data from ControlledZoneNum and ActualZoneNum - if (!state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone(PurchAirNum)) { - state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone(PurchAirNum) = true; - - // Is the supply node really a zone inlet node? - // this check has to be done here because of SimPurchasedAir passing in ControlledZoneNum - SupplyNodeNum = PurchAir(PurchAirNum).ZoneSupplyAirNodeNum; - if (SupplyNodeNum > 0) { - NodeIndex = - FindNumberInList(SupplyNodeNum, state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode, state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes); - if (NodeIndex == 0) { - ShowSevereError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); - ShowContinueError(state, "Zone Supply Air Node Name=" + NodeID(SupplyNodeNum) + " is not a zone inlet node."); - ShowContinueError(state, "Check ZoneHVAC:EquipmentConnections for zone=" + state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneName); - ShowFatalError(state, "Preceding condition causes termination."); - } + // one time inits for each unit - links PurchAirNum with static input data from ControlledZoneNum and ActualZoneNum + if (!state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone(PurchAirNum)) { + state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone(PurchAirNum) = true; + + // Is the supply node really a zone inlet node? + // this check has to be done here because of SimPurchasedAir passing in ControlledZoneNum + SupplyNodeNum = PurchAir(PurchAirNum).ZoneSupplyAirNodeNum; + if (SupplyNodeNum > 0) { + NodeIndex = FindNumberInList(SupplyNodeNum, + state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode, + state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes); + if (NodeIndex == 0) { + ShowSevereError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); + ShowContinueError(state, "Zone Supply Air Node Name=" + NodeID(SupplyNodeNum) + " is not a zone inlet node."); + ShowContinueError(state, + "Check ZoneHVAC:EquipmentConnections for zone=" + state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneName); + ShowFatalError(state, "Preceding condition causes termination."); } + } - // Set recirculation node number - // If exhaust node is specified, then recirculation is exhaust node, otherwise use zone return node - // this check has to be done here because of SimPurchasedAir passing in ControlledZoneNum - UseReturnNode = false; - if (PurchAir(PurchAirNum).ZoneExhaustAirNodeNum > 0) { - ExhaustNodeNum = PurchAir(PurchAirNum).ZoneExhaustAirNodeNum; - NodeIndex = FindNumberInList( - ExhaustNodeNum, state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ExhaustNode, state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumExhaustNodes); - if (NodeIndex == 0) { - ShowSevereError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); - ShowContinueError(state, "Zone Exhaust Air Node Name=" + NodeID(ExhaustNodeNum) + " is not a zone exhaust node."); - ShowContinueError(state, "Check ZoneHVAC:EquipmentConnections for zone=" + state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneName); - ShowContinueError(state, "Zone return air node will be used for ideal loads recirculation air."); - UseReturnNode = true; - } else { - PurchAir(PurchAirNum).ZoneRecircAirNodeNum = PurchAir(PurchAirNum).ZoneExhaustAirNodeNum; - } - } else { + // Set recirculation node number + // If exhaust node is specified, then recirculation is exhaust node, otherwise use zone return node + // this check has to be done here because of SimPurchasedAir passing in ControlledZoneNum + UseReturnNode = false; + if (PurchAir(PurchAirNum).ZoneExhaustAirNodeNum > 0) { + ExhaustNodeNum = PurchAir(PurchAirNum).ZoneExhaustAirNodeNum; + NodeIndex = FindNumberInList(ExhaustNodeNum, + state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ExhaustNode, + state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumExhaustNodes); + if (NodeIndex == 0) { + ShowSevereError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); + ShowContinueError(state, "Zone Exhaust Air Node Name=" + NodeID(ExhaustNodeNum) + " is not a zone exhaust node."); + ShowContinueError(state, + "Check ZoneHVAC:EquipmentConnections for zone=" + state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneName); + ShowContinueError(state, "Zone return air node will be used for ideal loads recirculation air."); UseReturnNode = true; + } else { + PurchAir(PurchAirNum).ZoneRecircAirNodeNum = PurchAir(PurchAirNum).ZoneExhaustAirNodeNum; } - if (UseReturnNode) { - if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumReturnNodes == 1) { - PurchAir(PurchAirNum).ZoneRecircAirNodeNum = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ReturnNode(1); - } else if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumReturnNodes > 1) { - ShowWarningError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); - ShowContinueError(state, - "No Zone Exhaust Air Node Name has been specified for this system and the zone has more than one Return Air Node."); - ShowContinueError(state, "Using the first return air node =" + NodeID(state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ReturnNode(1))); - } else { - ShowFatalError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); - ShowContinueError(state, - " Invalid recirculation node. No exhaust or return node has been specified for this zone in ZoneHVAC:EquipmentConnections."); - ShowFatalError(state, "Preceding condition causes termination."); - } + } else { + UseReturnNode = true; + } + if (UseReturnNode) { + if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumReturnNodes == 1) { + PurchAir(PurchAirNum).ZoneRecircAirNodeNum = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ReturnNode(1); + } else if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumReturnNodes > 1) { + ShowWarningError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); + ShowContinueError(state, + "No Zone Exhaust Air Node Name has been specified for this system and the zone has more than one Return Air Node."); + ShowContinueError( + state, "Using the first return air node =" + NodeID(state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ReturnNode(1))); + } else { + ShowFatalError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); + ShowContinueError( + state, + " Invalid recirculation node. No exhaust or return node has been specified for this zone in ZoneHVAC:EquipmentConnections."); + ShowFatalError(state, "Preceding condition causes termination."); } - // If there is OA and economizer is active, then there must be a limit on cooling flow rate - if (PurchAir(PurchAirNum).OutdoorAir && (PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer)) { - if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::NoLimit) || (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity)) { - ShowSevereError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); - ShowContinueError(state, "There is outdoor air with economizer active but there is no limit on cooling air flow rate."); - ShowContinueError(state, "Cooling Limit must be set to LimitFlowRate or LimitFlowRateAndCapacity, and Maximum Cooling Air Flow Rate " - "must be set to a value or autosize."); - ShowContinueError(state, "Simulation will proceed with no limit on outdoor air flow rate."); - } + } + // If there is OA and economizer is active, then there must be a limit on cooling flow rate + if (PurchAir(PurchAirNum).OutdoorAir && (PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer)) { + if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::NoLimit) || (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity)) { + ShowSevereError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); + ShowContinueError(state, "There is outdoor air with economizer active but there is no limit on cooling air flow rate."); + ShowContinueError(state, + "Cooling Limit must be set to LimitFlowRate or LimitFlowRateAndCapacity, and Maximum Cooling Air Flow Rate " + "must be set to a value or autosize."); + ShowContinueError(state, "Simulation will proceed with no limit on outdoor air flow rate."); } } + } - if (!state.dataGlobal->SysSizingCalc && state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag(PurchAirNum)) { + if (!state.dataGlobal->SysSizingCalc && state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag(PurchAirNum)) { - SizePurchasedAir(state, PurchAirNum); + SizePurchasedAir(state, PurchAirNum); - state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag(PurchAirNum) = false; - } + state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag(PurchAirNum) = false; + } - // Do the Begin Environment initializations - if (state.dataGlobal->BeginEnvrnFlag && state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum)) { + // Do the Begin Environment initializations + if (state.dataGlobal->BeginEnvrnFlag && state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum)) { - if ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) { - PurchAir(PurchAirNum).MaxHeatMassFlowRate = state.dataEnvrn->StdRhoAir * PurchAir(PurchAirNum).MaxHeatVolFlowRate; - } else { - PurchAir(PurchAirNum).MaxHeatMassFlowRate = 0.0; - } - if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) { - PurchAir(PurchAirNum).MaxCoolMassFlowRate = state.dataEnvrn->StdRhoAir * PurchAir(PurchAirNum).MaxCoolVolFlowRate; - } else { - PurchAir(PurchAirNum).MaxCoolMassFlowRate = 0.0; - } - state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum) = false; + if ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) { + PurchAir(PurchAirNum).MaxHeatMassFlowRate = state.dataEnvrn->StdRhoAir * PurchAir(PurchAirNum).MaxHeatVolFlowRate; + } else { + PurchAir(PurchAirNum).MaxHeatMassFlowRate = 0.0; } - - if (!state.dataGlobal->BeginEnvrnFlag) { - state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum) = true; + if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) { + PurchAir(PurchAirNum).MaxCoolMassFlowRate = state.dataEnvrn->StdRhoAir * PurchAir(PurchAirNum).MaxCoolVolFlowRate; + } else { + PurchAir(PurchAirNum).MaxCoolMassFlowRate = 0.0; } + state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum) = false; + } - // These initializations are done every iteration - // check that supply air temps can meet the zone thermostat setpoints - if (PurchAir(PurchAirNum).MinCoolSuppAirTemp > ZoneThermostatSetPointHi(ActualZoneNum) && ZoneThermostatSetPointHi(ActualZoneNum) != 0 && - PurchAir(PurchAirNum).CoolingLimit == LimitType::NoLimit) { - // Check if the unit is scheduled off - UnitOn = true; - // IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN - if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) { - UnitOn = false; - } - // END IF - // Check if cooling available - CoolOn = true; - // IF (PurchAir(PurchAirNum)%CoolSchedPtr > 0) THEN - if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).CoolSchedPtr) <= 0) { - CoolOn = false; - } - // END IF - if (UnitOn && CoolOn) { - if (PurchAir(PurchAirNum).CoolErrIndex == 0) { - ShowSevereError(state, "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name + - " serving Zone " + Zone(ActualZoneNum).Name); - ShowContinueError(state, - format("..the minimum supply air temperature for cooling [{:.2R}] is greater than the zone cooling mean air " - "temperature (MAT) setpoint [{:.2R}].", - PurchAir(PurchAirNum).MinCoolSuppAirTemp, - ZoneThermostatSetPointHi(ActualZoneNum))); - ShowContinueError(state, "..For operative and comfort thermostat controls, the MAT setpoint is computed."); - ShowContinueError(state, "..This error may indicate that the mean radiant temperature or another comfort factor is too warm."); - ShowContinueError(state, "Unit availability is nominally ON and Cooling availability is nominally ON."); - ShowContinueError(state, format("Limit Cooling Capacity Type={}", cLimitType(PurchAir(PurchAirNum).CoolingLimit))); - // could check for optemp control or comfort control here - ShowContinueErrorTimeStamp(state, ""); - } - ShowRecurringSevereErrorAtEnd(state, "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name + - " serving Zone " + Zone(ActualZoneNum).Name + - ", the minimum supply air temperature for cooling error continues", - PurchAir(PurchAirNum).CoolErrIndex, - PurchAir(PurchAirNum).MinCoolSuppAirTemp, - PurchAir(PurchAirNum).MinCoolSuppAirTemp, - _, - "C", - "C"); + if (!state.dataGlobal->BeginEnvrnFlag) { + state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum) = true; + } + + // These initializations are done every iteration + // check that supply air temps can meet the zone thermostat setpoints + if (PurchAir(PurchAirNum).MinCoolSuppAirTemp > ZoneThermostatSetPointHi(ActualZoneNum) && ZoneThermostatSetPointHi(ActualZoneNum) != 0 && + PurchAir(PurchAirNum).CoolingLimit == LimitType::NoLimit) { + // Check if the unit is scheduled off + UnitOn = true; + // IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN + if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) { + UnitOn = false; + } + // END IF + // Check if cooling available + CoolOn = true; + // IF (PurchAir(PurchAirNum)%CoolSchedPtr > 0) THEN + if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).CoolSchedPtr) <= 0) { + CoolOn = false; + } + // END IF + if (UnitOn && CoolOn) { + if (PurchAir(PurchAirNum).CoolErrIndex == 0) { + ShowSevereError(state, + "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name + " serving Zone " + + Zone(ActualZoneNum).Name); + ShowContinueError(state, + format("..the minimum supply air temperature for cooling [{:.2R}] is greater than the zone cooling mean air " + "temperature (MAT) setpoint [{:.2R}].", + PurchAir(PurchAirNum).MinCoolSuppAirTemp, + ZoneThermostatSetPointHi(ActualZoneNum))); + ShowContinueError(state, "..For operative and comfort thermostat controls, the MAT setpoint is computed."); + ShowContinueError(state, "..This error may indicate that the mean radiant temperature or another comfort factor is too warm."); + ShowContinueError(state, "Unit availability is nominally ON and Cooling availability is nominally ON."); + ShowContinueError(state, format("Limit Cooling Capacity Type={}", cLimitType(PurchAir(PurchAirNum).CoolingLimit))); + // could check for optemp control or comfort control here + ShowContinueErrorTimeStamp(state, ""); } + ShowRecurringSevereErrorAtEnd(state, + "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name + + " serving Zone " + Zone(ActualZoneNum).Name + + ", the minimum supply air temperature for cooling error continues", + PurchAir(PurchAirNum).CoolErrIndex, + PurchAir(PurchAirNum).MinCoolSuppAirTemp, + PurchAir(PurchAirNum).MinCoolSuppAirTemp, + _, + "C", + "C"); } - if (PurchAir(PurchAirNum).MaxHeatSuppAirTemp < ZoneThermostatSetPointLo(ActualZoneNum) && ZoneThermostatSetPointLo(ActualZoneNum) != 0 && - PurchAir(PurchAirNum).HeatingLimit == LimitType::NoLimit) { - // Check if the unit is scheduled off - UnitOn = true; - // IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN - if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) { - UnitOn = false; - } - // END IF - // Check if heating and cooling available - HeatOn = true; - // IF (PurchAir(PurchAirNum)%HeatSchedPtr > 0) THEN - if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).HeatSchedPtr) <= 0) { - HeatOn = false; - } - // END IF - if (UnitOn && HeatOn) { - if (PurchAir(PurchAirNum).HeatErrIndex == 0) { - ShowSevereMessage(state, "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name + + } + if (PurchAir(PurchAirNum).MaxHeatSuppAirTemp < ZoneThermostatSetPointLo(ActualZoneNum) && ZoneThermostatSetPointLo(ActualZoneNum) != 0 && + PurchAir(PurchAirNum).HeatingLimit == LimitType::NoLimit) { + // Check if the unit is scheduled off + UnitOn = true; + // IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN + if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) { + UnitOn = false; + } + // END IF + // Check if heating and cooling available + HeatOn = true; + // IF (PurchAir(PurchAirNum)%HeatSchedPtr > 0) THEN + if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).HeatSchedPtr) <= 0) { + HeatOn = false; + } + // END IF + if (UnitOn && HeatOn) { + if (PurchAir(PurchAirNum).HeatErrIndex == 0) { + ShowSevereMessage(state, + "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name + " serving Zone " + Zone(ActualZoneNum).Name); - ShowContinueError(state, - format("..the maximum supply air temperature for heating [{:.2R}] is less than the zone mean air temperature " - "heating setpoint [{:.2R}].", - PurchAir(PurchAirNum).MaxHeatSuppAirTemp, - ZoneThermostatSetPointLo(ActualZoneNum))); - ShowContinueError(state, "..For operative and comfort thermostat controls, the MAT setpoint is computed."); - ShowContinueError(state, "..This error may indicate that the mean radiant temperature or another comfort factor is too cold."); - ShowContinueError(state, "Unit availability is nominally ON and Heating availability is nominally ON."); - ShowContinueError(state, format("Limit Heating Capacity Type={}", cLimitType(PurchAir(PurchAirNum).HeatingLimit))); - // could check for optemp control or comfort control here - ShowContinueErrorTimeStamp(state, ""); - } - ShowRecurringSevereErrorAtEnd(state, "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name + - " serving Zone " + Zone(ActualZoneNum).Name + - ", maximum supply air temperature for heating error continues", - PurchAir(PurchAirNum).HeatErrIndex, - PurchAir(PurchAirNum).MaxHeatSuppAirTemp, - PurchAir(PurchAirNum).MaxHeatSuppAirTemp, - _, - "C", - "C"); + ShowContinueError(state, + format("..the maximum supply air temperature for heating [{:.2R}] is less than the zone mean air temperature " + "heating setpoint [{:.2R}].", + PurchAir(PurchAirNum).MaxHeatSuppAirTemp, + ZoneThermostatSetPointLo(ActualZoneNum))); + ShowContinueError(state, "..For operative and comfort thermostat controls, the MAT setpoint is computed."); + ShowContinueError(state, "..This error may indicate that the mean radiant temperature or another comfort factor is too cold."); + ShowContinueError(state, "Unit availability is nominally ON and Heating availability is nominally ON."); + ShowContinueError(state, format("Limit Heating Capacity Type={}", cLimitType(PurchAir(PurchAirNum).HeatingLimit))); + // could check for optemp control or comfort control here + ShowContinueErrorTimeStamp(state, ""); } + ShowRecurringSevereErrorAtEnd(state, + "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name + + " serving Zone " + Zone(ActualZoneNum).Name + + ", maximum supply air temperature for heating error continues", + PurchAir(PurchAirNum).HeatErrIndex, + PurchAir(PurchAirNum).MaxHeatSuppAirTemp, + PurchAir(PurchAirNum).MaxHeatSuppAirTemp, + _, + "C", + "C"); } - // IF (ErrorsFound .and. .not. WarmupFlag) THEN - // CALL ShowFatalError(state, 'Preceding conditions cause termination.') - // ENDIF } + // IF (ErrorsFound .and. .not. WarmupFlag) THEN + // CALL ShowFatalError(state, 'Preceding conditions cause termination.') + // ENDIF +} + +void SizePurchasedAir(EnergyPlusData &state, int const PurchAirNum) +{ + + // SUBROUTINE INFORMATION: + // AUTHOR Fred Buhl + // DATE WRITTEN April 2003 + // MODIFIED M. Witte, June 2011, add sizing for new capacity fields + // August 2013 Daeho Kang, add component sizing table entries + // RE-ENGINEERED na - void SizePurchasedAir(EnergyPlusData &state, int const PurchAirNum) - { - - // SUBROUTINE INFORMATION: - // AUTHOR Fred Buhl - // DATE WRITTEN April 2003 - // MODIFIED M. Witte, June 2011, add sizing for new capacity fields - // August 2013 Daeho Kang, add component sizing table entries - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // This subroutine is for sizing Purchased Air Components for which flow rates have not been - // specified in the input. - - // METHODOLOGY EMPLOYED: - // Obtains flow rates from the zone sizing arrays. - - // Using/Aliasing - using namespace DataSizing; - using DataHeatBalance::Zone; - using DataHVACGlobals::CoolingCapacitySizing; - using DataHVACGlobals::HeatingAirflowSizing; - using DataHVACGlobals::HeatingCapacitySizing; - - using Psychrometrics::CPCW; - using Psychrometrics::CPHW; - using Psychrometrics::PsyCpAirFnW; - using Psychrometrics::PsyHFnTdbW; - using Psychrometrics::RhoH2O; - - // SUBROUTINE PARAMETER DEFINITIONS: - static std::string const RoutineName("SizePurchasedAir: "); // include trailing blank space - - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - bool IsAutoSize; // Indicator to autosize - Real64 MaxHeatVolFlowRateDes; // Autosized maximum heating air flow for reporting - Real64 MaxHeatVolFlowRateUser; // Hardsized maximum heating air flow for reporting - Real64 MaxCoolVolFlowRateDes; // Autosized maximum cooling air flow for reporting - Real64 MaxCoolVolFlowRateUser; // Hardsized maximum cooling air flow for reporting - Real64 MaxHeatSensCapDes; // Autosized maximum sensible heating capacity for reporting - Real64 MaxHeatSensCapUser; // Hardsized maximum sensible heating capacity for reporting - Real64 MaxCoolTotCapDes; // Autosized maximum sensible cooling capacity for reporting - Real64 MaxCoolTotCapUser; // Hardsized maximum sensible cooling capacity for reporting - std::string CompName; // component name - std::string CompType; // component type - std::string SizingString; // input field sizing description (e.g., Nominal Capacity) - Real64 TempSize; // autosized value of coil input field - int FieldNum = 2; // IDD numeric field number where input field description is found - int SizingMethod; // Integer representation of sizing method name (e.g., CoolingAirflowSizing, HeatingAirflowSizing, CoolingCapacitySizing, - // HeatingCapacitySizing, etc.) - bool PrintFlag; // TRUE when sizing information is reported in the eio file - int zoneHVACIndex; // index of zoneHVAC equipment sizing specification - int SAFMethod(0); // supply air flow rate sizing method (SupplyAirFlowRate, FlowPerFloorArea, FractionOfAutosizedCoolingAirflow, - // FractionOfAutosizedHeatingAirflow ...) - int CapSizingMethod(0); // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity, and - // FractionOfAutosizedHeatingCapacity ) - Real64 CoolingAirVolFlowDes(0.0); // cooling supply air flow rate - Real64 HeatingAirVolFlowDes(0.0); // heating supply air flow rate - - auto & PurchAir(state.dataPurchasedAirMgr->PurchAir); - - IsAutoSize = false; - MaxHeatVolFlowRateDes = 0.0; - MaxHeatVolFlowRateUser = 0.0; - MaxCoolVolFlowRateDes = 0.0; - MaxCoolVolFlowRateUser = 0.0; - MaxHeatSensCapDes = 0.0; - MaxHeatSensCapUser = 0.0; - MaxCoolTotCapDes = 0.0; - MaxCoolTotCapUser = 0.0; - - ZoneHeatingOnlyFan = false; - ZoneCoolingOnlyFan = false; - CompType = PurchAir(PurchAirNum).cObjectName; - CompName = PurchAir(PurchAirNum).Name; - bool ErrorsFound = false; - - if (CurZoneEqNum > 0) { - if (PurchAir(PurchAirNum).HVACSizingIndex > 0) { - DataZoneNumber = PurchAir(PurchAirNum).ZonePtr; - zoneHVACIndex = PurchAir(PurchAirNum).HVACSizingIndex; - - FieldNum = 5; // N5 , \field Maximum Heating Air Flow Rate - PrintFlag = true; - SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]"; - if (ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod > 0) { - SizingMethod = HeatingAirflowSizing; - ZoneHeatingOnlyFan = true; - SAFMethod = ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod; - ZoneEqSizing(CurZoneEqNum).SizingMethod(SizingMethod) = SAFMethod; - if (SAFMethod == SupplyAirFlowRate || SAFMethod == FlowPerFloorArea || SAFMethod == FractionOfAutosizedHeatingAirflow) { - if (SAFMethod == SupplyAirFlowRate) { - if ((ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) && - ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || - (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) { - TempSize = ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow; - HeatingAirFlowSizer sizingHeatingAirFlow; - sizingHeatingAirFlow.overrideSizingString(SizingString); - // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound); - } else { - if (ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow > 0.0) { - HeatingAirFlowSizer sizingHeatingAirFlow; - sizingHeatingAirFlow.overrideSizingString(SizingString); - // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow, ErrorsFound); - } - } - } else if (SAFMethod == FlowPerFloorArea) { - ZoneEqSizing(CurZoneEqNum).SystemAirFlow = true; - ZoneEqSizing(CurZoneEqNum).AirVolFlow = ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow * Zone(DataZoneNumber).FloorArea; - TempSize = ZoneEqSizing(CurZoneEqNum).AirVolFlow; - DataScalableSizingON = true; + // PURPOSE OF THIS SUBROUTINE: + // This subroutine is for sizing Purchased Air Components for which flow rates have not been + // specified in the input. + + // METHODOLOGY EMPLOYED: + // Obtains flow rates from the zone sizing arrays. + + // Using/Aliasing + using namespace DataSizing; + using DataHeatBalance::Zone; + using DataHVACGlobals::CoolingCapacitySizing; + using DataHVACGlobals::HeatingAirflowSizing; + using DataHVACGlobals::HeatingCapacitySizing; + + using Psychrometrics::CPCW; + using Psychrometrics::CPHW; + using Psychrometrics::PsyCpAirFnW; + using Psychrometrics::PsyHFnTdbW; + using Psychrometrics::RhoH2O; + + // SUBROUTINE PARAMETER DEFINITIONS: + static std::string const RoutineName("SizePurchasedAir: "); // include trailing blank space + + // SUBROUTINE LOCAL VARIABLE DECLARATIONS: + bool IsAutoSize; // Indicator to autosize + Real64 MaxHeatVolFlowRateDes; // Autosized maximum heating air flow for reporting + Real64 MaxHeatVolFlowRateUser; // Hardsized maximum heating air flow for reporting + Real64 MaxCoolVolFlowRateDes; // Autosized maximum cooling air flow for reporting + Real64 MaxCoolVolFlowRateUser; // Hardsized maximum cooling air flow for reporting + Real64 MaxHeatSensCapDes; // Autosized maximum sensible heating capacity for reporting + Real64 MaxHeatSensCapUser; // Hardsized maximum sensible heating capacity for reporting + Real64 MaxCoolTotCapDes; // Autosized maximum sensible cooling capacity for reporting + Real64 MaxCoolTotCapUser; // Hardsized maximum sensible cooling capacity for reporting + std::string CompName; // component name + std::string CompType; // component type + std::string SizingString; // input field sizing description (e.g., Nominal Capacity) + Real64 TempSize; // autosized value of coil input field + int FieldNum = 2; // IDD numeric field number where input field description is found + int SizingMethod; // Integer representation of sizing method name (e.g., CoolingAirflowSizing, HeatingAirflowSizing, CoolingCapacitySizing, + // HeatingCapacitySizing, etc.) + bool PrintFlag; // TRUE when sizing information is reported in the eio file + int zoneHVACIndex; // index of zoneHVAC equipment sizing specification + int SAFMethod(0); // supply air flow rate sizing method (SupplyAirFlowRate, FlowPerFloorArea, FractionOfAutosizedCoolingAirflow, + // FractionOfAutosizedHeatingAirflow ...) + int CapSizingMethod(0); // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity, and + // FractionOfAutosizedHeatingCapacity ) + Real64 CoolingAirVolFlowDes(0.0); // cooling supply air flow rate + Real64 HeatingAirVolFlowDes(0.0); // heating supply air flow rate + + auto &PurchAir(state.dataPurchasedAirMgr->PurchAir); + + IsAutoSize = false; + MaxHeatVolFlowRateDes = 0.0; + MaxHeatVolFlowRateUser = 0.0; + MaxCoolVolFlowRateDes = 0.0; + MaxCoolVolFlowRateUser = 0.0; + MaxHeatSensCapDes = 0.0; + MaxHeatSensCapUser = 0.0; + MaxCoolTotCapDes = 0.0; + MaxCoolTotCapUser = 0.0; + + ZoneHeatingOnlyFan = false; + ZoneCoolingOnlyFan = false; + CompType = PurchAir(PurchAirNum).cObjectName; + CompName = PurchAir(PurchAirNum).Name; + bool ErrorsFound = false; + + if (CurZoneEqNum > 0) { + if (PurchAir(PurchAirNum).HVACSizingIndex > 0) { + DataZoneNumber = PurchAir(PurchAirNum).ZonePtr; + zoneHVACIndex = PurchAir(PurchAirNum).HVACSizingIndex; + + FieldNum = 5; // N5 , \field Maximum Heating Air Flow Rate + PrintFlag = true; + SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]"; + if (ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod > 0) { + SizingMethod = HeatingAirflowSizing; + ZoneHeatingOnlyFan = true; + SAFMethod = ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod; + ZoneEqSizing(CurZoneEqNum).SizingMethod(SizingMethod) = SAFMethod; + if (SAFMethod == SupplyAirFlowRate || SAFMethod == FlowPerFloorArea || SAFMethod == FractionOfAutosizedHeatingAirflow) { + if (SAFMethod == SupplyAirFlowRate) { + if ((ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) && + ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) { + TempSize = ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow; HeatingAirFlowSizer sizingHeatingAirFlow; sizingHeatingAirFlow.overrideSizingString(SizingString); // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound); - } else if (SAFMethod == FractionOfAutosizedHeatingAirflow) { - DataFracOfAutosizedHeatingAirflow = ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow; - if ((ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) && - ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || - (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) { - TempSize = AutoSize; - DataScalableSizingON = true; + } else { + if (ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow > 0.0) { HeatingAirFlowSizer sizingHeatingAirFlow; sizingHeatingAirFlow.overrideSizingString(SizingString); // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound); + HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow, ErrorsFound); } - - } else { - // Invalid sizing method } - } else if (SAFMethod == FlowPerHeatingCapacity) { - SizingMethod = HeatingCapacitySizing; - TempSize = AutoSize; - PrintFlag = false; + } else if (SAFMethod == FlowPerFloorArea) { + ZoneEqSizing(CurZoneEqNum).SystemAirFlow = true; + ZoneEqSizing(CurZoneEqNum).AirVolFlow = ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow * Zone(DataZoneNumber).FloorArea; + TempSize = ZoneEqSizing(CurZoneEqNum).AirVolFlow; + DataScalableSizingON = true; + HeatingAirFlowSizer sizingHeatingAirFlow; + sizingHeatingAirFlow.overrideSizingString(SizingString); + // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); + sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound); + } else if (SAFMethod == FractionOfAutosizedHeatingAirflow) { + DataFracOfAutosizedHeatingAirflow = ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow; if ((ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) && ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) { TempSize = AutoSize; DataScalableSizingON = true; - HeatingCapacitySizer sizerHeatingCapacity; - sizerHeatingCapacity.overrideSizingString(SizingString); - sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - DataAutosizedHeatingCapacity = sizerHeatingCapacity.size(state, TempSize, ErrorsFound); - DataFlowPerHeatingCapacity = ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow; - SizingMethod = HeatingAirflowSizing; - PrintFlag = true; - TempSize = AutoSize; HeatingAirFlowSizer sizingHeatingAirFlow; sizingHeatingAirFlow.overrideSizingString(SizingString); // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound); } - } - MaxHeatVolFlowRateDes = max(0.0, HeatingAirVolFlowDes); - PurchAir(PurchAirNum).MaxHeatVolFlowRate = MaxHeatVolFlowRateDes; - ZoneHeatingOnlyFan = false; - - CapSizingMethod = ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod; - ZoneEqSizing(CurZoneEqNum).CapSizingMethod = CapSizingMethod; - if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea || - CapSizingMethod == FractionOfAutosizedHeatingCapacity) { - if (CapSizingMethod == HeatingDesignCapacity) { - if (ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity > 0.0) { - ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true; - ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity; - } - TempSize = ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity; - } else if (CapSizingMethod == CapacityPerFloorArea) { - ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true; - ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = - ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity * Zone(DataZoneNumber).FloorArea; - DataScalableSizingON = true; - } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) { - DataFracOfAutosizedHeatingCapacity = ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity; - TempSize = AutoSize; - } - } - SizingMethod = HeatingCapacitySizing; - SizingString = ""; - ZoneHeatingOnlyFan = true; - PrintFlag = false; - HeatingCapacitySizer sizerHeatingCapacity; - sizerHeatingCapacity.overrideSizingString(SizingString); - sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - MaxHeatSensCapDes = sizerHeatingCapacity.size(state, TempSize, ErrorsFound); - ZoneHeatingOnlyFan = false; - if (MaxHeatSensCapDes < SmallLoad) { - MaxHeatSensCapDes = 0.0; - } - if (IsAutoSize) { - PurchAir(PurchAirNum).MaxHeatSensCap = MaxHeatSensCapDes; - BaseSizer::reportSizerOutput(state, PurchAir(PurchAirNum).cObjectName, - PurchAir(PurchAirNum).Name, - "Design Size Maximum Sensible Heating Capacity [W]", - MaxHeatSensCapDes); - // If there is OA, check if sizing calcs have OA>0, throw warning if not - if ((PurchAir(PurchAirNum).OutdoorAir) && (FinalZoneSizing(CurZoneEqNum).MinOA == 0.0)) { - ShowWarningError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); - ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this "); - ShowContinueError(state, "zone is zero. The Maximum Sensible Heating Capacity will be autosized for zero outdoor air flow. "); - ShowContinueError(state, "Check the outdoor air specifications in the Sizing:Zone object for zone " + - FinalZoneSizing(CurZoneEqNum).ZoneName + '.'); - } - } else { - if (PurchAir(PurchAirNum).MaxHeatSensCap > 0.0 && MaxHeatSensCapDes > 0.0) { - MaxHeatSensCapUser = PurchAir(PurchAirNum).MaxHeatSensCap; - BaseSizer::reportSizerOutput(state, PurchAir(PurchAirNum).cObjectName, - PurchAir(PurchAirNum).Name, - "Design Size Maximum Sensible Heating Capacity [W]", - MaxHeatSensCapDes, - "User-Specified Maximum Sensible Heating Capacity [W]", - MaxHeatSensCapUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(MaxHeatSensCapDes - MaxHeatSensCapUser) / MaxHeatSensCapUser) > AutoVsHardSizingThreshold) { - ShowMessage(state, "SizePurchasedAir: Potential issue with equipment sizing for " + PurchAir(PurchAirNum).cObjectName + - ' ' + PurchAir(PurchAirNum).Name); - ShowContinueError( - state, format("...User-Specified Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapUser)); - ShowContinueError( - state, - format("...differs from Design Size Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } - } - PrintFlag = true; - if (ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod > 0) { - ZoneCoolingOnlyFan = true; - SAFMethod = ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod; - ZoneEqSizing(CurZoneEqNum).SizingMethod(SizingMethod) = SAFMethod; - if (SAFMethod == SupplyAirFlowRate || SAFMethod == FlowPerFloorArea || SAFMethod == FractionOfAutosizedCoolingAirflow) { - if (SAFMethod == SupplyAirFlowRate) { - if ((ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) && - ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || - (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) || - (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) { - TempSize = ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow; - CoolingAirFlowSizer sizingCoolingAirFlow; - sizingCoolingAirFlow.overrideSizingString(SizingString); - sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound); - } else { - if (ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow > 0.0) { - CoolingAirVolFlowDes = ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow; - CoolingAirFlowSizer sizingCoolingAirFlow; - sizingCoolingAirFlow.overrideSizingString(SizingString); - sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, CoolingAirVolFlowDes, ErrorsFound); - } - } - } else if (SAFMethod == FlowPerFloorArea) { - ZoneEqSizing(CurZoneEqNum).SystemAirFlow = true; - ZoneEqSizing(CurZoneEqNum).AirVolFlow = ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow * Zone(DataZoneNumber).FloorArea; - TempSize = ZoneEqSizing(CurZoneEqNum).AirVolFlow; - DataScalableSizingON = true; - CoolingAirFlowSizer sizingCoolingAirFlow; - std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]"; - if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]"; - sizingCoolingAirFlow.overrideSizingString(stringOverride); - // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound); - } else if (SAFMethod == FractionOfAutosizedCoolingAirflow) { - if ((ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) && - ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || - (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) || - (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) { - DataFracOfAutosizedCoolingAirflow = ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow; - TempSize = AutoSize; - DataScalableSizingON = true; - CoolingAirFlowSizer sizingCoolingAirFlow; - std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]"; - if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]"; - sizingCoolingAirFlow.overrideSizingString(stringOverride); - // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound); - } - } else { - // Invalid scalable sizing method - } - } else if (SAFMethod == FlowPerCoolingCapacity) { - if ((ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) && - ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || - (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) || - (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) { - SizingMethod = CoolingCapacitySizing; - TempSize = AutoSize; - PrintFlag = false; - CoolingCapacitySizer sizerCoolingCapacity; - sizerCoolingCapacity.overrideSizingString(SizingString); - sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - DataAutosizedCoolingCapacity = sizerCoolingCapacity.size(state, TempSize, ErrorsFound); - DataFlowPerCoolingCapacity = ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow; - PrintFlag = true; - TempSize = AutoSize; - DataScalableSizingON = true; - CoolingAirFlowSizer sizingCoolingAirFlow; - std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]"; - if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]"; - sizingCoolingAirFlow.overrideSizingString(stringOverride); - // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound); - } - } - MaxCoolVolFlowRateDes = max(0.0, CoolingAirVolFlowDes); - PurchAir(PurchAirNum).MaxCoolVolFlowRate = MaxCoolVolFlowRateDes; - ZoneCoolingOnlyFan = false; - DataScalableSizingON = false; - - CapSizingMethod = ZoneHVACSizing(zoneHVACIndex).CoolingCapMethod; - ZoneEqSizing(CurZoneEqNum).CapSizingMethod = CapSizingMethod; - if (CapSizingMethod == CoolingDesignCapacity || CapSizingMethod == CapacityPerFloorArea || - CapSizingMethod == FractionOfAutosizedCoolingCapacity) { - if (CapSizingMethod == CoolingDesignCapacity) { - if (ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity > 0.0) { - ZoneEqSizing(CurZoneEqNum).CoolingCapacity = true; - ZoneEqSizing(CurZoneEqNum).DesCoolingLoad = ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity; - } else { - DataFlowUsedForSizing = FinalZoneSizing(CurZoneEqNum).DesCoolMassFlow; - } - TempSize = ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity; - } else if (CapSizingMethod == CapacityPerFloorArea) { - ZoneEqSizing(CurZoneEqNum).CoolingCapacity = true; - ZoneEqSizing(CurZoneEqNum).DesCoolingLoad = - ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity * Zone(DataZoneNumber).FloorArea; - DataScalableSizingON = true; - } else if (CapSizingMethod == FractionOfAutosizedCoolingCapacity) { - DataFracOfAutosizedHeatingCapacity = ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity; - DataFlowUsedForSizing = FinalZoneSizing(CurZoneEqNum).DesCoolMassFlow; - TempSize = AutoSize; - } - } - SizingMethod = CoolingCapacitySizing; - SizingString = ""; - ZoneCoolingOnlyFan = true; - PrintFlag = false; - TempSize = PurchAir(PurchAirNum).MaxCoolTotCap; - CoolingCapacitySizer sizerCoolingCapacity; - sizerCoolingCapacity.overrideSizingString(SizingString); - sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - MaxCoolTotCapDes = sizerCoolingCapacity.size(state, TempSize, ErrorsFound); - ZoneCoolingOnlyFan = false; - if (MaxCoolTotCapDes < SmallLoad) { - MaxCoolTotCapDes = 0.0; - } - if (IsAutoSize) { - PurchAir(PurchAirNum).MaxCoolTotCap = MaxCoolTotCapDes; - BaseSizer::reportSizerOutput(state, PurchAir(PurchAirNum).cObjectName, - PurchAir(PurchAirNum).Name, - "Design Size Maximum Total Cooling Capacity [W]", - MaxCoolTotCapDes); - // If there is OA, check if sizing calcs have OA>0, throw warning if not - if ((PurchAir(PurchAirNum).OutdoorAir) && (FinalZoneSizing(CurZoneEqNum).MinOA == 0.0)) { - ShowWarningError(state, "SizePurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); - ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this "); - ShowContinueError(state, "zone is zero. The Maximum Total Cooling Capacity will be autosized for zero outdoor air flow. "); - ShowContinueError(state, "Check the outdoor air specifications in the Sizing:Zone object for zone " + - FinalZoneSizing(CurZoneEqNum).ZoneName + '.'); - } } else { - if (PurchAir(PurchAirNum).MaxCoolTotCap > 0.0 && MaxCoolTotCapDes > 0.0) { - MaxCoolTotCapUser = PurchAir(PurchAirNum).MaxCoolTotCap; - BaseSizer::reportSizerOutput(state, PurchAir(PurchAirNum).cObjectName, - PurchAir(PurchAirNum).Name, - "Design Size Maximum Total Cooling Capacity [W]", - MaxCoolTotCapDes, - "User-Specified Maximum Total Cooling Capacity [W]", - MaxCoolTotCapUser); - if (state.dataGlobal->DisplayExtraWarnings) { - if ((std::abs(MaxCoolTotCapDes - MaxCoolTotCapUser) / MaxCoolTotCapUser) > AutoVsHardSizingThreshold) { - ShowMessage(state, "SizePurchasedAir: Potential issue with equipment sizing for " + PurchAir(PurchAirNum).cObjectName + - ' ' + PurchAir(PurchAirNum).Name); - ShowContinueError(state, - format("User-Specified Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapUser)); - ShowContinueError( - state, format("differs from Design Size Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapDes)); - ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); - ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); - } - } - } - } - } - - } else { - // SizingString = "Maximum Heating Air Flow Rate [m3/s]"; - SizingMethod = HeatingAirflowSizing; - FieldNum = 5; - SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]"; - IsAutoSize = false; - PrintFlag = true; - if ((PurchAir(PurchAirNum).MaxHeatVolFlowRate == AutoSize) && - ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) { - IsAutoSize = true; - } - if (!IsAutoSize && !ZoneSizingRunDone) { // Simulation continue - if (PurchAir(PurchAirNum).MaxHeatVolFlowRate > 0.0) { - HeatingAirFlowSizer sizingHeatingAirFlow; - sizingHeatingAirFlow.overrideSizingString(SizingString); - // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - PurchAir(PurchAirNum).MaxHeatVolFlowRate = sizingHeatingAirFlow.size(state, PurchAir(PurchAirNum).MaxHeatVolFlowRate, ErrorsFound); + // Invalid sizing method } - MaxHeatVolFlowRateDes = 0.0; - } else { - ZoneHeatingOnlyFan = true; - TempSize = PurchAir(PurchAirNum).MaxHeatVolFlowRate; - HeatingAirFlowSizer sizingHeatingAirFlow; - sizingHeatingAirFlow.overrideSizingString(SizingString); - // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - MaxHeatVolFlowRateDes = sizingHeatingAirFlow.size(state, PurchAir(PurchAirNum).MaxHeatVolFlowRate, ErrorsFound); - PurchAir(PurchAirNum).MaxHeatVolFlowRate = MaxHeatVolFlowRateDes; - ZoneHeatingOnlyFan = false; - } - - IsAutoSize = false; - SizingMethod = HeatingCapacitySizing; - FieldNum = 6; // N6, \field Maximum Sensible Heating Capacity - SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]"; - if ((PurchAir(PurchAirNum).MaxHeatSensCap == AutoSize) && - ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) || (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) { - IsAutoSize = true; - } - if (!IsAutoSize && !ZoneSizingRunDone) { // Simulation continue - if (PurchAir(PurchAirNum).MaxHeatSensCap > 0.0) { + } else if (SAFMethod == FlowPerHeatingCapacity) { + SizingMethod = HeatingCapacitySizing; + TempSize = AutoSize; + PrintFlag = false; + if ((ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) && + ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) { + TempSize = AutoSize; + DataScalableSizingON = true; HeatingCapacitySizer sizerHeatingCapacity; sizerHeatingCapacity.overrideSizingString(SizingString); sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - MaxHeatSensCapDes = sizerHeatingCapacity.size(state, PurchAir(PurchAirNum).MaxHeatSensCap, ErrorsFound); + DataAutosizedHeatingCapacity = sizerHeatingCapacity.size(state, TempSize, ErrorsFound); + DataFlowPerHeatingCapacity = ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow; + SizingMethod = HeatingAirflowSizing; + PrintFlag = true; + TempSize = AutoSize; + HeatingAirFlowSizer sizingHeatingAirFlow; + sizingHeatingAirFlow.overrideSizingString(SizingString); + // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); + sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound); + } + } + MaxHeatVolFlowRateDes = max(0.0, HeatingAirVolFlowDes); + PurchAir(PurchAirNum).MaxHeatVolFlowRate = MaxHeatVolFlowRateDes; + ZoneHeatingOnlyFan = false; + + CapSizingMethod = ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod; + ZoneEqSizing(CurZoneEqNum).CapSizingMethod = CapSizingMethod; + if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea || + CapSizingMethod == FractionOfAutosizedHeatingCapacity) { + if (CapSizingMethod == HeatingDesignCapacity) { + if (ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity > 0.0) { + ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true; + ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity; + } + TempSize = ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity; + } else if (CapSizingMethod == CapacityPerFloorArea) { + ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true; + ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = + ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity * Zone(DataZoneNumber).FloorArea; + DataScalableSizingON = true; + } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) { + DataFracOfAutosizedHeatingCapacity = ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity; + TempSize = AutoSize; } - } else { - TempSize = PurchAir(PurchAirNum).MaxHeatSensCap; - ZoneEqSizing(CurZoneEqNum).OAVolFlow = FinalZoneSizing(CurZoneEqNum).MinOA; - ZoneHeatingOnlyFan = true; - PrintFlag = false; - HeatingCapacitySizer sizerHeatingCapacity; - sizerHeatingCapacity.overrideSizingString(SizingString); - sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - MaxHeatSensCapDes = sizerHeatingCapacity.size(state, TempSize, ErrorsFound); - ZoneHeatingOnlyFan = false; } + SizingMethod = HeatingCapacitySizing; + SizingString = ""; + ZoneHeatingOnlyFan = true; + PrintFlag = false; + HeatingCapacitySizer sizerHeatingCapacity; + sizerHeatingCapacity.overrideSizingString(SizingString); + sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + MaxHeatSensCapDes = sizerHeatingCapacity.size(state, TempSize, ErrorsFound); + ZoneHeatingOnlyFan = false; if (MaxHeatSensCapDes < SmallLoad) { MaxHeatSensCapDes = 0.0; } if (IsAutoSize) { PurchAir(PurchAirNum).MaxHeatSensCap = MaxHeatSensCapDes; - BaseSizer::reportSizerOutput(state, PurchAir(PurchAirNum).cObjectName, + BaseSizer::reportSizerOutput(state, + PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name, "Design Size Maximum Sensible Heating Capacity [W]", MaxHeatSensCapDes); @@ -1758,13 +1617,15 @@ namespace EnergyPlus::PurchasedAirManager { ShowWarningError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this "); ShowContinueError(state, "zone is zero. The Maximum Sensible Heating Capacity will be autosized for zero outdoor air flow. "); - ShowContinueError(state, "Check the outdoor air specifications in the Sizing:Zone object for zone " + - FinalZoneSizing(CurZoneEqNum).ZoneName + '.'); + ShowContinueError(state, + "Check the outdoor air specifications in the Sizing:Zone object for zone " + + FinalZoneSizing(CurZoneEqNum).ZoneName + '.'); } } else { if (PurchAir(PurchAirNum).MaxHeatSensCap > 0.0 && MaxHeatSensCapDes > 0.0) { MaxHeatSensCapUser = PurchAir(PurchAirNum).MaxHeatSensCap; - BaseSizer::reportSizerOutput(state, PurchAir(PurchAirNum).cObjectName, + BaseSizer::reportSizerOutput(state, + PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name, "Design Size Maximum Sensible Heating Capacity [W]", MaxHeatSensCapDes, @@ -1772,8 +1633,9 @@ namespace EnergyPlus::PurchasedAirManager { MaxHeatSensCapUser); if (state.dataGlobal->DisplayExtraWarnings) { if ((std::abs(MaxHeatSensCapDes - MaxHeatSensCapUser) / MaxHeatSensCapUser) > AutoVsHardSizingThreshold) { - ShowMessage(state, "SizePurchasedAir: Potential issue with equipment sizing for " + PurchAir(PurchAirNum).cObjectName + ' ' + - PurchAir(PurchAirNum).Name); + ShowMessage(state, + "SizePurchasedAir: Potential issue with equipment sizing for " + PurchAir(PurchAirNum).cObjectName + ' ' + + PurchAir(PurchAirNum).Name); ShowContinueError(state, format("...User-Specified Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapUser)); ShowContinueError( @@ -1784,70 +1646,134 @@ namespace EnergyPlus::PurchasedAirManager { } } } + } - PrintFlag = true; - IsAutoSize = false; - if ((PurchAir(PurchAirNum).MaxCoolVolFlowRate == AutoSize) && - ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) || - (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) { - IsAutoSize = true; - } - if (!IsAutoSize && !ZoneSizingRunDone) { // Simulation continue - if (PurchAir(PurchAirNum).MaxCoolVolFlowRate > 0.0) { + PrintFlag = true; + if (ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod > 0) { + ZoneCoolingOnlyFan = true; + SAFMethod = ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod; + ZoneEqSizing(CurZoneEqNum).SizingMethod(SizingMethod) = SAFMethod; + if (SAFMethod == SupplyAirFlowRate || SAFMethod == FlowPerFloorArea || SAFMethod == FractionOfAutosizedCoolingAirflow) { + if (SAFMethod == SupplyAirFlowRate) { + if ((ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) && + ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) || + (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) { + TempSize = ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow; + CoolingAirFlowSizer sizingCoolingAirFlow; + sizingCoolingAirFlow.overrideSizingString(SizingString); + sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound); + } else { + if (ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow > 0.0) { + CoolingAirVolFlowDes = ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow; + CoolingAirFlowSizer sizingCoolingAirFlow; + sizingCoolingAirFlow.overrideSizingString(SizingString); + sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, CoolingAirVolFlowDes, ErrorsFound); + } + } + } else if (SAFMethod == FlowPerFloorArea) { + ZoneEqSizing(CurZoneEqNum).SystemAirFlow = true; + ZoneEqSizing(CurZoneEqNum).AirVolFlow = ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow * Zone(DataZoneNumber).FloorArea; + TempSize = ZoneEqSizing(CurZoneEqNum).AirVolFlow; + DataScalableSizingON = true; CoolingAirFlowSizer sizingCoolingAirFlow; std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]"; if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]"; sizingCoolingAirFlow.overrideSizingString(stringOverride); // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - PurchAir(PurchAirNum).MaxCoolVolFlowRate = sizingCoolingAirFlow.size(state, PurchAir(PurchAirNum).MaxCoolVolFlowRate, ErrorsFound); + CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound); + } else if (SAFMethod == FractionOfAutosizedCoolingAirflow) { + if ((ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) && + ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) || + (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) { + DataFracOfAutosizedCoolingAirflow = ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow; + TempSize = AutoSize; + DataScalableSizingON = true; + CoolingAirFlowSizer sizingCoolingAirFlow; + std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]"; + if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]"; + sizingCoolingAirFlow.overrideSizingString(stringOverride); + // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); + sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound); + } + } else { + // Invalid scalable sizing method } - } else { - ZoneCoolingOnlyFan = true; - TempSize = PurchAir(PurchAirNum).MaxCoolVolFlowRate; - CoolingAirFlowSizer sizingCoolingAirFlow; - std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]"; - if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]"; - sizingCoolingAirFlow.overrideSizingString(stringOverride); - // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); - sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - MaxCoolVolFlowRateDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound); - PurchAir(PurchAirNum).MaxCoolVolFlowRate = MaxCoolVolFlowRateDes; - ZoneCoolingOnlyFan = false; - } - - IsAutoSize = false; - SizingMethod = CoolingCapacitySizing; - FieldNum = 8; // N8, \field Maximum Total Cooling Capacity - SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]"; - if ((PurchAir(PurchAirNum).MaxCoolTotCap == AutoSize) && - ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity))) { - IsAutoSize = true; - } - if (!IsAutoSize && !ZoneSizingRunDone) { // Simulation continue - if (PurchAir(PurchAirNum).MaxCoolTotCap > 0.0) { + } else if (SAFMethod == FlowPerCoolingCapacity) { + if ((ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) && + ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) || + (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) { + SizingMethod = CoolingCapacitySizing; + TempSize = AutoSize; + PrintFlag = false; CoolingCapacitySizer sizerCoolingCapacity; sizerCoolingCapacity.overrideSizingString(SizingString); sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - PurchAir(PurchAirNum).MaxCoolTotCap = sizerCoolingCapacity.size(state, PurchAir(PurchAirNum).MaxCoolTotCap, ErrorsFound); + DataAutosizedCoolingCapacity = sizerCoolingCapacity.size(state, TempSize, ErrorsFound); + DataFlowPerCoolingCapacity = ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow; + PrintFlag = true; + TempSize = AutoSize; + DataScalableSizingON = true; + CoolingAirFlowSizer sizingCoolingAirFlow; + std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]"; + if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]"; + sizingCoolingAirFlow.overrideSizingString(stringOverride); + // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); + sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound); + } + } + MaxCoolVolFlowRateDes = max(0.0, CoolingAirVolFlowDes); + PurchAir(PurchAirNum).MaxCoolVolFlowRate = MaxCoolVolFlowRateDes; + ZoneCoolingOnlyFan = false; + DataScalableSizingON = false; + + CapSizingMethod = ZoneHVACSizing(zoneHVACIndex).CoolingCapMethod; + ZoneEqSizing(CurZoneEqNum).CapSizingMethod = CapSizingMethod; + if (CapSizingMethod == CoolingDesignCapacity || CapSizingMethod == CapacityPerFloorArea || + CapSizingMethod == FractionOfAutosizedCoolingCapacity) { + if (CapSizingMethod == CoolingDesignCapacity) { + if (ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity > 0.0) { + ZoneEqSizing(CurZoneEqNum).CoolingCapacity = true; + ZoneEqSizing(CurZoneEqNum).DesCoolingLoad = ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity; + } else { + DataFlowUsedForSizing = FinalZoneSizing(CurZoneEqNum).DesCoolMassFlow; + } + TempSize = ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity; + } else if (CapSizingMethod == CapacityPerFloorArea) { + ZoneEqSizing(CurZoneEqNum).CoolingCapacity = true; + ZoneEqSizing(CurZoneEqNum).DesCoolingLoad = + ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity * Zone(DataZoneNumber).FloorArea; + DataScalableSizingON = true; + } else if (CapSizingMethod == FractionOfAutosizedCoolingCapacity) { + DataFracOfAutosizedHeatingCapacity = ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity; + DataFlowUsedForSizing = FinalZoneSizing(CurZoneEqNum).DesCoolMassFlow; + TempSize = AutoSize; } - } else { - ZoneCoolingOnlyFan = true; - ZoneEqSizing(CurZoneEqNum).OAVolFlow = FinalZoneSizing(CurZoneEqNum).MinOA; - PrintFlag = false; - TempSize = PurchAir(PurchAirNum).MaxCoolTotCap; - CoolingCapacitySizer sizerCoolingCapacity; - sizerCoolingCapacity.overrideSizingString(SizingString); - sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); - MaxCoolTotCapDes = sizerCoolingCapacity.size(state, TempSize, ErrorsFound); - ZoneCoolingOnlyFan = false; } + SizingMethod = CoolingCapacitySizing; + SizingString = ""; + ZoneCoolingOnlyFan = true; + PrintFlag = false; + TempSize = PurchAir(PurchAirNum).MaxCoolTotCap; + CoolingCapacitySizer sizerCoolingCapacity; + sizerCoolingCapacity.overrideSizingString(SizingString); + sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + MaxCoolTotCapDes = sizerCoolingCapacity.size(state, TempSize, ErrorsFound); + ZoneCoolingOnlyFan = false; if (MaxCoolTotCapDes < SmallLoad) { MaxCoolTotCapDes = 0.0; } if (IsAutoSize) { PurchAir(PurchAirNum).MaxCoolTotCap = MaxCoolTotCapDes; - BaseSizer::reportSizerOutput(state, PurchAir(PurchAirNum).cObjectName, + BaseSizer::reportSizerOutput(state, + PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name, "Design Size Maximum Total Cooling Capacity [W]", MaxCoolTotCapDes); @@ -1856,13 +1782,15 @@ namespace EnergyPlus::PurchasedAirManager { ShowWarningError(state, "SizePurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this "); ShowContinueError(state, "zone is zero. The Maximum Total Cooling Capacity will be autosized for zero outdoor air flow. "); - ShowContinueError(state, "Check the outdoor air specifications in the Sizing:Zone object for zone " + - FinalZoneSizing(CurZoneEqNum).ZoneName + '.'); + ShowContinueError(state, + "Check the outdoor air specifications in the Sizing:Zone object for zone " + + FinalZoneSizing(CurZoneEqNum).ZoneName + '.'); } } else { if (PurchAir(PurchAirNum).MaxCoolTotCap > 0.0 && MaxCoolTotCapDes > 0.0) { MaxCoolTotCapUser = PurchAir(PurchAirNum).MaxCoolTotCap; - BaseSizer::reportSizerOutput(state, PurchAir(PurchAirNum).cObjectName, + BaseSizer::reportSizerOutput(state, + PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name, "Design Size Maximum Total Cooling Capacity [W]", MaxCoolTotCapDes, @@ -1870,8 +1798,9 @@ namespace EnergyPlus::PurchasedAirManager { MaxCoolTotCapUser); if (state.dataGlobal->DisplayExtraWarnings) { if ((std::abs(MaxCoolTotCapDes - MaxCoolTotCapUser) / MaxCoolTotCapUser) > AutoVsHardSizingThreshold) { - ShowMessage(state, "SizePurchasedAir: Potential issue with equipment sizing for " + PurchAir(PurchAirNum).cObjectName + ' ' + - PurchAir(PurchAirNum).Name); + ShowMessage(state, + "SizePurchasedAir: Potential issue with equipment sizing for " + PurchAir(PurchAirNum).cObjectName + ' ' + + PurchAir(PurchAirNum).Name); ShowContinueError(state, format("User-Specified Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapUser)); ShowContinueError(state, format("differs from Design Size Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapDes)); @@ -1882,836 +1811,1040 @@ namespace EnergyPlus::PurchasedAirManager { } } } - } - // IF (PurchAir(PurchAirNum)%OutdoorAir .AND. PurchAir(PurchAirNum)%OutsideAirVolFlowRate == AutoSize) THEN - // IF (CurZoneEqNum > 0) THEN - // CALL CheckZoneSizing(TRIM(PurchAir(PurchAirNum)%cObjectName), PurchAir(PurchAirNum)%Name) - // PurchAir(PurchAirNum)%OutsideAirVolFlowRate = FinalZoneSizing(CurZoneEqNum)%MinOA - // IF (PurchAir(PurchAirNum)%OutsideAirVolFlowRate < SmallAirVolFlow) THEN - // PurchAir(PurchAirNum)%OutsideAirVolFlowRate = 0.0 - // END IF - // CALL BaseSizer::reportSizerOutput(TRIM(PurchAir(PurchAirNum)%cObjectName), PurchAir(PurchAirNum)%Name, & - // 'Outdoor Air Flow Rate [m3/s]', PurchAir(PurchAirNum)%OutsideAirVolFlowRate ) - // END IF - // END IF - } + } else { + // SizingString = "Maximum Heating Air Flow Rate [m3/s]"; + SizingMethod = HeatingAirflowSizing; + FieldNum = 5; + SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]"; + IsAutoSize = false; + PrintFlag = true; + if ((PurchAir(PurchAirNum).MaxHeatVolFlowRate == AutoSize) && + ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) { + IsAutoSize = true; + } + if (!IsAutoSize && !ZoneSizingRunDone) { // Simulation continue + if (PurchAir(PurchAirNum).MaxHeatVolFlowRate > 0.0) { + HeatingAirFlowSizer sizingHeatingAirFlow; + sizingHeatingAirFlow.overrideSizingString(SizingString); + // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); + sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + PurchAir(PurchAirNum).MaxHeatVolFlowRate = + sizingHeatingAirFlow.size(state, PurchAir(PurchAirNum).MaxHeatVolFlowRate, ErrorsFound); + } + MaxHeatVolFlowRateDes = 0.0; + } else { + ZoneHeatingOnlyFan = true; + TempSize = PurchAir(PurchAirNum).MaxHeatVolFlowRate; + HeatingAirFlowSizer sizingHeatingAirFlow; + sizingHeatingAirFlow.overrideSizingString(SizingString); + // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); + sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + MaxHeatVolFlowRateDes = sizingHeatingAirFlow.size(state, PurchAir(PurchAirNum).MaxHeatVolFlowRate, ErrorsFound); + PurchAir(PurchAirNum).MaxHeatVolFlowRate = MaxHeatVolFlowRateDes; + ZoneHeatingOnlyFan = false; + } - void CalcPurchAirLoads(EnergyPlusData &state, int const PurchAirNum, - Real64 &SysOutputProvided, // Sensible output provided [W] cooling = negative - Real64 &MoistOutputProvided, // Moisture output provided [kg/s] dehumidification = negative - int const ControlledZoneNum, - int const ActualZoneNum) - { - - // SUBROUTINE INFORMATION: - // AUTHOR Russ Taylor - // DATE WRITTEN Nov 1997 - // MODIFIED Shirey, Aug 2009 (LatOutputProvided - now MoistOutputProvided) - // M. Witte June 2011, add new features including DCV, economizer, dehumidification - // and humidification, - // July 2012, Chandan Sharma - FSEC: Added hybrid ventilation manager - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // Needs description. - - // METHODOLOGY EMPLOYED: - // Needs description, as appropriate. - - // REFERENCES: - // na - - // Using/Aliasing - using DataHeatBalance::Zone; - using DataHeatBalFanSys::TempControlType; - using DataHVACGlobals::ForceOff; - using DataHVACGlobals::SmallLoad; - using DataHVACGlobals::ZoneComp; - using DataLoopNode::Node; - using DataZoneEquipment::PurchasedAir_Num; - - // SUBROUTINE PARAMETER DEFINITIONS: - static std::string const RoutineName("CalcPurchAirLoads"); - - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - int InNodeNum; // Ideal loads supply node to zone - // INTEGER :: ExhNodeNum ! Ideal loads exhaust node from zone - int ZoneNodeNum; // Zone air node - int OANodeNum; // Outdoor air inlet node - int RecircNodeNum; // Return air or zone exhaust node - OpMode OperatingMode; // current operating mode, Off, Heat, Cool, or DeadBand - Real64 SupplyMassFlowRate; // System supply air mass flow rate [kg/s] - Real64 SupplyMassFlowRateForHumid; // System supply air mass flow rate required to meet humdification load [kg/s] - Real64 SupplyMassFlowRateForDehum; // System supply air mass flow rate required to meet dehumidification load [kg/s] - Real64 SupplyMassFlowRateForCool; // System supply air mass flow rate required to meet sensible cooling load[kg/s] - Real64 SupplyMassFlowRateForHeat; // System supply air mass flow rate required to meet sensible heating load[kg/s] - Real64 SupplyHumRatForHumid; // Supply air humidity ratio require to meet the humidification load [kgWater/kgDryAir] - Real64 SupplyHumRatForDehum; // Supply air humidity ratio require to meet the dehumidification load [kgWater/kgDryAir] - Real64 OAMassFlowRate; // Outdoor air mass flow rate [kg/s] - Real64 OAVolFlowRate; // Outdoor air volume flow rate at standard density [m3/s] - Real64 MinOASensOutput; // Minimum Outdoor air sensible output [W], <0 means OA is cooler than zone air - Real64 MinOALatOutput; // Minimum Outdoor air moisture load [kg/s] - Real64 SensOutput; // Sensible output [W] (psitive means heating, negative means cooling) - Real64 HeatSensOutput; // Heating sensible output [W] - Real64 CoolSensOutput; // Cooling sensible output [W] (positive value menas cooling) - Real64 LatOutput; // Latent output [W] (positive value means hudmification, negative means dehumidification) - Real64 CoolLatOutput; // Cooling latent output [W] (positive value means dehumidification) - Real64 CoolTotOutput; // Cooling total output [W] (positive value means cooling) - Real64 DeltaT; // Delta temperature - reused in multiple places - Real64 DeltaHumRat; // Delta humidity ratio - reused in multiple places - Real64 QZnHeatSP; // Load required to meet heating setpoint [W] (>0 is a heating load) - Real64 QZnCoolSP; // Load required to meet cooling setpoint [W] (<0 is a cooling load) - Real64 MdotZnHumidSP; // Load required to meet humidifying setpoint [kgWater/s] (>0 = a humidify load) - Real64 MdotZnDehumidSP; // Load required to meet dehumidifying setpoint [kgWater/s] (<0 = a dehumidify load) - bool UnitOn; - bool HeatOn; // Flag for heating and humidification availbility schedule, true if heating is on - bool CoolOn; // Flag for cooling and dehumidification availbility schedule, true if cooling is on - bool EconoOn; // Flag for economizer operation, true if economizer is on - Real64 SupplyTemp; // Supply inlet to zone dry bulb temperature [C] - Real64 SupplyHumRat; // Supply inlet to zone humidity ratio [kgWater/kgDryAir] - Real64 SupplyHumRatOrig; // Supply inlet to zone humidity ratio before saturation check [kgWater/kgDryAir] - Real64 SupplyHumRatSat; // Supply inlet to zone humidity ratio saturation at SupplyTemp [kgWater/kgDryAir] - Real64 SupplyEnthalpy; // Supply inlet to zone enthalpy [J/kg] - Real64 MixedAirTemp; // Mixed air dry bulb temperature [C] - Real64 MixedAirHumRat; // Mixed air humidity ratio [kgWater/kgDryAir] - Real64 MixedAirEnthalpy; // Mixed air enthalpy [J/kg] - Real64 CpAir; // Specific heat [J/kg-C] reused in multiple places - // REAL(r64) :: SpecHumOut ! Specific humidity ratio of outlet air (kg moisture / kg moist air) - // REAL(r64) :: SpecHumIn ! Specific humidity ratio of inlet [zone] air (kg moisture / kg moist air) - - auto & PurchAir(state.dataPurchasedAirMgr->PurchAir); - - // Sign convention: SysOutputProvided <0 Supply air is heated on entering zone (zone is cooled) - // SysOutputProvided >0 Supply air is cooled on entering zone (zone is heated) - InNodeNum = PurchAir(PurchAirNum).ZoneSupplyAirNodeNum; - ZoneNodeNum = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode; - OANodeNum = PurchAir(PurchAirNum).OutdoorAirNodeNum; - RecircNodeNum = PurchAir(PurchAirNum).ZoneRecircAirNodeNum; - SupplyMassFlowRate = 0.0; - OAMassFlowRate = 0.0; - PurchAir(PurchAirNum).MinOAMassFlowRate = 0.0; - PurchAir(PurchAirNum).TimeEconoActive = 0.0; - PurchAir(PurchAirNum).TimeHtRecActive = 0.0; - SysOutputProvided = 0.0; - MoistOutputProvided = 0.0; - CoolSensOutput = 0.0; - CoolLatOutput = 0.0; - CoolTotOutput = 0.0; - HeatSensOutput = 0.0; - LatOutput = 0.0; + IsAutoSize = false; + SizingMethod = HeatingCapacitySizing; + FieldNum = 6; // N6, \field Maximum Sensible Heating Capacity + SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]"; + if ((PurchAir(PurchAirNum).MaxHeatSensCap == AutoSize) && ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) || + (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) { + IsAutoSize = true; + } + if (!IsAutoSize && !ZoneSizingRunDone) { // Simulation continue + if (PurchAir(PurchAirNum).MaxHeatSensCap > 0.0) { + HeatingCapacitySizer sizerHeatingCapacity; + sizerHeatingCapacity.overrideSizingString(SizingString); + sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + MaxHeatSensCapDes = sizerHeatingCapacity.size(state, PurchAir(PurchAirNum).MaxHeatSensCap, ErrorsFound); + } + } else { + TempSize = PurchAir(PurchAirNum).MaxHeatSensCap; + ZoneEqSizing(CurZoneEqNum).OAVolFlow = FinalZoneSizing(CurZoneEqNum).MinOA; + ZoneHeatingOnlyFan = true; + PrintFlag = false; + HeatingCapacitySizer sizerHeatingCapacity; + sizerHeatingCapacity.overrideSizingString(SizingString); + sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + MaxHeatSensCapDes = sizerHeatingCapacity.size(state, TempSize, ErrorsFound); + ZoneHeatingOnlyFan = false; + } + if (MaxHeatSensCapDes < SmallLoad) { + MaxHeatSensCapDes = 0.0; + } + if (IsAutoSize) { + PurchAir(PurchAirNum).MaxHeatSensCap = MaxHeatSensCapDes; + BaseSizer::reportSizerOutput(state, + PurchAir(PurchAirNum).cObjectName, + PurchAir(PurchAirNum).Name, + "Design Size Maximum Sensible Heating Capacity [W]", + MaxHeatSensCapDes); + // If there is OA, check if sizing calcs have OA>0, throw warning if not + if ((PurchAir(PurchAirNum).OutdoorAir) && (FinalZoneSizing(CurZoneEqNum).MinOA == 0.0)) { + ShowWarningError(state, "InitPurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); + ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this "); + ShowContinueError(state, "zone is zero. The Maximum Sensible Heating Capacity will be autosized for zero outdoor air flow. "); + ShowContinueError(state, + "Check the outdoor air specifications in the Sizing:Zone object for zone " + + FinalZoneSizing(CurZoneEqNum).ZoneName + '.'); + } + } else { + if (PurchAir(PurchAirNum).MaxHeatSensCap > 0.0 && MaxHeatSensCapDes > 0.0) { + MaxHeatSensCapUser = PurchAir(PurchAirNum).MaxHeatSensCap; + BaseSizer::reportSizerOutput(state, + PurchAir(PurchAirNum).cObjectName, + PurchAir(PurchAirNum).Name, + "Design Size Maximum Sensible Heating Capacity [W]", + MaxHeatSensCapDes, + "User-Specified Maximum Sensible Heating Capacity [W]", + MaxHeatSensCapUser); + if (state.dataGlobal->DisplayExtraWarnings) { + if ((std::abs(MaxHeatSensCapDes - MaxHeatSensCapUser) / MaxHeatSensCapUser) > AutoVsHardSizingThreshold) { + ShowMessage(state, + "SizePurchasedAir: Potential issue with equipment sizing for " + PurchAir(PurchAirNum).cObjectName + ' ' + + PurchAir(PurchAirNum).Name); + ShowContinueError(state, format("...User-Specified Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapUser)); + ShowContinueError( + state, format("...differs from Design Size Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapDes)); + ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); + ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); + } + } + } + } - // default unit to ON - UnitOn = true; - EconoOn = false; - // get current zone requirements - QZnHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).RemainingOutputReqToHeatSP; - QZnCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).RemainingOutputReqToCoolSP; - - if (allocated(ZoneComp)) { - ZoneComp(PurchasedAir_Num).ZoneCompAvailMgrs(PurchAirNum).ZoneNum = ActualZoneNum; - PurchAir(PurchAirNum).AvailStatus = ZoneComp(PurchasedAir_Num).ZoneCompAvailMgrs(PurchAirNum).AvailStatus; - // Check if the hybrid ventilation availability manager is turning the unit off - if (PurchAir(PurchAirNum).AvailStatus == ForceOff) { - UnitOn = false; + PrintFlag = true; + IsAutoSize = false; + if ((PurchAir(PurchAirNum).MaxCoolVolFlowRate == AutoSize) && + ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) || + (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) { + IsAutoSize = true; + } + if (!IsAutoSize && !ZoneSizingRunDone) { // Simulation continue + if (PurchAir(PurchAirNum).MaxCoolVolFlowRate > 0.0) { + CoolingAirFlowSizer sizingCoolingAirFlow; + std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]"; + if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]"; + sizingCoolingAirFlow.overrideSizingString(stringOverride); + // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); + sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + PurchAir(PurchAirNum).MaxCoolVolFlowRate = + sizingCoolingAirFlow.size(state, PurchAir(PurchAirNum).MaxCoolVolFlowRate, ErrorsFound); + } + } else { + ZoneCoolingOnlyFan = true; + TempSize = PurchAir(PurchAirNum).MaxCoolVolFlowRate; + CoolingAirFlowSizer sizingCoolingAirFlow; + std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]"; + if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]"; + sizingCoolingAirFlow.overrideSizingString(stringOverride); + // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex); + sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + MaxCoolVolFlowRateDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound); + PurchAir(PurchAirNum).MaxCoolVolFlowRate = MaxCoolVolFlowRateDes; + ZoneCoolingOnlyFan = false; + } + + IsAutoSize = false; + SizingMethod = CoolingCapacitySizing; + FieldNum = 8; // N8, \field Maximum Total Cooling Capacity + SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]"; + if ((PurchAir(PurchAirNum).MaxCoolTotCap == AutoSize) && ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity))) { + IsAutoSize = true; + } + if (!IsAutoSize && !ZoneSizingRunDone) { // Simulation continue + if (PurchAir(PurchAirNum).MaxCoolTotCap > 0.0) { + CoolingCapacitySizer sizerCoolingCapacity; + sizerCoolingCapacity.overrideSizingString(SizingString); + sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + PurchAir(PurchAirNum).MaxCoolTotCap = sizerCoolingCapacity.size(state, PurchAir(PurchAirNum).MaxCoolTotCap, ErrorsFound); + } + } else { + ZoneCoolingOnlyFan = true; + ZoneEqSizing(CurZoneEqNum).OAVolFlow = FinalZoneSizing(CurZoneEqNum).MinOA; + PrintFlag = false; + TempSize = PurchAir(PurchAirNum).MaxCoolTotCap; + CoolingCapacitySizer sizerCoolingCapacity; + sizerCoolingCapacity.overrideSizingString(SizingString); + sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName); + MaxCoolTotCapDes = sizerCoolingCapacity.size(state, TempSize, ErrorsFound); + ZoneCoolingOnlyFan = false; + } + if (MaxCoolTotCapDes < SmallLoad) { + MaxCoolTotCapDes = 0.0; + } + if (IsAutoSize) { + PurchAir(PurchAirNum).MaxCoolTotCap = MaxCoolTotCapDes; + BaseSizer::reportSizerOutput(state, + PurchAir(PurchAirNum).cObjectName, + PurchAir(PurchAirNum).Name, + "Design Size Maximum Total Cooling Capacity [W]", + MaxCoolTotCapDes); + // If there is OA, check if sizing calcs have OA>0, throw warning if not + if ((PurchAir(PurchAirNum).OutdoorAir) && (FinalZoneSizing(CurZoneEqNum).MinOA == 0.0)) { + ShowWarningError(state, "SizePurchasedAir: In " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name); + ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this "); + ShowContinueError(state, "zone is zero. The Maximum Total Cooling Capacity will be autosized for zero outdoor air flow. "); + ShowContinueError(state, + "Check the outdoor air specifications in the Sizing:Zone object for zone " + + FinalZoneSizing(CurZoneEqNum).ZoneName + '.'); + } + } else { + if (PurchAir(PurchAirNum).MaxCoolTotCap > 0.0 && MaxCoolTotCapDes > 0.0) { + MaxCoolTotCapUser = PurchAir(PurchAirNum).MaxCoolTotCap; + BaseSizer::reportSizerOutput(state, + PurchAir(PurchAirNum).cObjectName, + PurchAir(PurchAirNum).Name, + "Design Size Maximum Total Cooling Capacity [W]", + MaxCoolTotCapDes, + "User-Specified Maximum Total Cooling Capacity [W]", + MaxCoolTotCapUser); + if (state.dataGlobal->DisplayExtraWarnings) { + if ((std::abs(MaxCoolTotCapDes - MaxCoolTotCapUser) / MaxCoolTotCapUser) > AutoVsHardSizingThreshold) { + ShowMessage(state, + "SizePurchasedAir: Potential issue with equipment sizing for " + PurchAir(PurchAirNum).cObjectName + ' ' + + PurchAir(PurchAirNum).Name); + ShowContinueError(state, format("User-Specified Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapUser)); + ShowContinueError(state, + format("differs from Design Size Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapDes)); + ShowContinueError(state, "This may, or may not, indicate mismatched component sizes."); + ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components."); + } + } + } } } + } - // Check if the unit is scheduled off - // IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN - if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) { + // IF (PurchAir(PurchAirNum)%OutdoorAir .AND. PurchAir(PurchAirNum)%OutsideAirVolFlowRate == AutoSize) THEN + // IF (CurZoneEqNum > 0) THEN + // CALL CheckZoneSizing(TRIM(PurchAir(PurchAirNum)%cObjectName), PurchAir(PurchAirNum)%Name) + // PurchAir(PurchAirNum)%OutsideAirVolFlowRate = FinalZoneSizing(CurZoneEqNum)%MinOA + // IF (PurchAir(PurchAirNum)%OutsideAirVolFlowRate < SmallAirVolFlow) THEN + // PurchAir(PurchAirNum)%OutsideAirVolFlowRate = 0.0 + // END IF + // CALL BaseSizer::reportSizerOutput(TRIM(PurchAir(PurchAirNum)%cObjectName), PurchAir(PurchAirNum)%Name, & + // 'Outdoor Air Flow Rate [m3/s]', PurchAir(PurchAirNum)%OutsideAirVolFlowRate ) + // END IF + // END IF +} + +void CalcPurchAirLoads(EnergyPlusData &state, + int const PurchAirNum, + Real64 &SysOutputProvided, // Sensible output provided [W] cooling = negative + Real64 &MoistOutputProvided, // Moisture output provided [kg/s] dehumidification = negative + int const ControlledZoneNum, + int const ActualZoneNum) +{ + + // SUBROUTINE INFORMATION: + // AUTHOR Russ Taylor + // DATE WRITTEN Nov 1997 + // MODIFIED Shirey, Aug 2009 (LatOutputProvided - now MoistOutputProvided) + // M. Witte June 2011, add new features including DCV, economizer, dehumidification + // and humidification, + // July 2012, Chandan Sharma - FSEC: Added hybrid ventilation manager + // RE-ENGINEERED na + + // PURPOSE OF THIS SUBROUTINE: + // Needs description. + + // METHODOLOGY EMPLOYED: + // Needs description, as appropriate. + + // REFERENCES: + // na + + // Using/Aliasing + using DataHeatBalance::Zone; + using DataHeatBalFanSys::TempControlType; + using DataHVACGlobals::ForceOff; + using DataHVACGlobals::SmallLoad; + using DataHVACGlobals::ZoneComp; + using DataLoopNode::Node; + using DataZoneEquipment::PurchasedAir_Num; + + // SUBROUTINE PARAMETER DEFINITIONS: + static std::string const RoutineName("CalcPurchAirLoads"); + + // SUBROUTINE LOCAL VARIABLE DECLARATIONS: + int InNodeNum; // Ideal loads supply node to zone + // INTEGER :: ExhNodeNum ! Ideal loads exhaust node from zone + int ZoneNodeNum; // Zone air node + int OANodeNum; // Outdoor air inlet node + int RecircNodeNum; // Return air or zone exhaust node + OpMode OperatingMode; // current operating mode, Off, Heat, Cool, or DeadBand + Real64 SupplyMassFlowRate; // System supply air mass flow rate [kg/s] + Real64 SupplyMassFlowRateForHumid; // System supply air mass flow rate required to meet humdification load [kg/s] + Real64 SupplyMassFlowRateForDehum; // System supply air mass flow rate required to meet dehumidification load [kg/s] + Real64 SupplyMassFlowRateForCool; // System supply air mass flow rate required to meet sensible cooling load[kg/s] + Real64 SupplyMassFlowRateForHeat; // System supply air mass flow rate required to meet sensible heating load[kg/s] + Real64 SupplyHumRatForHumid; // Supply air humidity ratio require to meet the humidification load [kgWater/kgDryAir] + Real64 SupplyHumRatForDehum; // Supply air humidity ratio require to meet the dehumidification load [kgWater/kgDryAir] + Real64 OAMassFlowRate; // Outdoor air mass flow rate [kg/s] + Real64 OAVolFlowRate; // Outdoor air volume flow rate at standard density [m3/s] + Real64 MinOASensOutput; // Minimum Outdoor air sensible output [W], <0 means OA is cooler than zone air + Real64 MinOALatOutput; // Minimum Outdoor air moisture load [kg/s] + Real64 SensOutput; // Sensible output [W] (psitive means heating, negative means cooling) + Real64 HeatSensOutput; // Heating sensible output [W] + Real64 CoolSensOutput; // Cooling sensible output [W] (positive value menas cooling) + Real64 LatOutput; // Latent output [W] (positive value means hudmification, negative means dehumidification) + Real64 CoolLatOutput; // Cooling latent output [W] (positive value means dehumidification) + Real64 CoolTotOutput; // Cooling total output [W] (positive value means cooling) + Real64 DeltaT; // Delta temperature - reused in multiple places + Real64 DeltaHumRat; // Delta humidity ratio - reused in multiple places + Real64 QZnHeatSP; // Load required to meet heating setpoint [W] (>0 is a heating load) + Real64 QZnCoolSP; // Load required to meet cooling setpoint [W] (<0 is a cooling load) + Real64 MdotZnHumidSP; // Load required to meet humidifying setpoint [kgWater/s] (>0 = a humidify load) + Real64 MdotZnDehumidSP; // Load required to meet dehumidifying setpoint [kgWater/s] (<0 = a dehumidify load) + bool UnitOn; + bool HeatOn; // Flag for heating and humidification availbility schedule, true if heating is on + bool CoolOn; // Flag for cooling and dehumidification availbility schedule, true if cooling is on + bool EconoOn; // Flag for economizer operation, true if economizer is on + Real64 SupplyHumRatOrig; // Supply inlet to zone humidity ratio before saturation check [kgWater/kgDryAir] + Real64 SupplyHumRatSat; // Supply inlet to zone humidity ratio saturation at SupplyTemp [kgWater/kgDryAir] + Real64 SupplyEnthalpy; // Supply inlet to zone enthalpy [J/kg] + Real64 MixedAirEnthalpy; // Mixed air enthalpy [J/kg] + Real64 CpAir; // Specific heat [J/kg-C] reused in multiple places + // REAL(r64) :: SpecHumOut ! Specific humidity ratio of outlet air (kg moisture / kg moist air) + // REAL(r64) :: SpecHumIn ! Specific humidity ratio of inlet [zone] air (kg moisture / kg moist air) + + auto &PurchAir(state.dataPurchasedAirMgr->PurchAir); + + // Sign convention: SysOutputProvided <0 Supply air is heated on entering zone (zone is cooled) + // SysOutputProvided >0 Supply air is cooled on entering zone (zone is heated) + InNodeNum = PurchAir(PurchAirNum).ZoneSupplyAirNodeNum; + ZoneNodeNum = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode; + OANodeNum = PurchAir(PurchAirNum).OutdoorAirNodeNum; + RecircNodeNum = PurchAir(PurchAirNum).ZoneRecircAirNodeNum; + SupplyMassFlowRate = 0.0; + OAMassFlowRate = 0.0; + PurchAir(PurchAirNum).MinOAMassFlowRate = 0.0; + PurchAir(PurchAirNum).TimeEconoActive = 0.0; + PurchAir(PurchAirNum).TimeHtRecActive = 0.0; + SysOutputProvided = 0.0; + MoistOutputProvided = 0.0; + CoolSensOutput = 0.0; + CoolLatOutput = 0.0; + CoolTotOutput = 0.0; + HeatSensOutput = 0.0; + LatOutput = 0.0; + + // default unit to ON + UnitOn = true; + EconoOn = false; + // get current zone requirements + QZnHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).RemainingOutputReqToHeatSP; + QZnCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).RemainingOutputReqToCoolSP; + + if (allocated(ZoneComp)) { + ZoneComp(PurchasedAir_Num).ZoneCompAvailMgrs(PurchAirNum).ZoneNum = ActualZoneNum; + PurchAir(PurchAirNum).AvailStatus = ZoneComp(PurchasedAir_Num).ZoneCompAvailMgrs(PurchAirNum).AvailStatus; + // Check if the hybrid ventilation availability manager is turning the unit off + if (PurchAir(PurchAirNum).AvailStatus == ForceOff) { UnitOn = false; } - // END IF - // Check if heating and cooling available - HeatOn = true; - // IF (PurchAir(PurchAirNum)%HeatSchedPtr > 0) THEN - if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).HeatSchedPtr) <= 0) { - HeatOn = false; - } - // END IF - CoolOn = true; - // IF (PurchAir(PurchAirNum)%CoolSchedPtr > 0) THEN - if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).CoolSchedPtr) <= 0) { - CoolOn = false; - } - // END IF - - if (UnitOn) { - // Calculate current minimum outdoor air flow rate based on design OA specifications and DCV or CO2 control - CalcPurchAirMinOAMassFlow(state, PurchAirNum, ActualZoneNum, OAMassFlowRate); + } - // EMS override point Purch air outdoor air massflow rate..... - if (PurchAir(PurchAirNum).EMSOverrideOAMdotOn) { - OAMassFlowRate = PurchAir(PurchAirNum).EMSValueOAMassFlowRate; - } + // Check if the unit is scheduled off + // IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN + if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) { + UnitOn = false; + } + // END IF + // Check if heating and cooling available + HeatOn = true; + // IF (PurchAir(PurchAirNum)%HeatSchedPtr > 0) THEN + if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).HeatSchedPtr) <= 0) { + HeatOn = false; + } + // END IF + CoolOn = true; + // IF (PurchAir(PurchAirNum)%CoolSchedPtr > 0) THEN + if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).CoolSchedPtr) <= 0) { + CoolOn = false; + } + // END IF - // Calculate minimum outdoor air sensible and latent load - if (PurchAir(PurchAirNum).OutdoorAir) { - CpAir = PsyCpAirFnW(Node(OANodeNum).HumRat); - MinOASensOutput = OAMassFlowRate * CpAir * (Node(OANodeNum).Temp - Node(ZoneNodeNum).Temp); - MinOALatOutput = OAMassFlowRate * (Node(OANodeNum).HumRat - Node(ZoneNodeNum).HumRat); - } else { - MinOASensOutput = 0.0; - MinOALatOutput = 0.0; - } - SupplyMassFlowRate = OAMassFlowRate; + if (UnitOn) { + // Calculate current minimum outdoor air flow rate based on design OA specifications and DCV or CO2 control + CalcPurchAirMinOAMassFlow(state, PurchAirNum, ActualZoneNum, OAMassFlowRate); - // Check if cooling of the supply air stream is required - - // Cooling operation - if ((MinOASensOutput >= QZnCoolSP) && (TempControlType(ActualZoneNum) != SingleHeatingSetPoint)) { - OperatingMode = OpMode::Cool; - // Calculate supply mass flow, temp and humidity with the following constraints: - // Min cooling supply temp - // Max total cooling capacity - // Max cooling airflow - // Min cooling supply humrat (and Max heating supply humrat) - // Min OA mass flow rate - - // Check if OA flow rate greater than max cooling airflow limit - if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) && - (OAMassFlowRate > PurchAir(PurchAirNum).MaxCoolMassFlowRate)) { - OAVolFlowRate = OAMassFlowRate / state.dataEnvrn->StdRhoAir; - if (PurchAir(PurchAirNum).OAFlowMaxCoolOutputError < 1) { - ++PurchAir(PurchAirNum).OAFlowMaxCoolOutputError; - ShowWarningError(state, - format("{} \"{}\" Requested outdoor air flow rate = {:.5T} [m3/s] exceeds limit.", - PurchAir(PurchAirNum).cObjectName, - PurchAir(PurchAirNum).Name, - OAVolFlowRate)); - ShowContinueError(state, - format(" Will be reduced to the Maximum Cooling Air Flow Rate = {:.5T} [m3/s]", - PurchAir(PurchAirNum).MaxCoolVolFlowRate)); - ShowContinueErrorTimeStamp(state, ""); - } else { - ShowRecurringWarningErrorAtEnd(state, - PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name + - "\" Requested outdoor air flow rate [m3/s] reduced to Maximum Cooling Air Flow Rate warning continues...", - PurchAir(PurchAirNum).OAFlowMaxCoolOutputIndex, - OAVolFlowRate); - } - OAMassFlowRate = PurchAir(PurchAirNum).MaxCoolMassFlowRate; + // EMS override point Purch air outdoor air massflow rate..... + if (PurchAir(PurchAirNum).EMSOverrideOAMdotOn) { + OAMassFlowRate = PurchAir(PurchAirNum).EMSValueOAMassFlowRate; + } + // Calculate minimum outdoor air sensible and latent load + if (PurchAir(PurchAirNum).OutdoorAir) { + CpAir = PsyCpAirFnW(Node(OANodeNum).HumRat); + MinOASensOutput = OAMassFlowRate * CpAir * (Node(OANodeNum).Temp - Node(ZoneNodeNum).Temp); + MinOALatOutput = OAMassFlowRate * (Node(OANodeNum).HumRat - Node(ZoneNodeNum).HumRat); + } else { + MinOASensOutput = 0.0; + MinOALatOutput = 0.0; + } + SupplyMassFlowRate = OAMassFlowRate; + + // Check if cooling of the supply air stream is required + + // Cooling operation + if ((MinOASensOutput >= QZnCoolSP) && (TempControlType(ActualZoneNum) != SingleHeatingSetPoint)) { + OperatingMode = OpMode::Cool; + // Calculate supply mass flow, temp and humidity with the following constraints: + // Min cooling supply temp + // Max total cooling capacity + // Max cooling airflow + // Min cooling supply humrat (and Max heating supply humrat) + // Min OA mass flow rate + + // Check if OA flow rate greater than max cooling airflow limit + if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) && + (OAMassFlowRate > PurchAir(PurchAirNum).MaxCoolMassFlowRate)) { + OAVolFlowRate = OAMassFlowRate / state.dataEnvrn->StdRhoAir; + if (PurchAir(PurchAirNum).OAFlowMaxCoolOutputError < 1) { + ++PurchAir(PurchAirNum).OAFlowMaxCoolOutputError; + ShowWarningError(state, + format("{} \"{}\" Requested outdoor air flow rate = {:.5T} [m3/s] exceeds limit.", + PurchAir(PurchAirNum).cObjectName, + PurchAir(PurchAirNum).Name, + OAVolFlowRate)); + ShowContinueError( + state, + format(" Will be reduced to the Maximum Cooling Air Flow Rate = {:.5T} [m3/s]", PurchAir(PurchAirNum).MaxCoolVolFlowRate)); + ShowContinueErrorTimeStamp(state, ""); } else { - // Model economizer - if (PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer) { - if (((PurchAir(PurchAirNum).EconomizerType == Econ::DifferentialDryBulb) && - (Node(OANodeNum).Temp < Node(PurchAir(PurchAirNum).ZoneRecircAirNodeNum).Temp)) || - ((PurchAir(PurchAirNum).EconomizerType == Econ::DifferentialEnthalpy) && - (Node(OANodeNum).Enthalpy < Node(PurchAir(PurchAirNum).ZoneRecircAirNodeNum).Enthalpy))) { - - // Calculate supply MassFlowRate based on sensible load but limit to Max Cooling Supply Air Flow Rate if specified - CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); - DeltaT = (Node(OANodeNum).Temp - Node(ZoneNodeNum).Temp); - if (DeltaT < -SmallTempDiff) { - SupplyMassFlowRate = QZnCoolSP / CpAir / DeltaT; - if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || - (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) && - (PurchAir(PurchAirNum).MaxCoolMassFlowRate > 0.0)) { - SupplyMassFlowRate = min(max(SupplyMassFlowRate, 0.0), PurchAir(PurchAirNum).MaxCoolMassFlowRate); - } - if (SupplyMassFlowRate > OAMassFlowRate) { - EconoOn = true; - OAMassFlowRate = SupplyMassFlowRate; - PurchAir(PurchAirNum).TimeEconoActive = TimeStepSys; - } + ShowRecurringWarningErrorAtEnd( + state, + PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name + + "\" Requested outdoor air flow rate [m3/s] reduced to Maximum Cooling Air Flow Rate warning continues...", + PurchAir(PurchAirNum).OAFlowMaxCoolOutputIndex, + OAVolFlowRate); + } + OAMassFlowRate = PurchAir(PurchAirNum).MaxCoolMassFlowRate; + + } else { + // Model economizer + if (PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer) { + if (((PurchAir(PurchAirNum).EconomizerType == Econ::DifferentialDryBulb) && + (Node(OANodeNum).Temp < Node(PurchAir(PurchAirNum).ZoneRecircAirNodeNum).Temp)) || + ((PurchAir(PurchAirNum).EconomizerType == Econ::DifferentialEnthalpy) && + (Node(OANodeNum).Enthalpy < Node(PurchAir(PurchAirNum).ZoneRecircAirNodeNum).Enthalpy))) { + + // Calculate supply MassFlowRate based on sensible load but limit to Max Cooling Supply Air Flow Rate if specified + CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); + DeltaT = (Node(OANodeNum).Temp - Node(ZoneNodeNum).Temp); + if (DeltaT < -SmallTempDiff) { + SupplyMassFlowRate = QZnCoolSP / CpAir / DeltaT; + if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) && + (PurchAir(PurchAirNum).MaxCoolMassFlowRate > 0.0)) { + SupplyMassFlowRate = min(max(SupplyMassFlowRate, 0.0), PurchAir(PurchAirNum).MaxCoolMassFlowRate); + } + if (SupplyMassFlowRate > OAMassFlowRate) { + EconoOn = true; + OAMassFlowRate = SupplyMassFlowRate; + PurchAir(PurchAirNum).TimeEconoActive = TimeStepSys; } } } } + } - // Determine supply mass flow rate - // Mass flow rate to meet sensible load, at Minimum Cooling Supply Air Temperature - SupplyMassFlowRateForCool = 0.0; - if (CoolOn) { - CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); - DeltaT = (PurchAir(PurchAirNum).MinCoolSuppAirTemp - Node(ZoneNodeNum).Temp); - if (DeltaT < -SmallTempDiff) { - SupplyMassFlowRateForCool = QZnCoolSP / CpAir / DeltaT; - } + // Determine supply mass flow rate + // Mass flow rate to meet sensible load, at Minimum Cooling Supply Air Temperature + SupplyMassFlowRateForCool = 0.0; + if (CoolOn) { + CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); + DeltaT = (PurchAir(PurchAirNum).MinCoolSuppAirTemp - Node(ZoneNodeNum).Temp); + if (DeltaT < -SmallTempDiff) { + SupplyMassFlowRateForCool = QZnCoolSP / CpAir / DeltaT; } + } - // Mass flow rate to meet dehumidification load, if applicable, at Minimum Cooling Supply Humidity Ratio - SupplyMassFlowRateForDehum = 0.0; - if (CoolOn) { - if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) { - MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToDehumidSP; - DeltaHumRat = (PurchAir(PurchAirNum).MinCoolSuppAirHumRat - Node(ZoneNodeNum).HumRat); - if ((DeltaHumRat < -SmallDeltaHumRat) && (MdotZnDehumidSP < 0.0)) { - SupplyMassFlowRateForDehum = MdotZnDehumidSP / DeltaHumRat; - } + // Mass flow rate to meet dehumidification load, if applicable, at Minimum Cooling Supply Humidity Ratio + SupplyMassFlowRateForDehum = 0.0; + if (CoolOn) { + if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) { + MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToDehumidSP; + DeltaHumRat = (PurchAir(PurchAirNum).MinCoolSuppAirHumRat - Node(ZoneNodeNum).HumRat); + if ((DeltaHumRat < -SmallDeltaHumRat) && (MdotZnDehumidSP < 0.0)) { + SupplyMassFlowRateForDehum = MdotZnDehumidSP / DeltaHumRat; } } + } - // Mass flow rate to meet humidification load, if applicable, at Maximum Heating Supply Humidity Ratio - // This section is the cooling section, so humidification should activate only if humidification control = humidistat - // and if dehumidification control = humidistat or none - SupplyMassFlowRateForHumid = 0.0; - if (HeatOn) { - if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) { - if ((PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) || (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::None)) { - MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToHumidSP; - DeltaHumRat = (PurchAir(PurchAirNum).MaxHeatSuppAirHumRat - Node(ZoneNodeNum).HumRat); - if ((DeltaHumRat > SmallDeltaHumRat) && (MdotZnHumidSP > 0.0)) { - SupplyMassFlowRateForHumid = MdotZnHumidSP / DeltaHumRat; - } + // Mass flow rate to meet humidification load, if applicable, at Maximum Heating Supply Humidity Ratio + // This section is the cooling section, so humidification should activate only if humidification control = humidistat + // and if dehumidification control = humidistat or none + SupplyMassFlowRateForHumid = 0.0; + if (HeatOn) { + if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) { + if ((PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) || + (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::None)) { + MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToHumidSP; + DeltaHumRat = (PurchAir(PurchAirNum).MaxHeatSuppAirHumRat - Node(ZoneNodeNum).HumRat); + if ((DeltaHumRat > SmallDeltaHumRat) && (MdotZnHumidSP > 0.0)) { + SupplyMassFlowRateForHumid = MdotZnHumidSP / DeltaHumRat; } } } + } - // If cooling capacity is limited to zero, SupplyMassFlowRate* should be set to zero - if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || - (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) && - (PurchAir(PurchAirNum).MaxCoolTotCap == 0)) { - SupplyMassFlowRateForCool = 0; - SupplyMassFlowRateForDehum = 0; - SupplyMassFlowRateForHumid = 0; - } - - // Supply mass flow is greatest of these, but limit to cooling max flow rate, if applicable - SupplyMassFlowRate = max(0.0, OAMassFlowRate, SupplyMassFlowRateForCool, SupplyMassFlowRateForDehum, SupplyMassFlowRateForHumid); - // EMS override point Purch air massflow rate..... but only if unit is on, i.e. SupplyMassFlowRate>0.0 - if (PurchAir(PurchAirNum).EMSOverrideMdotOn) { - SupplyMassFlowRate = PurchAir(PurchAirNum).EMSValueMassFlowRate; - OAMassFlowRate = min(OAMassFlowRate, SupplyMassFlowRate); - } - if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) && - (PurchAir(PurchAirNum).MaxCoolMassFlowRate > 0.0)) { - SupplyMassFlowRate = min(SupplyMassFlowRate, PurchAir(PurchAirNum).MaxCoolMassFlowRate); - } - - if (SupplyMassFlowRate <= VerySmallMassFlow) SupplyMassFlowRate = 0.0; - - // Calculate mixed air conditions - CalcPurchAirMixedAir(state, PurchAirNum, OAMassFlowRate, SupplyMassFlowRate, MixedAirTemp, MixedAirHumRat, MixedAirEnthalpy, OperatingMode); + // If cooling capacity is limited to zero, SupplyMassFlowRate* should be set to zero + if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) && + (PurchAir(PurchAirNum).MaxCoolTotCap == 0)) { + SupplyMassFlowRateForCool = 0; + SupplyMassFlowRateForDehum = 0; + SupplyMassFlowRateForHumid = 0; + } - // Calculate supply air conditions using final massflow rate, imposing capacity limits if specified - // If capacity limits are exceeded, keep massflow rate where it is and adjust supply temp - // In general, in the cooling section, don't let SupplyTemp be set to something that results in heating - if (SupplyMassFlowRate > 0.0) { - // Calculate supply temp at SupplyMassFlowRate and recheck limit on Minimum Cooling Supply Air Temperature - CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); - SupplyTemp = QZnCoolSP / (CpAir * SupplyMassFlowRate) + Node(ZoneNodeNum).Temp; - SupplyTemp = max(SupplyTemp, PurchAir(PurchAirNum).MinCoolSuppAirTemp); - // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp - SupplyTemp = min(SupplyTemp, MixedAirTemp); - SupplyHumRat = MixedAirHumRat; - SupplyEnthalpy = PsyHFnTdbW(SupplyTemp, SupplyHumRat); - - // Check sensible load vs max total cooling capacity, if specified, and adjust supply temp before applying humidity controls - // Will check again later, too - if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) { - CpAir = PsyCpAirFnW(MixedAirHumRat); - CoolSensOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy); - if (CoolSensOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) { - CoolSensOutput = PurchAir(PurchAirNum).MaxCoolTotCap; - SupplyEnthalpy = MixedAirEnthalpy - CoolSensOutput / SupplyMassFlowRate; - SupplyTemp = PsyTdbFnHW(SupplyEnthalpy, SupplyHumRat); - // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp - SupplyTemp = min(SupplyTemp, MixedAirTemp); - } // Capacity limit exceeded - } + // Supply mass flow is greatest of these, but limit to cooling max flow rate, if applicable + SupplyMassFlowRate = max(0.0, OAMassFlowRate, SupplyMassFlowRateForCool, SupplyMassFlowRateForDehum, SupplyMassFlowRateForHumid); + // EMS override point Purch air massflow rate..... but only if unit is on, i.e. SupplyMassFlowRate>0.0 + if (PurchAir(PurchAirNum).EMSOverrideMdotOn) { + SupplyMassFlowRate = PurchAir(PurchAirNum).EMSValueMassFlowRate; + OAMassFlowRate = min(OAMassFlowRate, SupplyMassFlowRate); + } + if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) && + (PurchAir(PurchAirNum).MaxCoolMassFlowRate > 0.0)) { + SupplyMassFlowRate = min(SupplyMassFlowRate, PurchAir(PurchAirNum).MaxCoolMassFlowRate); + } - // Set supply humidity ratio for cooling/dehumidification - SupplyHumRat = MixedAirHumRat; - { - auto const SELECT_CASE_var(PurchAir(PurchAirNum).DehumidCtrlType); - if (SELECT_CASE_var == HumControl::None) { - SupplyHumRat = MixedAirHumRat; - } else if (SELECT_CASE_var == HumControl::ConstantSensibleHeatRatio) { - // SHR = CoolSensOutput/CoolTotOutput - // CoolTotOutput = CoolSensOutput/SHR - CpAir = PsyCpAirFnW(MixedAirHumRat); - CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp); - CoolTotOutput = CoolSensOutput / PurchAir(PurchAirNum).CoolSHR; - SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate; - // Limit for overdrying (avoid Pysch errors which occur if SupplyEnthalpy is too low for SupplyTemp) - SupplyEnthalpy = max(SupplyEnthalpy, PsyHFnTdbW(SupplyTemp, 0.00001)); - SupplyHumRat = min(SupplyHumRat, PsyWFnTdbH(state, SupplyTemp, SupplyEnthalpy, RoutineName)); - // Apply min cooling humidity ratio limit - SupplyHumRat = max(SupplyHumRat, PurchAir(PurchAirNum).MinCoolSuppAirHumRat); - // But don't let it be higher than incoming MixedAirHumRat - SupplyHumRat = min(SupplyHumRat, MixedAirHumRat); - } else if (SELECT_CASE_var == HumControl::Humidistat) { - MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToDehumidSP; - SupplyHumRatForDehum = MdotZnDehumidSP / SupplyMassFlowRate + Node(ZoneNodeNum).HumRat; - SupplyHumRatForDehum = min(SupplyHumRatForDehum, PurchAir(PurchAirNum).MinCoolSuppAirHumRat); - SupplyHumRat = min(MixedAirHumRat, SupplyHumRatForDehum); - } else if (SELECT_CASE_var == HumControl::ConstantSupplyHumidityRatio) { - SupplyHumRat = PurchAir(PurchAirNum).MinCoolSuppAirHumRat; - } else { - SupplyHumRat = MixedAirHumRat; - } + if (SupplyMassFlowRate <= VerySmallMassFlow) SupplyMassFlowRate = 0.0; + + // Calculate mixed air conditions + CalcPurchAirMixedAir(state, + PurchAirNum, + OAMassFlowRate, + SupplyMassFlowRate, + PurchAir(PurchAirNum).MixedAirTemp, + PurchAir(PurchAirNum).MixedAirHumRat, + MixedAirEnthalpy, + OperatingMode); + + // Calculate supply air conditions using final massflow rate, imposing capacity limits if specified + // If capacity limits are exceeded, keep massflow rate where it is and adjust supply temp + // In general, in the cooling section, don't let SupplyTemp be set to something that results in heating + if (SupplyMassFlowRate > 0.0) { + // Calculate supply temp at SupplyMassFlowRate and recheck limit on Minimum Cooling Supply Air Temperature + CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); + PurchAir(PurchAirNum).SupplyTemp = QZnCoolSP / (CpAir * SupplyMassFlowRate) + Node(ZoneNodeNum).Temp; + PurchAir(PurchAirNum).SupplyTemp = max(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MinCoolSuppAirTemp); + // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp + PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp); + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; + SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat); + + // Check sensible load vs max total cooling capacity, if specified, and adjust supply temp before applying humidity controls + // Will check again later, too + if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) { + CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat); + CoolSensOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy); + if (CoolSensOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) { + CoolSensOutput = PurchAir(PurchAirNum).MaxCoolTotCap; + SupplyEnthalpy = MixedAirEnthalpy - CoolSensOutput / SupplyMassFlowRate; + PurchAir(PurchAirNum).SupplyTemp = PsyTdbFnHW(SupplyEnthalpy, PurchAir(PurchAirNum).SupplyHumRat); + // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp + PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp); + } // Capacity limit exceeded + } + + // Set supply humidity ratio for cooling/dehumidification + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; + { + auto const SELECT_CASE_var(PurchAir(PurchAirNum).DehumidCtrlType); + if (SELECT_CASE_var == HumControl::None) { + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; // Unnecessary line? + } else if (SELECT_CASE_var == HumControl::ConstantSensibleHeatRatio) { + // SHR = CoolSensOutput/CoolTotOutput + // CoolTotOutput = CoolSensOutput/SHR + CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat); + CoolSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp); + CoolTotOutput = CoolSensOutput / PurchAir(PurchAirNum).CoolSHR; + SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate; + // Limit for overdrying (avoid Pysch errors which occur if SupplyEnthalpy is too low for SupplyTemp) + SupplyEnthalpy = max(SupplyEnthalpy, PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, 0.00001)); + PurchAir(PurchAirNum).SupplyHumRat = + min(PurchAir(PurchAirNum).SupplyHumRat, PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName)); + // Apply min cooling humidity ratio limit + PurchAir(PurchAirNum).SupplyHumRat = max(PurchAir(PurchAirNum).SupplyHumRat, PurchAir(PurchAirNum).MinCoolSuppAirHumRat); + // But don't let it be higher than incoming MixedAirHumRat + PurchAir(PurchAirNum).SupplyHumRat = min(PurchAir(PurchAirNum).SupplyHumRat, PurchAir(PurchAirNum).MixedAirHumRat); + } else if (SELECT_CASE_var == HumControl::Humidistat) { + MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToDehumidSP; + SupplyHumRatForDehum = MdotZnDehumidSP / SupplyMassFlowRate + Node(ZoneNodeNum).HumRat; + SupplyHumRatForDehum = min(SupplyHumRatForDehum, PurchAir(PurchAirNum).MinCoolSuppAirHumRat); + PurchAir(PurchAirNum).SupplyHumRat = min(PurchAir(PurchAirNum).MixedAirHumRat, SupplyHumRatForDehum); + } else if (SELECT_CASE_var == HumControl::ConstantSupplyHumidityRatio) { + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MinCoolSuppAirHumRat; + } else { + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; } + } - // Check supply humidity ratio for humidification (SupplyHumRatForHum should always be < SupplyHumRatForDehum) - // This section is the cooling section, so humidification should activate only if humidification control = humidistat - // and if dehumidification control = humidistat or none - if (HeatOn) { - if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) { - if ((PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) || (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::None)) { - MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToHumidSP; - SupplyHumRatForHumid = MdotZnHumidSP / SupplyMassFlowRate + Node(ZoneNodeNum).HumRat; - SupplyHumRatForHumid = min(SupplyHumRatForHumid, PurchAir(PurchAirNum).MaxHeatSuppAirHumRat); - SupplyHumRat = max(SupplyHumRat, SupplyHumRatForHumid); - } + // Check supply humidity ratio for humidification (SupplyHumRatForHum should always be < SupplyHumRatForDehum) + // This section is the cooling section, so humidification should activate only if humidification control = humidistat + // and if dehumidification control = humidistat or none + if (HeatOn) { + if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) { + if ((PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) || + (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::None)) { + MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToHumidSP; + SupplyHumRatForHumid = MdotZnHumidSP / SupplyMassFlowRate + Node(ZoneNodeNum).HumRat; + SupplyHumRatForHumid = min(SupplyHumRatForHumid, PurchAir(PurchAirNum).MaxHeatSuppAirHumRat); + PurchAir(PurchAirNum).SupplyHumRat = max(PurchAir(PurchAirNum).SupplyHumRat, SupplyHumRatForHumid); } } + } + + // Limit supply humidity ratio to saturation at supply outlet temp - // Limit supply humidity ratio to saturation at supply outlet temp - SupplyHumRatOrig = SupplyHumRat; - SupplyHumRatSat = PsyWFnTdbRhPb(state, SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName); - SupplyHumRat = min(SupplyHumRatOrig, SupplyHumRatSat); - SupplyEnthalpy = PsyHFnTdbW(SupplyTemp, SupplyHumRat); - - // Check max total Cooling capacity, if specified - if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) { - // If dehumidifying, compare total cooling to the limit - if (SupplyHumRat < MixedAirHumRat) { // Dehumidifying - CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy); - if ((CoolTotOutput) > PurchAir(PurchAirNum).MaxCoolTotCap) { - CoolTotOutput = PurchAir(PurchAirNum).MaxCoolTotCap; - SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate; - // Adjust output based on dehumidification control type - { - auto const SELECT_CASE_var(PurchAir(PurchAirNum).DehumidCtrlType); - if (SELECT_CASE_var == HumControl::ConstantSensibleHeatRatio) { - // Adjust both supply temp and humidity ratio to maintain SHR - // SHR = CoolSensOutput/CoolTotOutput - // CoolSensOutput = SHR*CoolTotOutput - CpAir = PsyCpAirFnW(MixedAirHumRat); - CoolSensOutput = CoolTotOutput * PurchAir(PurchAirNum).CoolSHR; - SupplyTemp = MixedAirTemp - CoolSensOutput / (CpAir * SupplyMassFlowRate); + SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat; + SupplyHumRatSat = PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName); + PurchAir(PurchAirNum).SupplyHumRat = min(SupplyHumRatOrig, SupplyHumRatSat); + SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat); + + // Check max total Cooling capacity, if specified + if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) { + // If dehumidifying, compare total cooling to the limit + if (PurchAir(PurchAirNum).SupplyHumRat < PurchAir(PurchAirNum).MixedAirHumRat) { // Dehumidifying + CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy); + if ((CoolTotOutput) > PurchAir(PurchAirNum).MaxCoolTotCap) { + CoolTotOutput = PurchAir(PurchAirNum).MaxCoolTotCap; + SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate; + // Adjust output based on dehumidification control type + { + auto const SELECT_CASE_var(PurchAir(PurchAirNum).DehumidCtrlType); + if (SELECT_CASE_var == HumControl::ConstantSensibleHeatRatio) { + // Adjust both supply temp and humidity ratio to maintain SHR + // SHR = CoolSensOutput/CoolTotOutput + // CoolSensOutput = SHR*CoolTotOutput + CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat); + CoolSensOutput = CoolTotOutput * PurchAir(PurchAirNum).CoolSHR; + PurchAir(PurchAirNum).SupplyTemp = + PurchAir(PurchAirNum).MixedAirTemp - CoolSensOutput / (CpAir * SupplyMassFlowRate); + // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp + PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp); + // Limit for overdrying (avoid Pysch errors which occur if SupplyEnthalpy is too low for SupplyTemp) + SupplyEnthalpy = max(SupplyEnthalpy, PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, 0.00001)); + PurchAir(PurchAirNum).SupplyHumRat = + PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName); + } else if (SELECT_CASE_var == HumControl::Humidistat) { + // Keep supply temp and adjust humidity ratio to reduce load + PurchAir(PurchAirNum).SupplyHumRat = + PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName); + } else if ((SELECT_CASE_var == HumControl::None) || (SELECT_CASE_var == HumControl::ConstantSupplyHumidityRatio)) { + // Keep humidity ratio and adjust supply temp + // Check if latent output exceeds capacity + CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat); + CoolSensOutput = + SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp); + CoolLatOutput = CoolTotOutput - CoolSensOutput; + if (CoolLatOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) { + PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp; + PurchAir(PurchAirNum).SupplyHumRat = + PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName); + CoolLatOutput = PurchAir(PurchAirNum).MaxCoolTotCap; + } else { + PurchAir(PurchAirNum).SupplyTemp = PsyTdbFnHW(SupplyEnthalpy, PurchAir(PurchAirNum).SupplyHumRat); // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp - SupplyTemp = min(SupplyTemp, MixedAirTemp); - // Limit for overdrying (avoid Pysch errors which occur if SupplyEnthalpy is too low for SupplyTemp) - SupplyEnthalpy = max(SupplyEnthalpy, PsyHFnTdbW(SupplyTemp, 0.00001)); - SupplyHumRat = PsyWFnTdbH(state, SupplyTemp, SupplyEnthalpy, RoutineName); - } else if (SELECT_CASE_var == HumControl::Humidistat) { - // Keep supply temp and adjust humidity ratio to reduce load - SupplyHumRat = PsyWFnTdbH(state, SupplyTemp, SupplyEnthalpy, RoutineName); - } else if ((SELECT_CASE_var == HumControl::None) || (SELECT_CASE_var == HumControl::ConstantSupplyHumidityRatio)) { - // Keep humidity ratio and adjust supply temp - // Check if latent output exceeds capacity - CpAir = PsyCpAirFnW(MixedAirHumRat); - CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp); - CoolLatOutput = CoolTotOutput - CoolSensOutput; - if (CoolLatOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) { - SupplyTemp = MixedAirTemp; - SupplyHumRat = PsyWFnTdbH(state, SupplyTemp, SupplyEnthalpy, RoutineName); - CoolLatOutput = PurchAir(PurchAirNum).MaxCoolTotCap; - } else { - SupplyTemp = PsyTdbFnHW(SupplyEnthalpy, SupplyHumRat); - // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp - SupplyTemp = min(SupplyTemp, MixedAirTemp); - } + PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp); } } - // Limit supply humidity ratio to saturation at supply outlet temp - // If saturation exceeded, then honor capacity limit and set to dew point at supplyenthalpy - SupplyHumRatOrig = SupplyHumRat; - SupplyHumRatSat = PsyWFnTdbRhPb(state, SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName); - if (SupplyHumRatSat < SupplyHumRatOrig) { - SupplyTemp = PsyTsatFnHPb(state, SupplyEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName); - // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp - SupplyTemp = min(SupplyTemp, MixedAirTemp); - SupplyHumRat = PsyWFnTdbH(state, SupplyTemp, SupplyEnthalpy, RoutineName); - SupplyEnthalpy = PsyHFnTdbW(SupplyTemp, SupplyHumRat); - // CpAir = PsyCpAirFnW(MixedAirHumRat) - // CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp) - // CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy) - } - } // Capacity limit exceeded - } else { // Not dehumidifying - // If not dehumidifying, compare sensible cooling to the limit - // This section will only increase supply temp, so no need to recheck for super-saturation - CpAir = PsyCpAirFnW(MixedAirHumRat); - CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp); - if (CoolSensOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) { - CoolSensOutput = PurchAir(PurchAirNum).MaxCoolTotCap; - SupplyTemp = MixedAirTemp - CoolSensOutput / (SupplyMassFlowRate * CpAir); - } // Capacity limit exceeded - } // Dehumidifying or not - } // Capacity limit active - - } else { // SupplyMassFlowRate is zero - SupplyEnthalpy = MixedAirEnthalpy; - SupplyHumRat = MixedAirHumRat; - SupplyTemp = MixedAirTemp; - CoolSensOutput = 0.0; - CoolTotOutput = 0.0; - } - // Heating or no-load operation - } else { // Heating or no-load case - if ((MinOASensOutput < QZnHeatSP) && (TempControlType(ActualZoneNum) != SingleCoolingSetPoint)) { - OperatingMode = OpMode::Heat; - } else { // DeadBand mode shuts off heat recovery and economizer - OperatingMode = OpMode::DeadBand; - } - // Calculate supply mass flow, temp and humidity with the following constraints: - // Max heating supply temp - // Max sensible heating capacity - // Max heating airflow - // Max heating supply humrat (and Min cooling supply humrat) - // Min OA mass flow rate - - // Check if OA flow rate greater than max heating airflow limit - if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) && - (OAMassFlowRate > PurchAir(PurchAirNum).MaxHeatMassFlowRate)) { - OAVolFlowRate = OAMassFlowRate / state.dataEnvrn->StdRhoAir; - if (PurchAir(PurchAirNum).OAFlowMaxHeatOutputError < 1) { - ++PurchAir(PurchAirNum).OAFlowMaxHeatOutputError; - ShowWarningError(state, - format("{} \"{}\" Requested outdoor air flow rate = {:.5T} [m3/s] exceeds limit.", - PurchAir(PurchAirNum).cObjectName, - PurchAir(PurchAirNum).Name, - OAVolFlowRate)); - ShowContinueError(state, - format(" Will be reduced to the Maximum Heating Air Flow Rate = {:.5T} [m3/s]", - PurchAir(PurchAirNum).MaxHeatVolFlowRate)); - ShowContinueErrorTimeStamp(state, ""); - } else { - ShowRecurringWarningErrorAtEnd(state, - PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name + - "\" Requested outdoor air flow rate [m3/s] reduced to Maximum Heating Air Flow Rate warning continues...", - PurchAir(PurchAirNum).OAFlowMaxHeatOutputIndex, - OAVolFlowRate); - } - OAMassFlowRate = PurchAir(PurchAirNum).MaxHeatMassFlowRate; - } + } + // Limit supply humidity ratio to saturation at supply outlet temp + // If saturation exceeded, then honor capacity limit and set to dew point at supplyenthalpy + + SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat; + SupplyHumRatSat = PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName); + if (SupplyHumRatSat < SupplyHumRatOrig) { + PurchAir(PurchAirNum).SupplyTemp = PsyTsatFnHPb(state, SupplyEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName); + + // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp + PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp); + PurchAir(PurchAirNum).SupplyHumRat = PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName); + SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat); + // CpAir = PsyCpAirFnW(MixedAirHumRat) + // CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp) + // CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy) + } + } // Capacity limit exceeded + } else { // Not dehumidifying + // If not dehumidifying, compare sensible cooling to the limit + // This section will only increase supply temp, so no need to recheck for super-saturation + CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat); + CoolSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp); + if (CoolSensOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) { + CoolSensOutput = PurchAir(PurchAirNum).MaxCoolTotCap; + PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp - CoolSensOutput / (SupplyMassFlowRate * CpAir); + } // Capacity limit exceeded + } // Dehumidifying or not + } // Capacity limit active + + } else { // SupplyMassFlowRate is zero + SupplyEnthalpy = MixedAirEnthalpy; + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; + PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp; + CoolSensOutput = 0.0; + CoolTotOutput = 0.0; + } + // Heating or no-load operation + } else { // Heating or no-load case + if ((MinOASensOutput < QZnHeatSP) && (TempControlType(ActualZoneNum) != SingleCoolingSetPoint)) { + OperatingMode = OpMode::Heat; + } else { // DeadBand mode shuts off heat recovery and economizer + OperatingMode = OpMode::DeadBand; + } + // Calculate supply mass flow, temp and humidity with the following constraints: + // Max heating supply temp + // Max sensible heating capacity + // Max heating airflow + // Max heating supply humrat (and Min cooling supply humrat) + // Min OA mass flow rate + + // Check if OA flow rate greater than max heating airflow limit + if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) && + (OAMassFlowRate > PurchAir(PurchAirNum).MaxHeatMassFlowRate)) { + OAVolFlowRate = OAMassFlowRate / state.dataEnvrn->StdRhoAir; + if (PurchAir(PurchAirNum).OAFlowMaxHeatOutputError < 1) { + ++PurchAir(PurchAirNum).OAFlowMaxHeatOutputError; + ShowWarningError(state, + format("{} \"{}\" Requested outdoor air flow rate = {:.5T} [m3/s] exceeds limit.", + PurchAir(PurchAirNum).cObjectName, + PurchAir(PurchAirNum).Name, + OAVolFlowRate)); + ShowContinueError( + state, + format(" Will be reduced to the Maximum Heating Air Flow Rate = {:.5T} [m3/s]", PurchAir(PurchAirNum).MaxHeatVolFlowRate)); + ShowContinueErrorTimeStamp(state, ""); + } else { + ShowRecurringWarningErrorAtEnd( + state, + PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name + + "\" Requested outdoor air flow rate [m3/s] reduced to Maximum Heating Air Flow Rate warning continues...", + PurchAir(PurchAirNum).OAFlowMaxHeatOutputIndex, + OAVolFlowRate); + } + OAMassFlowRate = PurchAir(PurchAirNum).MaxHeatMassFlowRate; + } - SupplyMassFlowRate = OAMassFlowRate; + SupplyMassFlowRate = OAMassFlowRate; - // Determine supply mass flow rate - // Mass flow rate to meet sensible load, at Minimum Cooling Supply Air Temperature - SupplyMassFlowRateForHeat = 0.0; - if ((HeatOn) && (OperatingMode == OpMode::Heat)) { - CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); - DeltaT = (PurchAir(PurchAirNum).MaxHeatSuppAirTemp - Node(ZoneNodeNum).Temp); - if (DeltaT > SmallTempDiff) { - SupplyMassFlowRateForHeat = QZnHeatSP / CpAir / DeltaT; - } + // Determine supply mass flow rate + // Mass flow rate to meet sensible load, at Minimum Cooling Supply Air Temperature + SupplyMassFlowRateForHeat = 0.0; + if ((HeatOn) && (OperatingMode == OpMode::Heat)) { + CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); + DeltaT = (PurchAir(PurchAirNum).MaxHeatSuppAirTemp - Node(ZoneNodeNum).Temp); + if (DeltaT > SmallTempDiff) { + SupplyMassFlowRateForHeat = QZnHeatSP / CpAir / DeltaT; } + } - // Mass flow rate to meet dehumidification load, if applicable, at Minimum Cooling Supply Humidity Ratio - // This section is the heating/deadband section, so dehumidification should activate - // only if dehumidification control = humidistat - // and if humidification control = humidistat or none or if operating in deadband mode - SupplyMassFlowRateForDehum = 0.0; - if (CoolOn) { - if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) { - if ((PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) || (PurchAir(PurchAirNum).HumidCtrlType == HumControl::None) || - (OperatingMode == OpMode::DeadBand)) { - MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToDehumidSP; - DeltaHumRat = (PurchAir(PurchAirNum).MinCoolSuppAirHumRat - Node(ZoneNodeNum).HumRat); - if ((DeltaHumRat < -SmallDeltaHumRat) && (MdotZnDehumidSP < 0.0)) { - SupplyMassFlowRateForDehum = MdotZnDehumidSP / DeltaHumRat; - } + // Mass flow rate to meet dehumidification load, if applicable, at Minimum Cooling Supply Humidity Ratio + // This section is the heating/deadband section, so dehumidification should activate + // only if dehumidification control = humidistat + // and if humidification control = humidistat or none or if operating in deadband mode + SupplyMassFlowRateForDehum = 0.0; + if (CoolOn) { + if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) { + if ((PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) || + (PurchAir(PurchAirNum).HumidCtrlType == HumControl::None) || (OperatingMode == OpMode::DeadBand)) { + MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToDehumidSP; + DeltaHumRat = (PurchAir(PurchAirNum).MinCoolSuppAirHumRat - Node(ZoneNodeNum).HumRat); + if ((DeltaHumRat < -SmallDeltaHumRat) && (MdotZnDehumidSP < 0.0)) { + SupplyMassFlowRateForDehum = MdotZnDehumidSP / DeltaHumRat; } } } + } - // Mass flow rate to meet humidification load, if applicable, at Maximum Heating Supply Humidity Ratio - SupplyMassFlowRateForHumid = 0.0; - if (HeatOn) { - if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) { - MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToHumidSP; - DeltaHumRat = (PurchAir(PurchAirNum).MaxHeatSuppAirHumRat - Node(ZoneNodeNum).HumRat); - if ((DeltaHumRat > SmallDeltaHumRat) && (MdotZnHumidSP > 0.0)) { - SupplyMassFlowRateForHumid = MdotZnHumidSP / DeltaHumRat; - } + // Mass flow rate to meet humidification load, if applicable, at Maximum Heating Supply Humidity Ratio + SupplyMassFlowRateForHumid = 0.0; + if (HeatOn) { + if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) { + MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToHumidSP; + DeltaHumRat = (PurchAir(PurchAirNum).MaxHeatSuppAirHumRat - Node(ZoneNodeNum).HumRat); + if ((DeltaHumRat > SmallDeltaHumRat) && (MdotZnHumidSP > 0.0)) { + SupplyMassFlowRateForHumid = MdotZnHumidSP / DeltaHumRat; } } + } - // If heating capacity is limited to zero, SupplyMassFlowRate* should be set to zero - if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) || - (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) && - (PurchAir(PurchAirNum).MaxHeatSensCap == 0)) { - SupplyMassFlowRateForHeat = 0; - SupplyMassFlowRateForDehum = 0; - SupplyMassFlowRateForHumid = 0; - } + // If heating capacity is limited to zero, SupplyMassFlowRate* should be set to zero + if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) || + (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) && + (PurchAir(PurchAirNum).MaxHeatSensCap == 0)) { + SupplyMassFlowRateForHeat = 0; + SupplyMassFlowRateForDehum = 0; + SupplyMassFlowRateForHumid = 0; + } - // Supply mass flow is greatest of these, but limit to heating max flow rate, if applicable - SupplyMassFlowRate = max(0.0, OAMassFlowRate, SupplyMassFlowRateForHeat, SupplyMassFlowRateForDehum, SupplyMassFlowRateForHumid); - // EMS override point Purch air massflow rate..... but only if unit is on, i.e. SupplyMassFlowRate>0.0 - if (PurchAir(PurchAirNum).EMSOverrideMdotOn) { - SupplyMassFlowRate = PurchAir(PurchAirNum).EMSValueMassFlowRate; - OAMassFlowRate = min(OAMassFlowRate, SupplyMassFlowRate); - } - if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) && - (PurchAir(PurchAirNum).MaxHeatMassFlowRate > 0.0)) { - SupplyMassFlowRate = min(SupplyMassFlowRate, PurchAir(PurchAirNum).MaxHeatMassFlowRate); - } + // Supply mass flow is greatest of these, but limit to heating max flow rate, if applicable + SupplyMassFlowRate = max(0.0, OAMassFlowRate, SupplyMassFlowRateForHeat, SupplyMassFlowRateForDehum, SupplyMassFlowRateForHumid); + // EMS override point Purch air massflow rate..... but only if unit is on, i.e. SupplyMassFlowRate>0.0 + if (PurchAir(PurchAirNum).EMSOverrideMdotOn) { + SupplyMassFlowRate = PurchAir(PurchAirNum).EMSValueMassFlowRate; + OAMassFlowRate = min(OAMassFlowRate, SupplyMassFlowRate); + } + if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) || + (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) && + (PurchAir(PurchAirNum).MaxHeatMassFlowRate > 0.0)) { + SupplyMassFlowRate = min(SupplyMassFlowRate, PurchAir(PurchAirNum).MaxHeatMassFlowRate); + } - if (SupplyMassFlowRate <= VerySmallMassFlow) SupplyMassFlowRate = 0.0; + if (SupplyMassFlowRate <= VerySmallMassFlow) SupplyMassFlowRate = 0.0; - // Calculate mixed air conditions - CalcPurchAirMixedAir(state, PurchAirNum, OAMassFlowRate, SupplyMassFlowRate, MixedAirTemp, MixedAirHumRat, MixedAirEnthalpy, OperatingMode); + // Calculate mixed air conditions + CalcPurchAirMixedAir(state, + PurchAirNum, + OAMassFlowRate, + SupplyMassFlowRate, + PurchAir(PurchAirNum).MixedAirTemp, + PurchAir(PurchAirNum).MixedAirHumRat, + MixedAirEnthalpy, + OperatingMode); - // Calculate supply air conditions using final massflow rate, imposing capacity limits if specified - // If capacity limits are exceeded, keep massflow rate where it is and adjust supply temp - if (SupplyMassFlowRate > 0.0) { - if ((HeatOn) && (OperatingMode == OpMode::Heat)) { - // Calculate supply temp at SupplyMassFlowRate and check limit on Maximum Heating Supply Air Temperature - CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); - SupplyTemp = QZnHeatSP / (CpAir * SupplyMassFlowRate) + Node(ZoneNodeNum).Temp; - SupplyTemp = min(SupplyTemp, PurchAir(PurchAirNum).MaxHeatSuppAirTemp); - // This is the heating mode, so SupplyTemp can't be less than MixedAirTemp - SupplyTemp = max(SupplyTemp, MixedAirTemp); - // Check max heating capacity, if specified - if ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) || - (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) { - CpAir = PsyCpAirFnW(MixedAirHumRat); - HeatSensOutput = SupplyMassFlowRate * CpAir * (SupplyTemp - MixedAirTemp); - if (HeatSensOutput > PurchAir(PurchAirNum).MaxHeatSensCap) { - SupplyTemp = PurchAir(PurchAirNum).MaxHeatSensCap / (SupplyMassFlowRate * CpAir) + MixedAirTemp; - HeatSensOutput = PurchAir(PurchAirNum).MaxHeatSensCap; - } + // Calculate supply air conditions using final massflow rate, imposing capacity limits if specified + // If capacity limits are exceeded, keep massflow rate where it is and adjust supply temp + if (SupplyMassFlowRate > 0.0) { + if ((HeatOn) && (OperatingMode == OpMode::Heat)) { + // Calculate supply temp at SupplyMassFlowRate and check limit on Maximum Heating Supply Air Temperature + CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); + PurchAir(PurchAirNum).SupplyTemp = QZnHeatSP / (CpAir * SupplyMassFlowRate) + Node(ZoneNodeNum).Temp; + PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MaxHeatSuppAirTemp); + // This is the heating mode, so SupplyTemp can't be less than MixedAirTemp + PurchAir(PurchAirNum).SupplyTemp = max(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp); + // Check max heating capacity, if specified + if ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) || + (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) { + CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat); + HeatSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - PurchAir(PurchAirNum).MixedAirTemp); + if (HeatSensOutput > PurchAir(PurchAirNum).MaxHeatSensCap) { + PurchAir(PurchAirNum).SupplyTemp = + PurchAir(PurchAirNum).MaxHeatSensCap / (SupplyMassFlowRate * CpAir) + PurchAir(PurchAirNum).MixedAirTemp; + HeatSensOutput = PurchAir(PurchAirNum).MaxHeatSensCap; } - } else { // Heat is off or operating mode is deadband (i.e. don't do any heating) - SupplyTemp = MixedAirTemp; } + } else { // Heat is off or operating mode is deadband (i.e. don't do any heating) + PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp; + } - // Set supply humidity ratio first for heating/humidification - SupplyHumRat = MixedAirHumRat; - { - auto const SELECT_CASE_var(PurchAir(PurchAirNum).HumidCtrlType); - if (SELECT_CASE_var == HumControl::None) { - SupplyHumRat = MixedAirHumRat; - } else if (SELECT_CASE_var == HumControl::Humidistat) { - MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToHumidSP; - SupplyHumRatForHumid = MdotZnHumidSP / SupplyMassFlowRate + Node(ZoneNodeNum).HumRat; - SupplyHumRatForHumid = min(SupplyHumRatForHumid, PurchAir(PurchAirNum).MaxHeatSuppAirHumRat); - SupplyHumRat = max(SupplyHumRat, SupplyHumRatForHumid); - } else if (SELECT_CASE_var == HumControl::ConstantSupplyHumidityRatio) { - if (OperatingMode == OpMode::Heat) { - // If this results in dehumidification, must check cooling capacity limit - if (MixedAirHumRat > PurchAir(PurchAirNum).MaxHeatSuppAirHumRat) { - if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || - (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) { - SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat; - SupplyEnthalpy = PsyHFnTdbW(SupplyTemp, SupplyHumRat); - CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy); - CpAir = PsyCpAirFnW(MixedAirHumRat); - CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp); - CoolLatOutput = CoolTotOutput - CoolSensOutput; - if (CoolLatOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) { - CoolLatOutput = PurchAir(PurchAirNum).MaxCoolTotCap; - CoolTotOutput = CoolSensOutput + CoolLatOutput; - SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate; - SupplyHumRat = PsyWFnTdbH(state, SupplyTemp, SupplyEnthalpy, RoutineName); - } - } else { - SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat; + // Set supply humidity ratio first for heating/humidification + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; + { + auto const SELECT_CASE_var(PurchAir(PurchAirNum).HumidCtrlType); + if (SELECT_CASE_var == HumControl::None) { + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; + } else if (SELECT_CASE_var == HumControl::Humidistat) { + MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToHumidSP; + SupplyHumRatForHumid = MdotZnHumidSP / SupplyMassFlowRate + Node(ZoneNodeNum).HumRat; + SupplyHumRatForHumid = min(SupplyHumRatForHumid, PurchAir(PurchAirNum).MaxHeatSuppAirHumRat); + PurchAir(PurchAirNum).SupplyHumRat = max(PurchAir(PurchAirNum).SupplyHumRat, SupplyHumRatForHumid); + } else if (SELECT_CASE_var == HumControl::ConstantSupplyHumidityRatio) { + if (OperatingMode == OpMode::Heat) { + // If this results in dehumidification, must check cooling capacity limit + if (PurchAir(PurchAirNum).MixedAirHumRat > PurchAir(PurchAirNum).MaxHeatSuppAirHumRat) { + if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) { + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat; + SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat); + CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy); + CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat); + CoolSensOutput = + SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp); + CoolLatOutput = CoolTotOutput - CoolSensOutput; + if (CoolLatOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) { + CoolLatOutput = PurchAir(PurchAirNum).MaxCoolTotCap; + CoolTotOutput = CoolSensOutput + CoolLatOutput; + SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate; + PurchAir(PurchAirNum).SupplyHumRat = + PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName); } } else { - SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat; + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat; } } else { - SupplyHumRat = MixedAirHumRat; + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat; } } else { - SupplyHumRat = MixedAirHumRat; + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; } + } else { + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; } - SupplyEnthalpy = PsyHFnTdbW(SupplyTemp, SupplyHumRat); - - // Check supply humidity ratio for dehumidification (SupplyHumRatForHumid should always be < SupplyHumRatForDehum) - // This section is the heating/deadband section, so dehumidification should activate - // only if dehumidification control = humidistat - // and if humidification control = humidistat or none or if operating in deadband mode - if (CoolOn) { - if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) { - if ((PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) || (PurchAir(PurchAirNum).HumidCtrlType == HumControl::None) || - (OperatingMode == OpMode::DeadBand)) { - MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToDehumidSP; - SupplyHumRatForDehum = MdotZnDehumidSP / SupplyMassFlowRate + Node(ZoneNodeNum).HumRat; - SupplyHumRatForDehum = max(SupplyHumRatForDehum, PurchAir(PurchAirNum).MinCoolSuppAirHumRat); - SupplyHumRat = min(SupplyHumRat, SupplyHumRatForDehum); - SupplyEnthalpy = PsyHFnTdbW(SupplyTemp, SupplyHumRat); - if (SupplyHumRat < MixedAirHumRat) { - // At this point, the system is heating or deadband but dehumidifying, check max cooling cap limit - CpAir = PsyCpAirFnW(MixedAirHumRat); - SensOutput = SupplyMassFlowRate * CpAir * (SupplyTemp - MixedAirTemp); - LatOutput = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy) - SensOutput; - if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || - (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) { - if (LatOutput > PurchAir(PurchAirNum).MaxCoolTotCap) { - LatOutput = PurchAir(PurchAirNum).MaxCoolTotCap; - SupplyEnthalpy = MixedAirEnthalpy + (LatOutput + SensOutput) / SupplyMassFlowRate; - SupplyHumRat = PsyWFnTdbH(state, SupplyTemp, SupplyEnthalpy, RoutineName); - } + } + SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat); + + // Check supply humidity ratio for dehumidification (SupplyHumRatForHumid should always be < SupplyHumRatForDehum) + // This section is the heating/deadband section, so dehumidification should activate + // only if dehumidification control = humidistat + // and if humidification control = humidistat or none or if operating in deadband mode + if (CoolOn) { + if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) { + if ((PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) || + (PurchAir(PurchAirNum).HumidCtrlType == HumControl::None) || (OperatingMode == OpMode::DeadBand)) { + MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ActualZoneNum).RemainingOutputReqToDehumidSP; + SupplyHumRatForDehum = MdotZnDehumidSP / SupplyMassFlowRate + Node(ZoneNodeNum).HumRat; + SupplyHumRatForDehum = max(SupplyHumRatForDehum, PurchAir(PurchAirNum).MinCoolSuppAirHumRat); + PurchAir(PurchAirNum).SupplyHumRat = min(PurchAir(PurchAirNum).SupplyHumRat, SupplyHumRatForDehum); + SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat); + if (PurchAir(PurchAirNum).SupplyHumRat < PurchAir(PurchAirNum).MixedAirHumRat) { + // At this point, the system is heating or deadband but dehumidifying, check max cooling cap limit + CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat); + SensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - PurchAir(PurchAirNum).MixedAirTemp); + LatOutput = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy) - SensOutput; + if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) || + (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) { + if (LatOutput > PurchAir(PurchAirNum).MaxCoolTotCap) { + LatOutput = PurchAir(PurchAirNum).MaxCoolTotCap; + SupplyEnthalpy = MixedAirEnthalpy + (LatOutput + SensOutput) / SupplyMassFlowRate; + PurchAir(PurchAirNum).SupplyHumRat = + PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName); } } } } } - - // Limit supply humidity ratio to saturation at supply outlet temp - SupplyHumRatOrig = SupplyHumRat; - SupplyHumRat = min(SupplyHumRat, PsyWFnTdbRhPb(state, SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName)); - SupplyEnthalpy = PsyHFnTdbW(SupplyTemp, SupplyHumRat); - - } else { // SupplyMassFlowRate is zero - SupplyEnthalpy = MixedAirEnthalpy; - SupplyHumRat = MixedAirHumRat; - SupplyTemp = MixedAirTemp; - HeatSensOutput = 0.0; } - } // Cooling or heating required - - // EMS override point Purch air supply temp and humidty ratio ..... but only if unit is on, SupplyMassFlowRate>0.0 - if (PurchAir(PurchAirNum).EMSOverrideSupplyTempOn) { - SupplyTemp = PurchAir(PurchAirNum).EMSValueSupplyTemp; - } - if (PurchAir(PurchAirNum).EMSOverrideSupplyHumRatOn) { - SupplyHumRat = PurchAir(PurchAirNum).EMSValueSupplyHumRat; - } + // Limit supply humidity ratio to saturation at supply outlet temp - if (SupplyMassFlowRate > 0.0) { - PurchAir(PurchAirNum).FinalMixedAirTemp = MixedAirTemp; - PurchAir(PurchAirNum).FinalMixedAirHumRat = MixedAirHumRat; - // compute coil loads - if ((SupplyHumRat == MixedAirHumRat) && (SupplyTemp == MixedAirTemp)) { - // If no change in humrat or temp, then set loads to zero - PurchAir(PurchAirNum).SenCoilLoad = 0.0; - PurchAir(PurchAirNum).LatCoilLoad = 0.0; - } else if ((SupplyHumRat == MixedAirHumRat) && (SupplyTemp != MixedAirTemp)) { - // If no change in humrat, then set latent load to zero and use enthalpies to calculate sensible load - PurchAir(PurchAirNum).SenCoilLoad = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy); - PurchAir(PurchAirNum).LatCoilLoad = 0.0; - } else { - CpAir = PsyCpAirFnW(MixedAirHumRat); - PurchAir(PurchAirNum).SenCoilLoad = SupplyMassFlowRate * CpAir * (SupplyTemp - MixedAirTemp); - PurchAir(PurchAirNum).LatCoilLoad = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy) - PurchAir(PurchAirNum).SenCoilLoad; - } + SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat; + PurchAir(PurchAirNum).SupplyHumRat = + min(PurchAir(PurchAirNum).SupplyHumRat, + PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName)); + SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat); - // Apply heating and cooling availability schedules to sensible load - if (((PurchAir(PurchAirNum).SenCoilLoad > 0.0) && !HeatOn) || ((PurchAir(PurchAirNum).SenCoilLoad < 0.0) && !CoolOn)) { - // Coil is off - PurchAir(PurchAirNum).SenCoilLoad = 0.0; - SupplyTemp = MixedAirTemp; - } + } else { // SupplyMassFlowRate is zero + SupplyEnthalpy = MixedAirEnthalpy; + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; + PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp; + HeatSensOutput = 0.0; + } - // Apply heating and cooling availability schedules to latent load - if (((PurchAir(PurchAirNum).LatCoilLoad > 0.0) && !HeatOn) || ((PurchAir(PurchAirNum).LatCoilLoad < 0.0) && !CoolOn)) { - // Coil is off - PurchAir(PurchAirNum).LatCoilLoad = 0.0; - SupplyHumRat = MixedAirHumRat; - } + } // Cooling or heating required - // Double-check if saturation exceeded, then thow warning, shouldn't happen here, don't reset, just warn - SupplyHumRatOrig = SupplyHumRat; - SupplyHumRatSat = PsyWFnTdbRhPb(state, SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName); - DeltaHumRat = SupplyHumRatOrig - SupplyHumRatSat; - if (DeltaHumRat > SmallDeltaHumRat) { - if (PurchAir(PurchAirNum).SaturationOutputError < 1) { - ++PurchAir(PurchAirNum).SaturationOutputError; - ShowWarningError(state, - format("{} \"{}\" Supply humidity ratio = {:.5T} exceeds saturation limit {:.5T} [kgWater/kgDryAir]", - PurchAir(PurchAirNum).cObjectName, - PurchAir(PurchAirNum).Name, - SupplyHumRatOrig, - SupplyHumRatSat)); - ShowContinueError(state, " Simulation continuing . . . "); - ShowContinueErrorTimeStamp(state, ""); - } else { - ShowRecurringWarningErrorAtEnd(state, - PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name + - "\" Supply humidity ratio exceeds saturation limit warning continues, delta max/min [kgWater/kgDryAir]...", - PurchAir(PurchAirNum).SaturationOutputIndex, - DeltaHumRat, - DeltaHumRat); - } - } + // EMS override point Purch air supply temp and humidty ratio ..... but only if unit is on, SupplyMassFlowRate>0.0 + if (PurchAir(PurchAirNum).EMSOverrideSupplyTempOn) { + PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).EMSValueSupplyTemp; + } + if (PurchAir(PurchAirNum).EMSOverrideSupplyHumRatOn) { + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).EMSValueSupplyHumRat; + } - SupplyEnthalpy = PsyHFnTdbW(SupplyTemp, SupplyHumRat); + if (SupplyMassFlowRate > 0.0) { + // compute coil loads + if ((PurchAir(PurchAirNum).SupplyHumRat == PurchAir(PurchAirNum).MixedAirHumRat) && + (PurchAir(PurchAirNum).SupplyTemp == PurchAir(PurchAirNum).MixedAirTemp)) { + // If no change in humrat or temp, then set loads to zero + PurchAir(PurchAirNum).SenCoilLoad = 0.0; + PurchAir(PurchAirNum).LatCoilLoad = 0.0; + } else if ((PurchAir(PurchAirNum).SupplyHumRat == PurchAir(PurchAirNum).MixedAirHumRat) && + (PurchAir(PurchAirNum).SupplyTemp != PurchAir(PurchAirNum).MixedAirTemp)) { + // If no change in humrat, then set latent load to zero and use enthalpies to calculate sensible load + PurchAir(PurchAirNum).SenCoilLoad = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy); + PurchAir(PurchAirNum).LatCoilLoad = 0.0; + } else { + CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat); + PurchAir(PurchAirNum).SenCoilLoad = + SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - PurchAir(PurchAirNum).MixedAirTemp); + PurchAir(PurchAirNum).LatCoilLoad = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy) - PurchAir(PurchAirNum).SenCoilLoad; + } - CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); - SysOutputProvided = SupplyMassFlowRate * CpAir * (SupplyTemp - Node(ZoneNodeNum).Temp); - MoistOutputProvided = SupplyMassFlowRate * (SupplyHumRat - Node(ZoneNodeNum).HumRat); // Latent rate, kg/s + // Apply heating and cooling availability schedules to sensible load + if (((PurchAir(PurchAirNum).SenCoilLoad > 0.0) && !HeatOn) || ((PurchAir(PurchAirNum).SenCoilLoad < 0.0) && !CoolOn)) { + // Coil is off + PurchAir(PurchAirNum).SenCoilLoad = 0.0; + PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp; + } - PurchAir(PurchAirNum).SenOutputToZone = SysOutputProvided; - PurchAir(PurchAirNum).LatOutputToZone = - SupplyMassFlowRate * (SupplyEnthalpy - Node(ZoneNodeNum).Enthalpy) - PurchAir(PurchAirNum).SenOutputToZone; + // Apply heating and cooling availability schedules to latent load + if (((PurchAir(PurchAirNum).LatCoilLoad > 0.0) && !HeatOn) || ((PurchAir(PurchAirNum).LatCoilLoad < 0.0) && !CoolOn)) { + // Coil is off + PurchAir(PurchAirNum).LatCoilLoad = 0.0; + PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; + } - CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); - if (PurchAir(PurchAirNum).OutdoorAir) { - PurchAir(PurchAirNum).OASenOutput = OAMassFlowRate * CpAir * (Node(OANodeNum).Temp - Node(ZoneNodeNum).Temp); - PurchAir(PurchAirNum).OALatOutput = - OAMassFlowRate * (Node(OANodeNum).Enthalpy - Node(ZoneNodeNum).Enthalpy) - PurchAir(PurchAirNum).OASenOutput; + // Double-check if saturation exceeded, then thow warning, shouldn't happen here, don't reset, just warn + + SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat; + SupplyHumRatSat = PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName); + + DeltaHumRat = SupplyHumRatOrig - SupplyHumRatSat; + if (DeltaHumRat > SmallDeltaHumRat) { + if (PurchAir(PurchAirNum).SaturationOutputError < 1) { + ++PurchAir(PurchAirNum).SaturationOutputError; + ShowWarningError(state, + format("{} \"{}\" Supply humidity ratio = {:.5T} exceeds saturation limit {:.5T} [kgWater/kgDryAir]", + PurchAir(PurchAirNum).cObjectName, + PurchAir(PurchAirNum).Name, + SupplyHumRatOrig, + SupplyHumRatSat)); + ShowContinueError(state, " Simulation continuing . . . "); + ShowContinueErrorTimeStamp(state, ""); } else { - PurchAir(PurchAirNum).OASenOutput = 0.0; - PurchAir(PurchAirNum).OALatOutput = 0.0; - } - if (state.dataContaminantBalance->Contaminant.CO2Simulation) { - if (PurchAir(PurchAirNum).OutdoorAir) { - Node(InNodeNum).CO2 = - ((SupplyMassFlowRate - OAMassFlowRate) * Node(RecircNodeNum).CO2 + OAMassFlowRate * Node(OANodeNum).CO2) / - SupplyMassFlowRate; - } else { - Node(InNodeNum).CO2 = Node(RecircNodeNum).CO2; - } - } - if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) { - if (PurchAir(PurchAirNum).OutdoorAir) { - Node(InNodeNum).GenContam = - ((SupplyMassFlowRate - OAMassFlowRate) * Node(RecircNodeNum).GenContam + OAMassFlowRate * Node(OANodeNum).GenContam) / - SupplyMassFlowRate; - } else { - Node(InNodeNum).GenContam = Node(RecircNodeNum).GenContam; - } - } - } else { // SupplyMassFlowRate = 0.0 - SysOutputProvided = 0.0; - MoistOutputProvided = 0.0; - - PurchAir(PurchAirNum).SenOutputToZone = 0.0; - PurchAir(PurchAirNum).LatOutputToZone = 0.0; - PurchAir(PurchAirNum).SenCoilLoad = 0.0; - PurchAir(PurchAirNum).LatCoilLoad = 0.0; - PurchAir(PurchAirNum).OASenOutput = 0.0; - PurchAir(PurchAirNum).OALatOutput = 0.0; - PurchAir(PurchAirNum).FinalMixedAirTemp = Node(RecircNodeNum).Temp; - PurchAir(PurchAirNum).FinalMixedAirHumRat = Node(RecircNodeNum).HumRat; - if (state.dataContaminantBalance->Contaminant.CO2Simulation) { - Node(InNodeNum).CO2 = Node(ZoneNodeNum).CO2; - } - if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) { - Node(InNodeNum).GenContam = Node(ZoneNodeNum).GenContam; + ShowRecurringWarningErrorAtEnd( + state, + PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name + + "\" Supply humidity ratio exceeds saturation limit warning continues, delta max/min [kgWater/kgDryAir]...", + PurchAir(PurchAirNum).SaturationOutputIndex, + DeltaHumRat, + DeltaHumRat); } } - Node(InNodeNum).Temp = SupplyTemp; - Node(InNodeNum).HumRat = SupplyHumRat; - Node(InNodeNum).Enthalpy = SupplyEnthalpy; - Node(InNodeNum).MassFlowRate = SupplyMassFlowRate; - if (PurchAir(PurchAirNum).OutdoorAir) Node(OANodeNum).MassFlowRate = OAMassFlowRate; + SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat); - } else { // purchased air OFF + CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); + SysOutputProvided = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - Node(ZoneNodeNum).Temp); + MoistOutputProvided = SupplyMassFlowRate * (PurchAir(PurchAirNum).SupplyHumRat - Node(ZoneNodeNum).HumRat); // Latent rate, kg/s - SysOutputProvided = 0.0; - MoistOutputProvided = 0.0; - SupplyMassFlowRate = 0.0; - OAMassFlowRate = 0.0; - Node(InNodeNum).Temp = Node(ZoneNodeNum).Temp; - Node(InNodeNum).HumRat = Node(ZoneNodeNum).HumRat; - Node(InNodeNum).Enthalpy = Node(ZoneNodeNum).Enthalpy; + PurchAir(PurchAirNum).SenOutputToZone = SysOutputProvided; + PurchAir(PurchAirNum).LatOutputToZone = + SupplyMassFlowRate * (SupplyEnthalpy - Node(ZoneNodeNum).Enthalpy) - PurchAir(PurchAirNum).SenOutputToZone; + + CpAir = PsyCpAirFnW(ZoneAirHumRat(ActualZoneNum)); + if (PurchAir(PurchAirNum).OutdoorAir) { + PurchAir(PurchAirNum).OASenOutput = OAMassFlowRate * CpAir * (Node(OANodeNum).Temp - Node(ZoneNodeNum).Temp); + PurchAir(PurchAirNum).OALatOutput = + OAMassFlowRate * (Node(OANodeNum).Enthalpy - Node(ZoneNodeNum).Enthalpy) - PurchAir(PurchAirNum).OASenOutput; + } else { + PurchAir(PurchAirNum).OASenOutput = 0.0; + PurchAir(PurchAirNum).OALatOutput = 0.0; + } if (state.dataContaminantBalance->Contaminant.CO2Simulation) { - Node(InNodeNum).CO2 = Node(ZoneNodeNum).CO2; + if (PurchAir(PurchAirNum).OutdoorAir) { + Node(InNodeNum).CO2 = + ((SupplyMassFlowRate - OAMassFlowRate) * Node(RecircNodeNum).CO2 + OAMassFlowRate * Node(OANodeNum).CO2) / SupplyMassFlowRate; + } else { + Node(InNodeNum).CO2 = Node(RecircNodeNum).CO2; + } } if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) { - Node(InNodeNum).GenContam = Node(ZoneNodeNum).GenContam; + if (PurchAir(PurchAirNum).OutdoorAir) { + Node(InNodeNum).GenContam = + ((SupplyMassFlowRate - OAMassFlowRate) * Node(RecircNodeNum).GenContam + OAMassFlowRate * Node(OANodeNum).GenContam) / + SupplyMassFlowRate; + } else { + Node(InNodeNum).GenContam = Node(RecircNodeNum).GenContam; + } } - - Node(InNodeNum).MassFlowRate = 0.0; - if (PurchAir(PurchAirNum).OutdoorAir) Node(OANodeNum).MassFlowRate = 0.0; - PurchAir(PurchAirNum).SenHeatRate = 0.0; - PurchAir(PurchAirNum).SenCoolRate = 0.0; - PurchAir(PurchAirNum).TotCoolRate = 0.0; + } else { // SupplyMassFlowRate = 0.0 + SysOutputProvided = 0.0; + MoistOutputProvided = 0.0; PurchAir(PurchAirNum).SenOutputToZone = 0.0; PurchAir(PurchAirNum).LatOutputToZone = 0.0; @@ -2719,707 +2852,768 @@ namespace EnergyPlus::PurchasedAirManager { PurchAir(PurchAirNum).LatCoilLoad = 0.0; PurchAir(PurchAirNum).OASenOutput = 0.0; PurchAir(PurchAirNum).OALatOutput = 0.0; - PurchAir(PurchAirNum).FinalMixedAirTemp = Node(RecircNodeNum).Temp; - PurchAir(PurchAirNum).FinalMixedAirHumRat = Node(RecircNodeNum).HumRat; - } - PurchAir(PurchAirNum).OutdoorAirMassFlowRate = OAMassFlowRate; - PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho = OAMassFlowRate / state.dataEnvrn->StdRhoAir; - PurchAir(PurchAirNum).SupplyAirMassFlowRate = SupplyMassFlowRate; - PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho = SupplyMassFlowRate / state.dataEnvrn->StdRhoAir; + PurchAir(PurchAirNum).MixedAirTemp = Node(RecircNodeNum).Temp; + PurchAir(PurchAirNum).MixedAirHumRat = Node(RecircNodeNum).HumRat; + if (state.dataContaminantBalance->Contaminant.CO2Simulation) { - if (PurchAir(PurchAirNum).PlenumExhaustAirNodeNum > 0) { - Node(PurchAir(PurchAirNum).PlenumExhaustAirNodeNum).MassFlowRate = SupplyMassFlowRate; + Node(InNodeNum).CO2 = Node(ZoneNodeNum).CO2; + } + if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) { + Node(InNodeNum).GenContam = Node(ZoneNodeNum).GenContam; + } } - Node(RecircNodeNum).MassFlowRate = SupplyMassFlowRate; - } - void CalcPurchAirMinOAMassFlow(EnergyPlusData &state, - int const PurchAirNum, // index to ideal loads unit - int const ActualZoneNum, // index to actual zone number - Real64 &OAMassFlowRate // outside air mass flow rate [kg/s] from volume flow using std density - ) - { + Node(InNodeNum).Temp = PurchAir(PurchAirNum).SupplyTemp; + Node(InNodeNum).HumRat = PurchAir(PurchAirNum).SupplyHumRat; + Node(InNodeNum).Enthalpy = SupplyEnthalpy; + Node(InNodeNum).MassFlowRate = SupplyMassFlowRate; + if (PurchAir(PurchAirNum).OutdoorAir) Node(OANodeNum).MassFlowRate = OAMassFlowRate; - // SUBROUTINE INFORMATION: - // AUTHOR M. Witte (GARD) - // DATE WRITTEN Jun 2011 (taken from HVACSingleDuctSystem.cc and adapted for Ideal Loads System) - // MODIFIED na - // RE-ENGINEERED na + } else { // purchased air OFF - // PURPOSE OF THIS SUBROUTINE: - // Calculates the amount of outside air required based on optional user input. - // Zone multipliers have been applied in GetInput. + SysOutputProvided = 0.0; + MoistOutputProvided = 0.0; + SupplyMassFlowRate = 0.0; + OAMassFlowRate = 0.0; + Node(InNodeNum).Temp = Node(ZoneNodeNum).Temp; + Node(InNodeNum).HumRat = Node(ZoneNodeNum).HumRat; + Node(InNodeNum).Enthalpy = Node(ZoneNodeNum).Enthalpy; + if (state.dataContaminantBalance->Contaminant.CO2Simulation) { + Node(InNodeNum).CO2 = Node(ZoneNodeNum).CO2; + } + if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) { + Node(InNodeNum).GenContam = Node(ZoneNodeNum).GenContam; + } - // METHODOLOGY EMPLOYED: - // User input defines method used to calculate OA. + Node(InNodeNum).MassFlowRate = 0.0; + if (PurchAir(PurchAirNum).OutdoorAir) Node(OANodeNum).MassFlowRate = 0.0; + PurchAir(PurchAirNum).SenHeatRate = 0.0; + PurchAir(PurchAirNum).SenCoolRate = 0.0; + PurchAir(PurchAirNum).TotCoolRate = 0.0; + + PurchAir(PurchAirNum).SenOutputToZone = 0.0; + PurchAir(PurchAirNum).LatOutputToZone = 0.0; + PurchAir(PurchAirNum).SenCoilLoad = 0.0; + PurchAir(PurchAirNum).LatCoilLoad = 0.0; + PurchAir(PurchAirNum).OASenOutput = 0.0; + PurchAir(PurchAirNum).OALatOutput = 0.0; + PurchAir(PurchAirNum).MixedAirTemp = Node(RecircNodeNum).Temp; + PurchAir(PurchAirNum).MixedAirHumRat = Node(RecircNodeNum).HumRat; + } - // REFERENCES: + PurchAir(PurchAirNum).OutdoorAirMassFlowRate = OAMassFlowRate; + PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho = OAMassFlowRate / state.dataEnvrn->StdRhoAir; + PurchAir(PurchAirNum).SupplyAirMassFlowRate = SupplyMassFlowRate; - // Using/Aliasing - using DataHeatBalance::Zone; - using DataZoneEquipment::CalcDesignSpecificationOutdoorAir; + PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho = SupplyMassFlowRate / state.dataEnvrn->StdRhoAir; - // Locals - // SUBROUTINE ARGUMENT DEFINITIONS: + if (PurchAir(PurchAirNum).PlenumExhaustAirNodeNum > 0) { + Node(PurchAir(PurchAirNum).PlenumExhaustAirNodeNum).MassFlowRate = SupplyMassFlowRate; + } + Node(RecircNodeNum).MassFlowRate = SupplyMassFlowRate; +} + +void CalcPurchAirMinOAMassFlow(EnergyPlusData &state, + int const PurchAirNum, // index to ideal loads unit + int const ActualZoneNum, // index to actual zone number + Real64 &OAMassFlowRate // outside air mass flow rate [kg/s] from volume flow using std density +) +{ + + // SUBROUTINE INFORMATION: + // AUTHOR M. Witte (GARD) + // DATE WRITTEN Jun 2011 (taken from HVACSingleDuctSystem.cc and adapted for Ideal Loads System) + // MODIFIED na + // RE-ENGINEERED na - // FUNCTION PARAMETER DEFINITIONS: - bool const UseMinOASchFlag(true); // Always use min OA schedule in calculations. + // PURPOSE OF THIS SUBROUTINE: + // Calculates the amount of outside air required based on optional user input. + // Zone multipliers have been applied in GetInput. - // FUNCTION LOCAL VARIABLE DECLARATIONS: - bool UseOccSchFlag; // TRUE = use actual occupancy, FALSE = use total zone people - Real64 OAVolumeFlowRate; // outside air flow rate (m3/s) + // METHODOLOGY EMPLOYED: + // User input defines method used to calculate OA. - auto & PurchAir(state.dataPurchasedAirMgr->PurchAir); + // REFERENCES: - if (PurchAir(PurchAirNum).OutdoorAir) { + // Using/Aliasing + using DataHeatBalance::Zone; + using DataZoneEquipment::CalcDesignSpecificationOutdoorAir; - if (PurchAir(PurchAirNum).DCVType == DCV::OccupancySchedule) { - UseOccSchFlag = true; - } else { - UseOccSchFlag = false; - } - OAVolumeFlowRate = - CalcDesignSpecificationOutdoorAir(state, PurchAir(PurchAirNum).OARequirementsPtr, ActualZoneNum, UseOccSchFlag, UseMinOASchFlag); - OAMassFlowRate = OAVolumeFlowRate * state.dataEnvrn->StdRhoAir; + // Locals + // SUBROUTINE ARGUMENT DEFINITIONS: - // If DCV with CO2SetPoint then check required OA flow to meet CO2 setpoint - if (PurchAir(PurchAirNum).DCVType == DCV::CO2SetPoint) { - OAMassFlowRate = max(OAMassFlowRate, state.dataContaminantBalance->ZoneSysContDemand(ActualZoneNum).OutputRequiredToCO2SP); - } + // FUNCTION PARAMETER DEFINITIONS: + bool const UseMinOASchFlag(true); // Always use min OA schedule in calculations. - if (OAMassFlowRate <= VerySmallMassFlow) OAMassFlowRate = 0.0; + // FUNCTION LOCAL VARIABLE DECLARATIONS: + bool UseOccSchFlag; // TRUE = use actual occupancy, FALSE = use total zone people + Real64 OAVolumeFlowRate; // outside air flow rate (m3/s) - } else { // No outdoor air - OAMassFlowRate = 0.0; - } - PurchAir(PurchAirNum).MinOAMassFlowRate = OAMassFlowRate; - } + auto &PurchAir(state.dataPurchasedAirMgr->PurchAir); - void CalcPurchAirMixedAir(EnergyPlusData &state, - int const PurchAirNum, // index to ideal loads unit - Real64 const OAMassFlowRate, // outside air mass flow rate [kg/s] - Real64 const SupplyMassFlowRate, // supply air mass flow rate [kg/s] - Real64 &MixedAirTemp, // Mixed air dry bulb temperature [C] - Real64 &MixedAirHumRat, // Mixed air humidity ratio [kgWater/kgDryAir] - Real64 &MixedAirEnthalpy, // Mixed air enthalpy [J/kg] - OpMode const OperatingMode // current operating mode, Off, Heating, Cooling, or DeadBand - ) - { - - // SUBROUTINE INFORMATION: - // AUTHOR M. Witte (GARD) - // DATE WRITTEN Sep 2011 - // MODIFIED na - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // Calculates the mixed air conditions, accounting for heat recovery. - - // METHODOLOGY EMPLOYED: - // na - - // REFERENCES: - - // Using/Aliasing - using DataLoopNode::Node; - - // Locals - // SUBROUTINE ARGUMENT DEFINITIONS: - - // SUBROUTINE PARAMETER DEFINITIONS: - static std::string const RoutineName("CalcPurchAirMixedAir"); - - // INTERFACE BLOCK SPECIFICATIONS - // na - - // DERIVED TYPE DEFINITIONS - // na - - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - int RecircNodeNum; // Zone return air node - int OANodeNum; // Outdoor air inlet node - Real64 RecircTemp; // Recirculated air from zone dry bulb temperature [C] - Real64 RecircHumRat; // Recirculated air from zone humidity ratio [kgWater/kgDryAir] - Real64 RecircEnthalpy; // Recirculated air from zone enthalpy [J/kg] - Real64 RecircMassFlowRate; // Recirculated air mass flow rate [kg/s] - Real64 OAInletTemp; // Outdoor air inlet dry bulb temperature [C] - Real64 OAInletHumRat; // Outdoor air inlet humidity ratio [kgWater/kgDryAir] - Real64 OAInletEnthalpy; // Outdoor air inlet enthalpy [J/kg] - Real64 OAAfterHtRecTemp; // Outdoor air after heat recovery to mixing box dry bulb temperature [C] - Real64 OAAfterHtRecHumRat; // Outdoor air after heat recovery to mixing box humidity ratio [kgWater/kgDryAir] - Real64 OAAfterHtRecEnthalpy; // Outdoor air after heat recovery to mixing box enthalpy [J/kg] - bool HeatRecOn; - Real64 CpAir; // Specific heat [J/kg-C] reused in multiple places - - auto & PurchAir(state.dataPurchasedAirMgr->PurchAir); - - // Initializations - OANodeNum = PurchAir(PurchAirNum).OutdoorAirNodeNum; - RecircNodeNum = PurchAir(PurchAirNum).ZoneRecircAirNodeNum; - - RecircMassFlowRate = 0.0; - RecircTemp = Node(RecircNodeNum).Temp; - RecircHumRat = Node(RecircNodeNum).HumRat; - RecircEnthalpy = Node(RecircNodeNum).Enthalpy; - if (PurchAir(PurchAirNum).OutdoorAir) { - OAInletTemp = Node(OANodeNum).Temp; - OAInletHumRat = Node(OANodeNum).HumRat; - OAInletEnthalpy = Node(OANodeNum).Enthalpy; - OAAfterHtRecTemp = OAInletTemp; - OAAfterHtRecHumRat = OAInletHumRat; - OAAfterHtRecEnthalpy = OAInletEnthalpy; + if (PurchAir(PurchAirNum).OutdoorAir) { + + if (PurchAir(PurchAirNum).DCVType == DCV::OccupancySchedule) { + UseOccSchFlag = true; } else { - OAInletTemp = 0.0; - OAInletHumRat = 0.0; - OAInletEnthalpy = 0.0; - OAAfterHtRecTemp = OAInletTemp; - OAAfterHtRecHumRat = OAInletHumRat; - OAAfterHtRecEnthalpy = OAInletEnthalpy; + UseOccSchFlag = false; } - HeatRecOn = false; - - if (PurchAir(PurchAirNum).OutdoorAir && (OAMassFlowRate > 0.0)) { - // Determine if heat recovery is beneficial - if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Sensible) { - if ((OperatingMode == OpMode::Heat) && (RecircTemp > OAInletTemp)) HeatRecOn = true; - if ((OperatingMode == OpMode::Cool) && (RecircTemp < OAInletTemp)) HeatRecOn = true; - } - if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Enthalpy) { - if ((OperatingMode == OpMode::Heat) && (RecircEnthalpy > OAInletEnthalpy)) HeatRecOn = true; - if ((OperatingMode == OpMode::Cool) && (RecircEnthalpy < OAInletEnthalpy)) HeatRecOn = true; - } - // Calculate heat recovery if active - if (HeatRecOn) { - PurchAir(PurchAirNum).TimeHtRecActive = TimeStepSys; - OAAfterHtRecTemp = OAInletTemp + PurchAir(PurchAirNum).HtRecSenEff * (RecircTemp - OAInletTemp); - if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Enthalpy) - OAAfterHtRecHumRat = OAInletHumRat + PurchAir(PurchAirNum).HtRecLatEff * (RecircHumRat - OAInletHumRat); - OAAfterHtRecEnthalpy = PsyHFnTdbW(OAAfterHtRecTemp, OAAfterHtRecHumRat); - // Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy - if (PsyTsatFnHPb(state, OAAfterHtRecEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName) > OAAfterHtRecTemp) { - OAAfterHtRecTemp = PsyTsatFnHPb(state, OAAfterHtRecEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName); - OAAfterHtRecHumRat = PsyWFnTdbH(state, OAAfterHtRecTemp, OAAfterHtRecEnthalpy, RoutineName); - } - } + OAVolumeFlowRate = + CalcDesignSpecificationOutdoorAir(state, PurchAir(PurchAirNum).OARequirementsPtr, ActualZoneNum, UseOccSchFlag, UseMinOASchFlag); + OAMassFlowRate = OAVolumeFlowRate * state.dataEnvrn->StdRhoAir; - if (SupplyMassFlowRate > OAMassFlowRate) { - RecircMassFlowRate = SupplyMassFlowRate - OAMassFlowRate; - MixedAirEnthalpy = (RecircMassFlowRate * Node(RecircNodeNum).Enthalpy + OAMassFlowRate * OAAfterHtRecEnthalpy) / SupplyMassFlowRate; - MixedAirHumRat = (RecircMassFlowRate * Node(RecircNodeNum).HumRat + OAMassFlowRate * OAAfterHtRecHumRat) / SupplyMassFlowRate; - // Mixed air temperature is calculated from the mixed air enthalpy and humidity ratio. - MixedAirTemp = PsyTdbFnHW(MixedAirEnthalpy, MixedAirHumRat); - } else { - RecircMassFlowRate = 0.0; - MixedAirEnthalpy = OAAfterHtRecEnthalpy; - MixedAirHumRat = OAAfterHtRecHumRat; - MixedAirTemp = OAAfterHtRecTemp; - } - - // Calculate OA and heat recovery sensible and latent rates - CpAir = PsyCpAirFnW(OAInletHumRat); - PurchAir(PurchAirNum).HtRecSenOutput = OAMassFlowRate * CpAir * (OAAfterHtRecTemp - OAInletTemp); - PurchAir(PurchAirNum).HtRecLatOutput = OAMassFlowRate * (OAAfterHtRecEnthalpy - OAInletEnthalpy) - PurchAir(PurchAirNum).HtRecSenOutput; - - } else { // No outdoor air - RecircMassFlowRate = SupplyMassFlowRate; - MixedAirTemp = RecircTemp; - MixedAirHumRat = RecircHumRat; - MixedAirEnthalpy = RecircEnthalpy; - PurchAir(PurchAirNum).HtRecSenOutput = 0.0; - PurchAir(PurchAirNum).HtRecLatOutput = 0.0; + // If DCV with CO2SetPoint then check required OA flow to meet CO2 setpoint + if (PurchAir(PurchAirNum).DCVType == DCV::CO2SetPoint) { + OAMassFlowRate = max(OAMassFlowRate, state.dataContaminantBalance->ZoneSysContDemand(ActualZoneNum).OutputRequiredToCO2SP); } - } - - void UpdatePurchasedAir(EnergyPlusData &state, int const PurchAirNum, bool const FirstHVACIteration) - { - - // SUBROUTINE INFORMATION: - // AUTHOR M. J. Witte - // DATE WRITTEN Sep 2011 - // MODIFIED R. Raustad, July 2017, added return plenum - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // Update node data for Ideal Loads (purchased air) system - - // USE STATEMENTS: - using ZonePlenum::SimAirZonePlenum; - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - // na - bool FirstCall; - bool SupPathInletChanged; + if (OAMassFlowRate <= VerySmallMassFlow) OAMassFlowRate = 0.0; - FirstCall = true; // just used to avoid redundant calulations - SupPathInletChanged = false; // don't care if something changes + } else { // No outdoor air + OAMassFlowRate = 0.0; + } + PurchAir(PurchAirNum).MinOAMassFlowRate = OAMassFlowRate; +} + +void CalcPurchAirMixedAir(EnergyPlusData &state, + int const PurchAirNum, // index to ideal loads unit + Real64 const OAMassFlowRate, // outside air mass flow rate [kg/s] + Real64 const SupplyMassFlowRate, // supply air mass flow rate [kg/s] + Real64 &MixedAirTemp, // Mixed air dry bulb temperature [C] + Real64 &MixedAirHumRat, // Mixed air humidity ratio [kgWater/kgDryAir] + Real64 &MixedAirEnthalpy, // Mixed air enthalpy [J/kg] + OpMode const OperatingMode // current operating mode, Off, Heating, Cooling, or DeadBand +) +{ + + // SUBROUTINE INFORMATION: + // AUTHOR M. Witte (GARD) + // DATE WRITTEN Sep 2011 + // MODIFIED na + // RE-ENGINEERED na - auto & PurchAir(state.dataPurchasedAirMgr->PurchAir); + // PURPOSE OF THIS SUBROUTINE: + // Calculates the mixed air conditions, accounting for heat recovery. - if (PurchAir(PurchAirNum).ReturnPlenumIndex > 0) { + // METHODOLOGY EMPLOYED: + // na - // if connected to a return plenum, set the flag that this ideal loads air system was simulated - state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex).IsSimulated(PurchAir(PurchAirNum).PurchAirArrayIndex) = true; + // REFERENCES: - // if all ideal loads air systems connected to the same plenum have been simulated, simulate the zone air plenum - if (all(state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex).IsSimulated)) { - SimAirZonePlenum(state, - PurchAir(PurchAirNum).ReturnPlenumName, - DataZoneEquipment::ZoneReturnPlenum_Type, - PurchAir(PurchAirNum).ReturnPlenumIndex, - FirstHVACIteration, - FirstCall, - SupPathInletChanged); - // reset this plenums flags for next iteration - state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex).IsSimulated = false; - } - } + // Using/Aliasing + using DataLoopNode::Node; + + // Locals + // SUBROUTINE ARGUMENT DEFINITIONS: + + // SUBROUTINE PARAMETER DEFINITIONS: + static std::string const RoutineName("CalcPurchAirMixedAir"); + + // INTERFACE BLOCK SPECIFICATIONS + // na + + // DERIVED TYPE DEFINITIONS + // na + + // SUBROUTINE LOCAL VARIABLE DECLARATIONS: + int RecircNodeNum; // Zone return air node + int OANodeNum; // Outdoor air inlet node + Real64 RecircTemp; // Recirculated air from zone dry bulb temperature [C] + Real64 RecircHumRat; // Recirculated air from zone humidity ratio [kgWater/kgDryAir] + Real64 RecircEnthalpy; // Recirculated air from zone enthalpy [J/kg] + Real64 RecircMassFlowRate; // Recirculated air mass flow rate [kg/s] + Real64 OAInletTemp; // Outdoor air inlet dry bulb temperature [C] + Real64 OAInletHumRat; // Outdoor air inlet humidity ratio [kgWater/kgDryAir] + Real64 OAInletEnthalpy; // Outdoor air inlet enthalpy [J/kg] + Real64 OAAfterHtRecTemp; // Outdoor air after heat recovery to mixing box dry bulb temperature [C] + Real64 OAAfterHtRecHumRat; // Outdoor air after heat recovery to mixing box humidity ratio [kgWater/kgDryAir] + Real64 OAAfterHtRecEnthalpy; // Outdoor air after heat recovery to mixing box enthalpy [J/kg] + bool HeatRecOn; + Real64 CpAir; // Specific heat [J/kg-C] reused in multiple places + + auto &PurchAir(state.dataPurchasedAirMgr->PurchAir); + + // Initializations + OANodeNum = PurchAir(PurchAirNum).OutdoorAirNodeNum; + RecircNodeNum = PurchAir(PurchAirNum).ZoneRecircAirNodeNum; + + RecircMassFlowRate = 0.0; + RecircTemp = Node(RecircNodeNum).Temp; + RecircHumRat = Node(RecircNodeNum).HumRat; + RecircEnthalpy = Node(RecircNodeNum).Enthalpy; + if (PurchAir(PurchAirNum).OutdoorAir) { + OAInletTemp = Node(OANodeNum).Temp; + OAInletHumRat = Node(OANodeNum).HumRat; + OAInletEnthalpy = Node(OANodeNum).Enthalpy; + OAAfterHtRecTemp = OAInletTemp; + OAAfterHtRecHumRat = OAInletHumRat; + OAAfterHtRecEnthalpy = OAInletEnthalpy; + } else { + OAInletTemp = 0.0; + OAInletHumRat = 0.0; + OAInletEnthalpy = 0.0; + OAAfterHtRecTemp = OAInletTemp; + OAAfterHtRecHumRat = OAInletHumRat; + OAAfterHtRecEnthalpy = OAInletEnthalpy; } + HeatRecOn = false; - void ReportPurchasedAir(EnergyPlusData &state, int const PurchAirNum) - { - - // SUBROUTINE INFORMATION: - // AUTHOR Russ Taylor - // DATE WRITTEN Nov 1997 - // MODIFIED na - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // Calculate values of report variables, if necessary. - - // Using/Aliasing - using DataHVACGlobals::TimeStepSys; - - auto & PurchAir(state.dataPurchasedAirMgr->PurchAir); - - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - Real64 ReportingConstant; - - // Sort out heating and cooling rates - PurchAir(PurchAirNum).SenHeatRate = max(PurchAir(PurchAirNum).SenCoilLoad, 0.0); - PurchAir(PurchAirNum).SenCoolRate = std::abs(min(PurchAir(PurchAirNum).SenCoilLoad, 0.0)); - PurchAir(PurchAirNum).LatHeatRate = max(PurchAir(PurchAirNum).LatCoilLoad, 0.0); - PurchAir(PurchAirNum).LatCoolRate = std::abs(min(PurchAir(PurchAirNum).LatCoilLoad, 0.0)); - PurchAir(PurchAirNum).TotHeatRate = PurchAir(PurchAirNum).SenHeatRate + PurchAir(PurchAirNum).LatHeatRate; - PurchAir(PurchAirNum).TotCoolRate = PurchAir(PurchAirNum).SenCoolRate + PurchAir(PurchAirNum).LatCoolRate; - - PurchAir(PurchAirNum).ZoneSenHeatRate = max(PurchAir(PurchAirNum).SenOutputToZone, 0.0); - PurchAir(PurchAirNum).ZoneSenCoolRate = std::abs(min(PurchAir(PurchAirNum).SenOutputToZone, 0.0)); - PurchAir(PurchAirNum).ZoneLatHeatRate = max(PurchAir(PurchAirNum).LatOutputToZone, 0.0); - PurchAir(PurchAirNum).ZoneLatCoolRate = std::abs(min(PurchAir(PurchAirNum).LatOutputToZone, 0.0)); - PurchAir(PurchAirNum).ZoneTotHeatRate = PurchAir(PurchAirNum).ZoneSenHeatRate + PurchAir(PurchAirNum).ZoneLatHeatRate; - PurchAir(PurchAirNum).ZoneTotCoolRate = PurchAir(PurchAirNum).ZoneSenCoolRate + PurchAir(PurchAirNum).ZoneLatCoolRate; - - // Sort out outdoor air "loads" - // OASenOutput = Outdoor air sensible output relative to zone conditions [W], <0 means OA is cooler than zone air - // OALatOutput = Outdoor air latent output relative to zone conditions [W], <0 means OA is drier than zone air - if (PurchAir(PurchAirNum).SenCoilLoad > 0.0) { // Heating is active - PurchAir(PurchAirNum).OASenHeatRate = std::abs(min(PurchAir(PurchAirNum).OASenOutput, 0.0)); - } else { - PurchAir(PurchAirNum).OASenHeatRate = 0.0; + if (PurchAir(PurchAirNum).OutdoorAir && (OAMassFlowRate > 0.0)) { + // Determine if heat recovery is beneficial + if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Sensible) { + if ((OperatingMode == OpMode::Heat) && (RecircTemp > OAInletTemp)) HeatRecOn = true; + if ((OperatingMode == OpMode::Cool) && (RecircTemp < OAInletTemp)) HeatRecOn = true; } - if (PurchAir(PurchAirNum).SenCoilLoad < 0.0) { // Cooling is active - PurchAir(PurchAirNum).OASenCoolRate = max(PurchAir(PurchAirNum).OASenOutput, 0.0); - } else { - PurchAir(PurchAirNum).OASenCoolRate = 0.0; + if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Enthalpy) { + if ((OperatingMode == OpMode::Heat) && (RecircEnthalpy > OAInletEnthalpy)) HeatRecOn = true; + if ((OperatingMode == OpMode::Cool) && (RecircEnthalpy < OAInletEnthalpy)) HeatRecOn = true; } - if (PurchAir(PurchAirNum).LatCoilLoad > 0.0) { // Humidification is active - PurchAir(PurchAirNum).OALatHeatRate = std::abs(min(PurchAir(PurchAirNum).OALatOutput, 0.0)); - } else { - PurchAir(PurchAirNum).OALatHeatRate = 0.0; + // Calculate heat recovery if active + if (HeatRecOn) { + PurchAir(PurchAirNum).TimeHtRecActive = TimeStepSys; + OAAfterHtRecTemp = OAInletTemp + PurchAir(PurchAirNum).HtRecSenEff * (RecircTemp - OAInletTemp); + if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Enthalpy) + OAAfterHtRecHumRat = OAInletHumRat + PurchAir(PurchAirNum).HtRecLatEff * (RecircHumRat - OAInletHumRat); + OAAfterHtRecEnthalpy = PsyHFnTdbW(OAAfterHtRecTemp, OAAfterHtRecHumRat); + // Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy + if (PsyTsatFnHPb(state, OAAfterHtRecEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName) > OAAfterHtRecTemp) { + OAAfterHtRecTemp = PsyTsatFnHPb(state, OAAfterHtRecEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName); + OAAfterHtRecHumRat = PsyWFnTdbH(state, OAAfterHtRecTemp, OAAfterHtRecEnthalpy, RoutineName); + } } - if (PurchAir(PurchAirNum).LatCoilLoad < 0.0) { // Dehumidification is active - PurchAir(PurchAirNum).OALatCoolRate = max(PurchAir(PurchAirNum).OALatOutput, 0.0); + + if (SupplyMassFlowRate > OAMassFlowRate) { + RecircMassFlowRate = SupplyMassFlowRate - OAMassFlowRate; + MixedAirEnthalpy = (RecircMassFlowRate * Node(RecircNodeNum).Enthalpy + OAMassFlowRate * OAAfterHtRecEnthalpy) / SupplyMassFlowRate; + MixedAirHumRat = (RecircMassFlowRate * Node(RecircNodeNum).HumRat + OAMassFlowRate * OAAfterHtRecHumRat) / SupplyMassFlowRate; + // Mixed air temperature is calculated from the mixed air enthalpy and humidity ratio. + MixedAirTemp = PsyTdbFnHW(MixedAirEnthalpy, MixedAirHumRat); } else { - PurchAir(PurchAirNum).OALatCoolRate = 0.0; + RecircMassFlowRate = 0.0; + MixedAirEnthalpy = OAAfterHtRecEnthalpy; + MixedAirHumRat = OAAfterHtRecHumRat; + MixedAirTemp = OAAfterHtRecTemp; } - PurchAir(PurchAirNum).OATotHeatRate = PurchAir(PurchAirNum).OASenHeatRate + PurchAir(PurchAirNum).OALatHeatRate; - PurchAir(PurchAirNum).OATotCoolRate = PurchAir(PurchAirNum).OASenCoolRate + PurchAir(PurchAirNum).OALatCoolRate; - - PurchAir(PurchAirNum).HtRecSenHeatRate = max(PurchAir(PurchAirNum).HtRecSenOutput, 0.0); - PurchAir(PurchAirNum).HtRecSenCoolRate = std::abs(min(PurchAir(PurchAirNum).HtRecSenOutput, 0.0)); - PurchAir(PurchAirNum).HtRecLatHeatRate = max(PurchAir(PurchAirNum).HtRecLatOutput, 0.0); - PurchAir(PurchAirNum).HtRecLatCoolRate = std::abs(min(PurchAir(PurchAirNum).HtRecLatOutput, 0.0)); - PurchAir(PurchAirNum).HtRecTotHeatRate = PurchAir(PurchAirNum).HtRecSenHeatRate + PurchAir(PurchAirNum).HtRecLatHeatRate; - PurchAir(PurchAirNum).HtRecTotCoolRate = PurchAir(PurchAirNum).HtRecSenCoolRate + PurchAir(PurchAirNum).HtRecLatCoolRate; - - ReportingConstant = TimeStepSys * DataGlobalConstants::SecInHour; - - PurchAir(PurchAirNum).SenHeatEnergy = PurchAir(PurchAirNum).SenHeatRate * ReportingConstant; - PurchAir(PurchAirNum).SenCoolEnergy = PurchAir(PurchAirNum).SenCoolRate * ReportingConstant; - PurchAir(PurchAirNum).LatHeatEnergy = PurchAir(PurchAirNum).LatHeatRate * ReportingConstant; - PurchAir(PurchAirNum).LatCoolEnergy = PurchAir(PurchAirNum).LatCoolRate * ReportingConstant; - PurchAir(PurchAirNum).TotHeatEnergy = PurchAir(PurchAirNum).TotHeatRate * ReportingConstant; - PurchAir(PurchAirNum).TotCoolEnergy = PurchAir(PurchAirNum).TotCoolRate * ReportingConstant; - - PurchAir(PurchAirNum).ZoneSenHeatEnergy = PurchAir(PurchAirNum).ZoneSenHeatRate * ReportingConstant; - PurchAir(PurchAirNum).ZoneSenCoolEnergy = PurchAir(PurchAirNum).ZoneSenCoolRate * ReportingConstant; - PurchAir(PurchAirNum).ZoneLatHeatEnergy = PurchAir(PurchAirNum).ZoneLatHeatRate * ReportingConstant; - PurchAir(PurchAirNum).ZoneLatCoolEnergy = PurchAir(PurchAirNum).ZoneLatCoolRate * ReportingConstant; - PurchAir(PurchAirNum).ZoneTotHeatEnergy = PurchAir(PurchAirNum).ZoneTotHeatRate * ReportingConstant; - PurchAir(PurchAirNum).ZoneTotCoolEnergy = PurchAir(PurchAirNum).ZoneTotCoolRate * ReportingConstant; - - PurchAir(PurchAirNum).OASenHeatEnergy = PurchAir(PurchAirNum).OASenHeatRate * ReportingConstant; - PurchAir(PurchAirNum).OASenCoolEnergy = PurchAir(PurchAirNum).OASenCoolRate * ReportingConstant; - PurchAir(PurchAirNum).OALatHeatEnergy = PurchAir(PurchAirNum).OALatHeatRate * ReportingConstant; - PurchAir(PurchAirNum).OALatCoolEnergy = PurchAir(PurchAirNum).OALatCoolRate * ReportingConstant; - PurchAir(PurchAirNum).OATotHeatEnergy = PurchAir(PurchAirNum).OATotHeatRate * ReportingConstant; - PurchAir(PurchAirNum).OATotCoolEnergy = PurchAir(PurchAirNum).OATotCoolRate * ReportingConstant; - - PurchAir(PurchAirNum).HtRecSenHeatEnergy = PurchAir(PurchAirNum).HtRecSenHeatRate * ReportingConstant; - PurchAir(PurchAirNum).HtRecSenCoolEnergy = PurchAir(PurchAirNum).HtRecSenCoolRate * ReportingConstant; - PurchAir(PurchAirNum).HtRecLatHeatEnergy = PurchAir(PurchAirNum).HtRecLatHeatRate * ReportingConstant; - PurchAir(PurchAirNum).HtRecLatCoolEnergy = PurchAir(PurchAirNum).HtRecLatCoolRate * ReportingConstant; - PurchAir(PurchAirNum).HtRecTotHeatEnergy = PurchAir(PurchAirNum).HtRecTotHeatRate * ReportingConstant; - PurchAir(PurchAirNum).HtRecTotCoolEnergy = PurchAir(PurchAirNum).HtRecTotCoolRate * ReportingConstant; + // Calculate OA and heat recovery sensible and latent rates + CpAir = PsyCpAirFnW(OAInletHumRat); + PurchAir(PurchAirNum).HtRecSenOutput = OAMassFlowRate * CpAir * (OAAfterHtRecTemp - OAInletTemp); + PurchAir(PurchAirNum).HtRecLatOutput = OAMassFlowRate * (OAAfterHtRecEnthalpy - OAInletEnthalpy) - PurchAir(PurchAirNum).HtRecSenOutput; + + } else { // No outdoor air + RecircMassFlowRate = SupplyMassFlowRate; + MixedAirTemp = RecircTemp; + MixedAirHumRat = RecircHumRat; + MixedAirEnthalpy = RecircEnthalpy; + PurchAir(PurchAirNum).HtRecSenOutput = 0.0; + PurchAir(PurchAirNum).HtRecLatOutput = 0.0; } +} - Real64 GetPurchasedAirOutAirMassFlow(EnergyPlusData &state, int const PurchAirNum) - { +void UpdatePurchasedAir(EnergyPlusData &state, int const PurchAirNum, bool const FirstHVACIteration) +{ - // FUNCTION INFORMATION: - // AUTHOR B Griffith - // DATE WRITTEN Dec 2006 - // MODIFIED na - // RE-ENGINEERED na + // SUBROUTINE INFORMATION: + // AUTHOR M. J. Witte + // DATE WRITTEN Sep 2011 + // MODIFIED R. Raustad, July 2017, added return plenum + // RE-ENGINEERED na - // PURPOSE OF THIS FUNCTION: - // lookup function for OA inlet mass flow for ventilation rate reporting + // PURPOSE OF THIS SUBROUTINE: + // Update node data for Ideal Loads (purchased air) system - // METHODOLOGY EMPLOYED: - // most analagous functions look up an outside air node but this function - // gets the actual mass flow of outdoor air, following the features of the model + // USE STATEMENTS: + using ZonePlenum::SimAirZonePlenum; - if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { - GetPurchasedAir(state); - state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; - } - return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).OutdoorAirMassFlowRate; - } + // SUBROUTINE LOCAL VARIABLE DECLARATIONS: + // na + bool FirstCall; + bool SupPathInletChanged; - int GetPurchasedAirZoneInletAirNode(EnergyPlusData &state, int const PurchAirNum) - { + FirstCall = true; // just used to avoid redundant calulations + SupPathInletChanged = false; // don't care if something changes - // FUNCTION INFORMATION: - // AUTHOR B Griffith - // DATE WRITTEN Dec 2006 - // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013 - // RE-ENGINEERED na + auto &PurchAir(state.dataPurchasedAirMgr->PurchAir); - // PURPOSE OF THIS FUNCTION: - // lookup function for zone inlet node for ventilation rate reporting + if (PurchAir(PurchAirNum).ReturnPlenumIndex > 0) { - if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { - GetPurchasedAir(state); - state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; - } + // if connected to a return plenum, set the flag that this ideal loads air system was simulated + state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex) + .IsSimulated(PurchAir(PurchAirNum).PurchAirArrayIndex) = true; - int GetPurchasedAirZoneInletAirNode = 0; - if (PurchAirNum > 0 && PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir) { - GetPurchasedAirZoneInletAirNode = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ZoneSupplyAirNodeNum; + // if all ideal loads air systems connected to the same plenum have been simulated, simulate the zone air plenum + if (all(state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex).IsSimulated)) { + SimAirZonePlenum(state, + PurchAir(PurchAirNum).ReturnPlenumName, + DataZoneEquipment::ZoneReturnPlenum_Type, + PurchAir(PurchAirNum).ReturnPlenumIndex, + FirstHVACIteration, + FirstCall, + SupPathInletChanged); + // reset this plenums flags for next iteration + state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex).IsSimulated = false; } + } +} + +void ReportPurchasedAir(EnergyPlusData &state, int const PurchAirNum) +{ + + // SUBROUTINE INFORMATION: + // AUTHOR Russ Taylor + // DATE WRITTEN Nov 1997 + // MODIFIED na + // RE-ENGINEERED na + + // PURPOSE OF THIS SUBROUTINE: + // Calculate values of report variables, if necessary. - return GetPurchasedAirZoneInletAirNode; + // Using/Aliasing + using DataHVACGlobals::TimeStepSys; + + auto &PurchAir(state.dataPurchasedAirMgr->PurchAir); + + // SUBROUTINE LOCAL VARIABLE DECLARATIONS: + Real64 ReportingConstant; + + // Sort out heating and cooling rates + PurchAir(PurchAirNum).SenHeatRate = max(PurchAir(PurchAirNum).SenCoilLoad, 0.0); + PurchAir(PurchAirNum).SenCoolRate = std::abs(min(PurchAir(PurchAirNum).SenCoilLoad, 0.0)); + PurchAir(PurchAirNum).LatHeatRate = max(PurchAir(PurchAirNum).LatCoilLoad, 0.0); + PurchAir(PurchAirNum).LatCoolRate = std::abs(min(PurchAir(PurchAirNum).LatCoilLoad, 0.0)); + PurchAir(PurchAirNum).TotHeatRate = PurchAir(PurchAirNum).SenHeatRate + PurchAir(PurchAirNum).LatHeatRate; + PurchAir(PurchAirNum).TotCoolRate = PurchAir(PurchAirNum).SenCoolRate + PurchAir(PurchAirNum).LatCoolRate; + + PurchAir(PurchAirNum).ZoneSenHeatRate = max(PurchAir(PurchAirNum).SenOutputToZone, 0.0); + PurchAir(PurchAirNum).ZoneSenCoolRate = std::abs(min(PurchAir(PurchAirNum).SenOutputToZone, 0.0)); + PurchAir(PurchAirNum).ZoneLatHeatRate = max(PurchAir(PurchAirNum).LatOutputToZone, 0.0); + PurchAir(PurchAirNum).ZoneLatCoolRate = std::abs(min(PurchAir(PurchAirNum).LatOutputToZone, 0.0)); + PurchAir(PurchAirNum).ZoneTotHeatRate = PurchAir(PurchAirNum).ZoneSenHeatRate + PurchAir(PurchAirNum).ZoneLatHeatRate; + PurchAir(PurchAirNum).ZoneTotCoolRate = PurchAir(PurchAirNum).ZoneSenCoolRate + PurchAir(PurchAirNum).ZoneLatCoolRate; + + // Sort out outdoor air "loads" + // OASenOutput = Outdoor air sensible output relative to zone conditions [W], <0 means OA is cooler than zone air + // OALatOutput = Outdoor air latent output relative to zone conditions [W], <0 means OA is drier than zone air + if (PurchAir(PurchAirNum).SenCoilLoad > 0.0) { // Heating is active + PurchAir(PurchAirNum).OASenHeatRate = std::abs(min(PurchAir(PurchAirNum).OASenOutput, 0.0)); + } else { + PurchAir(PurchAirNum).OASenHeatRate = 0.0; + } + if (PurchAir(PurchAirNum).SenCoilLoad < 0.0) { // Cooling is active + PurchAir(PurchAirNum).OASenCoolRate = max(PurchAir(PurchAirNum).OASenOutput, 0.0); + } else { + PurchAir(PurchAirNum).OASenCoolRate = 0.0; } + if (PurchAir(PurchAirNum).LatCoilLoad > 0.0) { // Humidification is active + PurchAir(PurchAirNum).OALatHeatRate = std::abs(min(PurchAir(PurchAirNum).OALatOutput, 0.0)); + } else { + PurchAir(PurchAirNum).OALatHeatRate = 0.0; + } + if (PurchAir(PurchAirNum).LatCoilLoad < 0.0) { // Dehumidification is active + PurchAir(PurchAirNum).OALatCoolRate = max(PurchAir(PurchAirNum).OALatOutput, 0.0); + } else { + PurchAir(PurchAirNum).OALatCoolRate = 0.0; + } + + PurchAir(PurchAirNum).OATotHeatRate = PurchAir(PurchAirNum).OASenHeatRate + PurchAir(PurchAirNum).OALatHeatRate; + PurchAir(PurchAirNum).OATotCoolRate = PurchAir(PurchAirNum).OASenCoolRate + PurchAir(PurchAirNum).OALatCoolRate; + + PurchAir(PurchAirNum).HtRecSenHeatRate = max(PurchAir(PurchAirNum).HtRecSenOutput, 0.0); + PurchAir(PurchAirNum).HtRecSenCoolRate = std::abs(min(PurchAir(PurchAirNum).HtRecSenOutput, 0.0)); + PurchAir(PurchAirNum).HtRecLatHeatRate = max(PurchAir(PurchAirNum).HtRecLatOutput, 0.0); + PurchAir(PurchAirNum).HtRecLatCoolRate = std::abs(min(PurchAir(PurchAirNum).HtRecLatOutput, 0.0)); + PurchAir(PurchAirNum).HtRecTotHeatRate = PurchAir(PurchAirNum).HtRecSenHeatRate + PurchAir(PurchAirNum).HtRecLatHeatRate; + PurchAir(PurchAirNum).HtRecTotCoolRate = PurchAir(PurchAirNum).HtRecSenCoolRate + PurchAir(PurchAirNum).HtRecLatCoolRate; + + ReportingConstant = TimeStepSys * DataGlobalConstants::SecInHour; + + PurchAir(PurchAirNum).SenHeatEnergy = PurchAir(PurchAirNum).SenHeatRate * ReportingConstant; + PurchAir(PurchAirNum).SenCoolEnergy = PurchAir(PurchAirNum).SenCoolRate * ReportingConstant; + PurchAir(PurchAirNum).LatHeatEnergy = PurchAir(PurchAirNum).LatHeatRate * ReportingConstant; + PurchAir(PurchAirNum).LatCoolEnergy = PurchAir(PurchAirNum).LatCoolRate * ReportingConstant; + PurchAir(PurchAirNum).TotHeatEnergy = PurchAir(PurchAirNum).TotHeatRate * ReportingConstant; + PurchAir(PurchAirNum).TotCoolEnergy = PurchAir(PurchAirNum).TotCoolRate * ReportingConstant; + + PurchAir(PurchAirNum).ZoneSenHeatEnergy = PurchAir(PurchAirNum).ZoneSenHeatRate * ReportingConstant; + PurchAir(PurchAirNum).ZoneSenCoolEnergy = PurchAir(PurchAirNum).ZoneSenCoolRate * ReportingConstant; + PurchAir(PurchAirNum).ZoneLatHeatEnergy = PurchAir(PurchAirNum).ZoneLatHeatRate * ReportingConstant; + PurchAir(PurchAirNum).ZoneLatCoolEnergy = PurchAir(PurchAirNum).ZoneLatCoolRate * ReportingConstant; + PurchAir(PurchAirNum).ZoneTotHeatEnergy = PurchAir(PurchAirNum).ZoneTotHeatRate * ReportingConstant; + PurchAir(PurchAirNum).ZoneTotCoolEnergy = PurchAir(PurchAirNum).ZoneTotCoolRate * ReportingConstant; + + PurchAir(PurchAirNum).OASenHeatEnergy = PurchAir(PurchAirNum).OASenHeatRate * ReportingConstant; + PurchAir(PurchAirNum).OASenCoolEnergy = PurchAir(PurchAirNum).OASenCoolRate * ReportingConstant; + PurchAir(PurchAirNum).OALatHeatEnergy = PurchAir(PurchAirNum).OALatHeatRate * ReportingConstant; + PurchAir(PurchAirNum).OALatCoolEnergy = PurchAir(PurchAirNum).OALatCoolRate * ReportingConstant; + PurchAir(PurchAirNum).OATotHeatEnergy = PurchAir(PurchAirNum).OATotHeatRate * ReportingConstant; + PurchAir(PurchAirNum).OATotCoolEnergy = PurchAir(PurchAirNum).OATotCoolRate * ReportingConstant; + + PurchAir(PurchAirNum).HtRecSenHeatEnergy = PurchAir(PurchAirNum).HtRecSenHeatRate * ReportingConstant; + PurchAir(PurchAirNum).HtRecSenCoolEnergy = PurchAir(PurchAirNum).HtRecSenCoolRate * ReportingConstant; + PurchAir(PurchAirNum).HtRecLatHeatEnergy = PurchAir(PurchAirNum).HtRecLatHeatRate * ReportingConstant; + PurchAir(PurchAirNum).HtRecLatCoolEnergy = PurchAir(PurchAirNum).HtRecLatCoolRate * ReportingConstant; + PurchAir(PurchAirNum).HtRecTotHeatEnergy = PurchAir(PurchAirNum).HtRecTotHeatRate * ReportingConstant; + PurchAir(PurchAirNum).HtRecTotCoolEnergy = PurchAir(PurchAirNum).HtRecTotCoolRate * ReportingConstant; +} + +Real64 GetPurchasedAirOutAirMassFlow(EnergyPlusData &state, int const PurchAirNum) +{ + + // FUNCTION INFORMATION: + // AUTHOR B Griffith + // DATE WRITTEN Dec 2006 + // MODIFIED na + // RE-ENGINEERED na - int GetPurchasedAirReturnAirNode(EnergyPlusData &state, int const PurchAirNum) - { + // PURPOSE OF THIS FUNCTION: + // lookup function for OA inlet mass flow for ventilation rate reporting - // FUNCTION INFORMATION: - // AUTHOR B Griffith - // DATE WRITTEN Dec 2006 - // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013 - // RE-ENGINEERED na + // METHODOLOGY EMPLOYED: + // most analagous functions look up an outside air node but this function + // gets the actual mass flow of outdoor air, following the features of the model - // PURPOSE OF THIS FUNCTION: - // lookup function for recirculation air node for ventilation rate reporting + if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { + GetPurchasedAir(state); + state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; + } + return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).OutdoorAirMassFlowRate; +} - if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { - GetPurchasedAir(state); - state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; - } +int GetPurchasedAirZoneInletAirNode(EnergyPlusData &state, int const PurchAirNum) +{ - int GetPurchasedAirReturnAirNode = 0; - if (PurchAirNum > 0 && PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir) { - GetPurchasedAirReturnAirNode = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ZoneRecircAirNodeNum; - } + // FUNCTION INFORMATION: + // AUTHOR B Griffith + // DATE WRITTEN Dec 2006 + // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013 + // RE-ENGINEERED na + + // PURPOSE OF THIS FUNCTION: + // lookup function for zone inlet node for ventilation rate reporting - return GetPurchasedAirReturnAirNode; + if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { + GetPurchasedAir(state); + state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; } - Real64 GetPurchasedAirMixedAirTemp(EnergyPlusData &state, int const PurchAirNum) - { + int GetPurchasedAirZoneInletAirNode = 0; + if (PurchAirNum > 0 && PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir) { + GetPurchasedAirZoneInletAirNode = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ZoneSupplyAirNodeNum; + } - // FUNCTION INFORMATION: - // AUTHOR B Griffith - // DATE WRITTEN Dec 2006 - // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013 - // RE-ENGINEERED na + return GetPurchasedAirZoneInletAirNode; +} - // PURPOSE OF THIS FUNCTION: - // lookup function for mixed air Temp for ventilation rate reporting +int GetPurchasedAirReturnAirNode(EnergyPlusData &state, int const PurchAirNum) +{ - // METHODOLOGY EMPLOYED: - // most analagous functions look up an outside air node but this function - // gets the actual mass flow of outdoor air, following the features of the model + // FUNCTION INFORMATION: + // AUTHOR B Griffith + // DATE WRITTEN Dec 2006 + // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013 + // RE-ENGINEERED na - if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { - GetPurchasedAir(state); - state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; - } + // PURPOSE OF THIS FUNCTION: + // lookup function for recirculation air node for ventilation rate reporting - return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).FinalMixedAirTemp; + if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { + GetPurchasedAir(state); + state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; } - Real64 GetPurchasedAirMixedAirHumRat(EnergyPlusData &state, int const PurchAirNum) - { + int GetPurchasedAirReturnAirNode = 0; + if (PurchAirNum > 0 && PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir) { + GetPurchasedAirReturnAirNode = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ZoneRecircAirNodeNum; + } - // FUNCTION INFORMATION: - // AUTHOR B Griffith - // DATE WRITTEN Dec 2006 - // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013 - // RE-ENGINEERED na + return GetPurchasedAirReturnAirNode; +} - // PURPOSE OF THIS FUNCTION: - // lookup function for mixed air HumRat for ventilation rate reporting +Real64 GetPurchasedAirMixedAirTemp(EnergyPlusData &state, int const PurchAirNum) +{ - // METHODOLOGY EMPLOYED: - // most analagous functions look up an outside air node but this function - // gets the actual mass flow of outdoor air, following the features of the model + // FUNCTION INFORMATION: + // AUTHOR B Griffith + // DATE WRITTEN Dec 2006 + // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013 + // RE-ENGINEERED na - if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { - GetPurchasedAir(state); - state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; - } + // PURPOSE OF THIS FUNCTION: + // lookup function for mixed air Temp for ventilation rate reporting - return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).FinalMixedAirHumRat; + // METHODOLOGY EMPLOYED: + // most analagous functions look up an outside air node but this function + // gets the actual mass flow of outdoor air, following the features of the model + if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { + GetPurchasedAir(state); + state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; } - bool CheckPurchasedAirForReturnPlenum(EnergyPlusData &state, int const &ReturnPlenumIndex) - { + return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).MixedAirTemp; +} - // FUNCTION INFORMATION: - // AUTHOR R Raustad - // DATE WRITTEN July 2017 +Real64 GetPurchasedAirMixedAirHumRat(EnergyPlusData &state, int const PurchAirNum) +{ - // PURPOSE OF THIS FUNCTION: - // lookup function to check if return plenum is used + // FUNCTION INFORMATION: + // AUTHOR B Griffith + // DATE WRITTEN Dec 2006 + // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013 + // RE-ENGINEERED na - // Return value - bool CheckPurchasedAirForReturnPlenum; + // PURPOSE OF THIS FUNCTION: + // lookup function for mixed air HumRat for ventilation rate reporting - // FUNCTION LOCAL VARIABLE DECLARATIONS: - int PurchAirNum; + // METHODOLOGY EMPLOYED: + // most analogous functions look up an outside air node but this function + // gets the actual mass flow of outdoor air, following the features of the model - if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { - GetPurchasedAir(state); - state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; - } + if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { + GetPurchasedAir(state); + state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; + } - CheckPurchasedAirForReturnPlenum = false; - for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) { - if (ReturnPlenumIndex != state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ReturnPlenumIndex) continue; - CheckPurchasedAirForReturnPlenum = true; - } + return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).MixedAirHumRat; +} - return CheckPurchasedAirForReturnPlenum; - } +bool CheckPurchasedAirForReturnPlenum(EnergyPlusData &state, int const &ReturnPlenumIndex) +{ - void InitializePlenumArrays(EnergyPlusData &state, int const PurchAirNum) - { - // FUNCTION INFORMATION: - // AUTHOR R Raustad - // DATE WRITTEN July 2017 - - // PURPOSE OF THIS FUNCTION: - // to initialize arrays needed to manage ideal load air system used with return plenums - // - // Example: - // NumPlenumArrays = 2 (same as there are two ZoneHVAC:ReturnPlenums objects connected to two or more ideal loads air systems - // In this example ideal loads air system #4 is not connected to a zone return plenum - // - // ZoneHVAC:ReturnPlenum( 1 ) = ReturnPlenum1 is not connected to any ideal loads air systems - // ZoneHVAC:ReturnPlenum( 2 ) = ReturnPlenum2 is connected to PurchAirPlenumArrays( 1 ) - // ZoneHVAC:ReturnPlenum( 3 ) = ReturnPlenum3 is connected to PurchAirPlenumArrays( 2 ) - // - // PurchAirPlenumArrays( 1 ) - // PurchAirPlenumArrays( 1 ).NumPurchAir = 2, there are 2 ideal loads air systems connected to this plenum - // PurchAirPlenumArrays( 1 ).PurchAirArray( 1 ) = 1, ideal loads air system #1 is attached to this plenum - // PurchAirPlenumArrays( 1 ).PurchAirArray( 2 ) = 3, ideal loads air system #3 is attached to this plenum - // PurchAirPlenumArrays( 1 ).IsSimulated( 1 ) = true, ideal loads air system #1 has been simulated this iteration - // PurchAirPlenumArrays( 1 ).IsSimulated( 2 ) = false, ideal loads air system #3 has not yet been simulated this iteration - // - // Ideal loads air sytems keep track of which plenum they are connected to - // PurchAir( 1 ).PlenumArrayIndex = 1 - // PurchAir( 1 ).ReturnPlenumName = ReturnPlenum2; - // PurchAir( 3 ).PlenumArrayIndex = 1 - // PurchAir( 3 ).ReturnPlenumName = ReturnPlenum2; - // - // The ideal loads air sytems also keep track of which item they are in the int and bool arrays - // PurchAir( 1 ).PurchAirArrayIndex = 1 - // PurchAir( 3 ).PurchAirArrayIndex = 2 - // - // PurchAirPlenumArrays( 2 ) - // PurchAirPlenumArrays( 2 ).NumPurchAir = 3, there are 3 ideal loads air systems connected to this plenum - // PurchAirPlenumArrays( 2 ).PurchAirArray( 1 ) = 2, ideal loads air system #2 is attached to this plenum - // PurchAirPlenumArrays( 2 ).PurchAirArray( 2 ) = 5, ideal loads air system #5 is attached to this plenum - // PurchAirPlenumArrays( 2 ).PurchAirArray( 3 ) = 6, ideal loads air system #6 is attached to this plenum - // PurchAirPlenumArrays( 2 ).IsSimulated( 1 ) = true, ideal loads air system #4 has been simulated this iteration - // PurchAirPlenumArrays( 2 ).IsSimulated( 2 ) = false, ideal loads air system #5 has not yet been simulated this iteration - // PurchAirPlenumArrays( 2 ).IsSimulated( 3 ) = false, ideal loads air system #6 has not yet been simulated this iteration - // - // Ideal loads air sytems keep track of which plenum they are connected to - // PurchAir( 2 ).PlenumArrayIndex = 2; - // PurchAir( 2 ).ReturnPlenumName = ReturnPlenum3; - // PurchAir( 5 ).PlenumArrayIndex = 2; - // PurchAir( 5 ).ReturnPlenumName = ReturnPlenum3; - // PurchAir( 6 ).PlenumArrayIndex = 2; - // PurchAir( 6 ).ReturnPlenumName = ReturnPlenum3; - // - // The ideal loads air sytems also keep track of which item they are in the int and bool arrays - // PurchAir( 2 ).PurchAirArrayIndex = 1; - // PurchAir( 5 ).PurchAirArrayIndex = 2; - // PurchAir( 6 ).PurchAirArrayIndex = 3; - // - // Given these connections, the data in the IsSimulated array can be set (or checked) according to this syntax: - // - // Each time an ideal loads air system is simulated the IsSimulated flag is set to true - // PurchAirPlenumArrays( PurchAir( PurchNum ).PlenumArrayIndex ).IsSimulated( PurchAir( PurchNum ).PurchAirArrayIndex ) = true; - // - // if all ideal loads air systems connected to the same plenum have been simulated, simulate the zone air return plenum (once per set of - // ideal loads systems) if ( all( PurchAirPlenumArrays( PurchAir( PurchAirNum ).ReturnPlenumIndex ).IsSimulated ) ) { - // SimAirZonePlenum( PurchAir( PurchAirNum ).ReturnPlenumName, DataZoneEquipment::ZoneReturnPlenum_Type, PurchAir( PurchAirNum - // ).ReturnPlenumIndex, FirstHVACIteration, FirstCall, SupPathInletChanged ); reset all IsSimulated flags for next iteration - // PurchAirPlenumArrays( PurchAir( PurchAirNum ).ReturnPlenumIndex ).IsSimulated = false; - // } - - // FUNCTION LOCAL VARIABLE DECLARATIONS: - int ReturnPlenumIndex; // index to ZoneHVAC:ReturnPlenum object - int ReturnPlenumNum; // loop counter - bool PlenumNotFound; // logical to determine if same plenum is used by other ideal loads air systems - int Loop; // loop counters - int Loop2; // loop counters - Array1D_int TempPurchArray; // temporary array used for dynamic allocation - Array1D_bool TempIsSimulated; // temporary array used for dynamic allocation - - // index to ZoneHVAC:ReturnPlenum object - ReturnPlenumIndex = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ReturnPlenumIndex; - PlenumNotFound = true; - - // if first time through, set up arrays - if (!state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocated()) { - - // the ideal loads air system keeps track of which item this system is in a list - state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex = 1; - // keep track of how many arrays (i.e., how many different plenums are attached to different ideal loads air systems - state.dataPurchasedAirMgr->NumPlenumArrays = 1; + // FUNCTION INFORMATION: + // AUTHOR R Raustad + // DATE WRITTEN July 2017 - // allocate new array - state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays); - // set counter for how many ideal loads air systems are attached to this plenum - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).NumPurchAir = - 1; // keeps track of how many ideal loads air system are connected to this return plenum - // keep track of which plenum this is ( i.e., PurchAirPlenumArrays(1) is ZoneHVAC:ReturnPlenum #4 ) - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).ReturnPlenumIndex = ReturnPlenumIndex; // stores index of return plenum (e.g., 4 of 5) - // allocate array holding index to one or more ideal loads air systems - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray.allocate(1); - // allocate boolean to keep track of whether or not this ideal loads air system has been simulated - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated.allocate(1); - // save the data - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray(1) = PurchAirNum; - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated(1) = false; + // PURPOSE OF THIS FUNCTION: + // lookup function to check if return plenum is used - } else { + // Return value + bool CheckPurchasedAirForReturnPlenum; - // find the correct index to PurchAirPlenumArrays - for (ReturnPlenumNum = 1; ReturnPlenumNum <= state.dataPurchasedAirMgr->NumPlenumArrays; ++ReturnPlenumNum) { - if (ReturnPlenumIndex != state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).ReturnPlenumIndex) continue; - - // allocate temporary arrays and save existing data - TempPurchArray.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir); - TempIsSimulated.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir); - // these are the member arrays in an existing PurchAirPlenumArrays - TempPurchArray = state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).PurchAirArray; - TempIsSimulated = state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).IsSimulated; - - // if this array has been used before, we need to increase member array space to save new PurchAir data - state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir += 1; - // save the location of this ideal loads air system in the member arrays - state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex = state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir; - - // allocate more space, this will wipe out data previously stored - state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).PurchAirArray.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir); - state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).IsSimulated.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir); - - // re-initialize previous data - for (Loop = 1; Loop < state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir; ++Loop) { - state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).PurchAirArray(Loop) = TempPurchArray(Loop); - state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).IsSimulated(Loop) = TempIsSimulated(Loop); - } - // delete temporary array - TempPurchArray.deallocate(); - TempIsSimulated.deallocate(); - - // save new data in expanded member array - state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).PurchAirArray(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir) = PurchAirNum; - state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).IsSimulated(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir) = false; - - PlenumNotFound = false; - break; - } - - if (PlenumNotFound) { - - // need to allocate additional space for new plenum array - // keep track of how many arrays (i.e., how many different plenums are attached to different ideal loads air systems) - state.dataPurchasedAirMgr->NumPlenumArrays += 1; - - // allocate temporary array and save existing data - state.dataPurchasedAirMgr->TempPurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays); - for (Loop = 1; Loop < state.dataPurchasedAirMgr->NumPlenumArrays; ++Loop) { - state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir = state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir; - state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).ReturnPlenumIndex = state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).ReturnPlenumIndex; - state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).PurchAirArray.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir); - state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).IsSimulated.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir); - for (Loop2 = 1; Loop2 <= state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir; ++Loop2) { - state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).PurchAirArray(Loop2) = state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).PurchAirArray(Loop2); - state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).IsSimulated(Loop2) = state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).IsSimulated(Loop2); - } - } + // FUNCTION LOCAL VARIABLE DECLARATIONS: + int PurchAirNum; + + if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) { + GetPurchasedAir(state); + state.dataPurchasedAirMgr->GetPurchAirInputFlag = false; + } + + CheckPurchasedAirForReturnPlenum = false; + for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) { + if (ReturnPlenumIndex != state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ReturnPlenumIndex) continue; + CheckPurchasedAirForReturnPlenum = true; + } - // delete primary array (probably could just re-allocate, but this is only done a few times per simulation) - state.dataPurchasedAirMgr->PurchAirPlenumArrays.deallocate(); - // reallocate to new size - state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays); + return CheckPurchasedAirForReturnPlenum; +} + +void InitializePlenumArrays(EnergyPlusData &state, int const PurchAirNum) +{ + // FUNCTION INFORMATION: + // AUTHOR R Raustad + // DATE WRITTEN July 2017 + + // PURPOSE OF THIS FUNCTION: + // to initialize arrays needed to manage ideal load air system used with return plenums + // + // Example: + // NumPlenumArrays = 2 (same as there are two ZoneHVAC:ReturnPlenums objects connected to two or more ideal loads air systems + // In this example ideal loads air system #4 is not connected to a zone return plenum + // + // ZoneHVAC:ReturnPlenum( 1 ) = ReturnPlenum1 is not connected to any ideal loads air systems + // ZoneHVAC:ReturnPlenum( 2 ) = ReturnPlenum2 is connected to PurchAirPlenumArrays( 1 ) + // ZoneHVAC:ReturnPlenum( 3 ) = ReturnPlenum3 is connected to PurchAirPlenumArrays( 2 ) + // + // PurchAirPlenumArrays( 1 ) + // PurchAirPlenumArrays( 1 ).NumPurchAir = 2, there are 2 ideal loads air systems connected to this plenum + // PurchAirPlenumArrays( 1 ).PurchAirArray( 1 ) = 1, ideal loads air system #1 is attached to this plenum + // PurchAirPlenumArrays( 1 ).PurchAirArray( 2 ) = 3, ideal loads air system #3 is attached to this plenum + // PurchAirPlenumArrays( 1 ).IsSimulated( 1 ) = true, ideal loads air system #1 has been simulated this iteration + // PurchAirPlenumArrays( 1 ).IsSimulated( 2 ) = false, ideal loads air system #3 has not yet been simulated this iteration + // + // Ideal loads air sytems keep track of which plenum they are connected to + // PurchAir( 1 ).PlenumArrayIndex = 1 + // PurchAir( 1 ).ReturnPlenumName = ReturnPlenum2; + // PurchAir( 3 ).PlenumArrayIndex = 1 + // PurchAir( 3 ).ReturnPlenumName = ReturnPlenum2; + // + // The ideal loads air sytems also keep track of which item they are in the int and bool arrays + // PurchAir( 1 ).PurchAirArrayIndex = 1 + // PurchAir( 3 ).PurchAirArrayIndex = 2 + // + // PurchAirPlenumArrays( 2 ) + // PurchAirPlenumArrays( 2 ).NumPurchAir = 3, there are 3 ideal loads air systems connected to this plenum + // PurchAirPlenumArrays( 2 ).PurchAirArray( 1 ) = 2, ideal loads air system #2 is attached to this plenum + // PurchAirPlenumArrays( 2 ).PurchAirArray( 2 ) = 5, ideal loads air system #5 is attached to this plenum + // PurchAirPlenumArrays( 2 ).PurchAirArray( 3 ) = 6, ideal loads air system #6 is attached to this plenum + // PurchAirPlenumArrays( 2 ).IsSimulated( 1 ) = true, ideal loads air system #4 has been simulated this iteration + // PurchAirPlenumArrays( 2 ).IsSimulated( 2 ) = false, ideal loads air system #5 has not yet been simulated this iteration + // PurchAirPlenumArrays( 2 ).IsSimulated( 3 ) = false, ideal loads air system #6 has not yet been simulated this iteration + // + // Ideal loads air sytems keep track of which plenum they are connected to + // PurchAir( 2 ).PlenumArrayIndex = 2; + // PurchAir( 2 ).ReturnPlenumName = ReturnPlenum3; + // PurchAir( 5 ).PlenumArrayIndex = 2; + // PurchAir( 5 ).ReturnPlenumName = ReturnPlenum3; + // PurchAir( 6 ).PlenumArrayIndex = 2; + // PurchAir( 6 ).ReturnPlenumName = ReturnPlenum3; + // + // The ideal loads air sytems also keep track of which item they are in the int and bool arrays + // PurchAir( 2 ).PurchAirArrayIndex = 1; + // PurchAir( 5 ).PurchAirArrayIndex = 2; + // PurchAir( 6 ).PurchAirArrayIndex = 3; + // + // Given these connections, the data in the IsSimulated array can be set (or checked) according to this syntax: + // + // Each time an ideal loads air system is simulated the IsSimulated flag is set to true + // PurchAirPlenumArrays( PurchAir( PurchNum ).PlenumArrayIndex ).IsSimulated( PurchAir( PurchNum ).PurchAirArrayIndex ) = true; + // + // if all ideal loads air systems connected to the same plenum have been simulated, simulate the zone air return plenum (once per set of + // ideal loads systems) if ( all( PurchAirPlenumArrays( PurchAir( PurchAirNum ).ReturnPlenumIndex ).IsSimulated ) ) { + // SimAirZonePlenum( PurchAir( PurchAirNum ).ReturnPlenumName, DataZoneEquipment::ZoneReturnPlenum_Type, PurchAir( PurchAirNum + // ).ReturnPlenumIndex, FirstHVACIteration, FirstCall, SupPathInletChanged ); reset all IsSimulated flags for next iteration + // PurchAirPlenumArrays( PurchAir( PurchAirNum ).ReturnPlenumIndex ).IsSimulated = false; + // } + + // FUNCTION LOCAL VARIABLE DECLARATIONS: + int ReturnPlenumIndex; // index to ZoneHVAC:ReturnPlenum object + int ReturnPlenumNum; // loop counter + bool PlenumNotFound; // logical to determine if same plenum is used by other ideal loads air systems + int Loop; // loop counters + int Loop2; // loop counters + Array1D_int TempPurchArray; // temporary array used for dynamic allocation + Array1D_bool TempIsSimulated; // temporary array used for dynamic allocation + + // index to ZoneHVAC:ReturnPlenum object + ReturnPlenumIndex = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ReturnPlenumIndex; + PlenumNotFound = true; + + // if first time through, set up arrays + if (!state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocated()) { + + // the ideal loads air system keeps track of which item this system is in a list + state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex = 1; + // keep track of how many arrays (i.e., how many different plenums are attached to different ideal loads air systems + state.dataPurchasedAirMgr->NumPlenumArrays = 1; + + // allocate new array + state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays); + // set counter for how many ideal loads air systems are attached to this plenum + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).NumPurchAir = + 1; // keeps track of how many ideal loads air system are connected to this return plenum + // keep track of which plenum this is ( i.e., PurchAirPlenumArrays(1) is ZoneHVAC:ReturnPlenum #4 ) + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).ReturnPlenumIndex = + ReturnPlenumIndex; // stores index of return plenum (e.g., 4 of 5) + // allocate array holding index to one or more ideal loads air systems + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray.allocate(1); + // allocate boolean to keep track of whether or not this ideal loads air system has been simulated + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated.allocate(1); + // save the data + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray(1) = PurchAirNum; + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated(1) = false; + + } else { + + // find the correct index to PurchAirPlenumArrays + for (ReturnPlenumNum = 1; ReturnPlenumNum <= state.dataPurchasedAirMgr->NumPlenumArrays; ++ReturnPlenumNum) { + if (ReturnPlenumIndex != state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).ReturnPlenumIndex) continue; + + // allocate temporary arrays and save existing data + TempPurchArray.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir); + TempIsSimulated.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir); + // these are the member arrays in an existing PurchAirPlenumArrays + TempPurchArray = state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).PurchAirArray; + TempIsSimulated = state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).IsSimulated; + + // if this array has been used before, we need to increase member array space to save new PurchAir data + state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir += 1; + // save the location of this ideal loads air system in the member arrays + state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex = + state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir; + + // allocate more space, this will wipe out data previously stored + state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum) + .PurchAirArray.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir); + state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum) + .IsSimulated.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir); + + // re-initialize previous data + for (Loop = 1; Loop < state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir; ++Loop) { + state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).PurchAirArray(Loop) = TempPurchArray(Loop); + state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).IsSimulated(Loop) = TempIsSimulated(Loop); + } + // delete temporary array + TempPurchArray.deallocate(); + TempIsSimulated.deallocate(); + + // save new data in expanded member array + state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum) + .PurchAirArray(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir) = PurchAirNum; + state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum) + .IsSimulated(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir) = false; + + PlenumNotFound = false; + break; + } - // allocate member arrays to same size as before - for (Loop = 1; Loop < state.dataPurchasedAirMgr->NumPlenumArrays; ++Loop) { - state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).PurchAirArray.allocate(state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir); - state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).IsSimulated.allocate(state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir); + if (PlenumNotFound) { + + // need to allocate additional space for new plenum array + // keep track of how many arrays (i.e., how many different plenums are attached to different ideal loads air systems) + state.dataPurchasedAirMgr->NumPlenumArrays += 1; + + // allocate temporary array and save existing data + state.dataPurchasedAirMgr->TempPurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays); + for (Loop = 1; Loop < state.dataPurchasedAirMgr->NumPlenumArrays; ++Loop) { + state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir = + state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir; + state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).ReturnPlenumIndex = + state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).ReturnPlenumIndex; + state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).PurchAirArray.allocate( + state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir); + state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).IsSimulated.allocate( + state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir); + for (Loop2 = 1; Loop2 <= state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir; ++Loop2) { + state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).PurchAirArray(Loop2) = + state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).PurchAirArray(Loop2); + state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).IsSimulated(Loop2) = + state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).IsSimulated(Loop2); } + } + + // delete primary array (probably could just re-allocate, but this is only done a few times per simulation) + state.dataPurchasedAirMgr->PurchAirPlenumArrays.deallocate(); + // reallocate to new size + state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays); - // save the data - state.dataPurchasedAirMgr->PurchAirPlenumArrays = state.dataPurchasedAirMgr->TempPurchAirPlenumArrays; - // delete temporary data - state.dataPurchasedAirMgr->TempPurchAirPlenumArrays.deallocate(); - - // save the index to where this ideal loads air system data is stored - state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex = 1; - // save the number of ideal loads air systems stored in these arrays - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).NumPurchAir = 1; - // save the index the the ZoneHVAC:ReturnPlenum - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).ReturnPlenumIndex = ReturnPlenumIndex; - // allocate member array and store data - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray.allocate(1); - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray(1) = PurchAirNum; - // allocate member array and store data - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated.allocate(1); - state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated(1) = false; + // allocate member arrays to same size as before + for (Loop = 1; Loop < state.dataPurchasedAirMgr->NumPlenumArrays; ++Loop) { + state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).PurchAirArray.allocate( + state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir); + state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).IsSimulated.allocate( + state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir); } + + // save the data + state.dataPurchasedAirMgr->PurchAirPlenumArrays = state.dataPurchasedAirMgr->TempPurchAirPlenumArrays; + // delete temporary data + state.dataPurchasedAirMgr->TempPurchAirPlenumArrays.deallocate(); + + // save the index to where this ideal loads air system data is stored + state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex = 1; + // save the number of ideal loads air systems stored in these arrays + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).NumPurchAir = 1; + // save the index the the ZoneHVAC:ReturnPlenum + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).ReturnPlenumIndex = ReturnPlenumIndex; + // allocate member array and store data + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray.allocate(1); + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray(1) = PurchAirNum; + // allocate member array and store data + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated.allocate(1); + state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated(1) = false; } } +} -} // namespace EnergyPlus +} // namespace EnergyPlus::PurchasedAirManager diff --git a/src/EnergyPlus/PurchasedAirManager.hh b/src/EnergyPlus/PurchasedAirManager.hh index 8e071b6a81d..a4adfd8bc39 100644 --- a/src/EnergyPlus/PurchasedAirManager.hh +++ b/src/EnergyPlus/PurchasedAirManager.hh @@ -64,30 +64,33 @@ struct EnergyPlusData; namespace PurchasedAirManager { // Heating and Cooling Limit type parameters - enum class LimitType { + enum class LimitType + { Unassigned, NoLimit, LimitFlowRate, LimitCapacity, LimitFlowRateAndCapacity }; - constexpr const char * cLimitType(LimitType l) { + constexpr const char *cLimitType(LimitType l) + { switch (l) { - case LimitType::NoLimit: - return "NoLimit"; - case LimitType::LimitFlowRate: - return "LimitFlowRate"; - case LimitType::LimitCapacity: - return "LimitCapacity"; - case LimitType::LimitFlowRateAndCapacity: - return "LimitFlowRateAndCapacity"; - default: - return "UNKNOWN!"; + case LimitType::NoLimit: + return "NoLimit"; + case LimitType::LimitFlowRate: + return "LimitFlowRate"; + case LimitType::LimitCapacity: + return "LimitCapacity"; + case LimitType::LimitFlowRateAndCapacity: + return "LimitFlowRateAndCapacity"; + default: + return "UNKNOWN!"; } } // Dehumidification and Humidification control type parameters - enum class HumControl { + enum class HumControl + { Unassigned, None, ConstantSensibleHeatRatio, @@ -96,7 +99,8 @@ namespace PurchasedAirManager { }; // Demand controlled ventilation type parameters - enum class DCV { + enum class DCV + { Unassigned, NoDCV, OccupancySchedule, @@ -104,7 +108,8 @@ namespace PurchasedAirManager { }; // Outdoor air economizer type parameters - enum class Econ { + enum class Econ + { Unassigned, NoEconomizer, DifferentialDryBulb, @@ -112,7 +117,8 @@ namespace PurchasedAirManager { }; // Heat recovery type parameters - enum class HeatRecovery { + enum class HeatRecovery + { Unassigned, NoHeatRecovery, Sensible, @@ -120,7 +126,8 @@ namespace PurchasedAirManager { }; // Operating mode parameters - enum class OpMode { + enum class OpMode + { Off, Heat, Cool, @@ -146,21 +153,21 @@ namespace PurchasedAirManager { Real64 MinCoolSuppAirTemp; // Minimum supply air temperature for cooling [C] Real64 MaxHeatSuppAirHumRat; // Maximum supply heating air humidity ratio [kg water/kg dry air] Real64 MinCoolSuppAirHumRat; // Minimum supply cooling air humidity ratio [kg water/kg dry air] - LimitType HeatingLimit; // Heating capacity limit type - NoLimit, LimitFlowRate, LimitCapacity, + LimitType HeatingLimit; // Heating capacity limit type - NoLimit, LimitFlowRate, LimitCapacity, // or LimitFlowRateAndCapacity Real64 MaxHeatVolFlowRate; // Maximum heating supply air flow[m3/s] Real64 MaxHeatSensCap; // Maximum heating sensible capacity [W] - LimitType CoolingLimit; // Cooling capacity limit type - NoLimit, LimitFlowRate, LimitCapacity, + LimitType CoolingLimit; // Cooling capacity limit type - NoLimit, LimitFlowRate, LimitCapacity, // or LimitFlowRateAndCapacity - Real64 MaxCoolVolFlowRate; // Maximum cooling supply air flow [m3/s] - Real64 MaxCoolTotCap; // Maximum cooling total capacity [W] - std::string HeatSched; // Heating availablity schedule - int HeatSchedPtr; // Index to heating availability schedule - std::string CoolSched; // Cooling availability schedule - int CoolSchedPtr; // Index to the cooling availability schedule - HumControl DehumidCtrlType; // Dehumidification control type - ConstantSensibleHeatRatio, + Real64 MaxCoolVolFlowRate; // Maximum cooling supply air flow [m3/s] + Real64 MaxCoolTotCap; // Maximum cooling total capacity [W] + std::string HeatSched; // Heating availablity schedule + int HeatSchedPtr; // Index to heating availability schedule + std::string CoolSched; // Cooling availability schedule + int CoolSchedPtr; // Index to the cooling availability schedule + HumControl DehumidCtrlType; // Dehumidification control type - ConstantSensibleHeatRatio, // Humidistat, or ConstantSupplyHumidityRatio - Real64 CoolSHR; // Cooling sensible heat ratio + Real64 CoolSHR; // Cooling sensible heat ratio HumControl HumidCtrlType; // Humidification control type - None, // Humidistat, or ConstantSupplyHumidityRatio int OARequirementsPtr; // Index to DesignSpecification:OutdoorAir object @@ -170,7 +177,7 @@ namespace PurchasedAirManager { // DifferentialDryBulb, or DifferentialEnthalpy bool OutdoorAir; // Is there outdoor air? int OutdoorAirNodeNum; // Node number of the outdoor air inlet node - HeatRecovery HtRecType; // Outdoor air heat recovery type - None, Sensible, Enthalpy + HeatRecovery HtRecType; // Outdoor air heat recovery type - None, Sensible, Enthalpy Real64 HtRecSenEff; // Sensible heat recovery effectiveness Real64 HtRecLatEff; // Latent heat recovery effectiveness int OAFlowFracSchPtr; // Fraction schedule applied to total OA requirement @@ -190,8 +197,6 @@ namespace PurchasedAirManager { Real64 SupplyAirMassFlowRate; // Supply air mass flow rate [kg/s] Real64 SupplyAirVolFlowRateStdRho; // supply air volume flow using standard density [m3/s] // Intermediate results - Real64 FinalMixedAirTemp; // Dry-bulb temperature of the mixed air, saved for system ventilation load reporting [C] - Real64 FinalMixedAirHumRat; // Humidity ratio of the mixed air, saved for system ventilation load reporting [kgWater/kgDryAir] Real64 HtRecSenOutput; // Sensible heating/cooling rate from heat recovery (<0 means cooling) [W] Real64 HtRecLatOutput; // Latent heating/cooling rate from heat recovery (<0 means cooling or dehumidfying) [W] Real64 OASenOutput; // Outdoor air sensible output relative to zone conditions [W], <0 means OA is cooler than zone air @@ -262,32 +267,36 @@ namespace PurchasedAirManager { Real64 TimeHtRecActive; // Time heat reocovery is active [hrs] int ZonePtr; // pointer to a zone served by an Ideal load air system int HVACSizingIndex; // index of a HVAC Sizing object for an Ideal load air system + Real64 SupplyTemp; // Supply inlet to zone dry bulb temperature [C] + Real64 SupplyHumRat; // Supply inlet to zone humidity ratio [kgWater/kgDryAir] + Real64 MixedAirTemp; // Mixed air dry bulb temperature [C] + Real64 MixedAirHumRat; // Mixed air humidity ratio [kgWater/kgDryAir] // Default Constructor ZonePurchasedAir() : AvailSchedPtr(0), ZoneSupplyAirNodeNum(0), ZoneExhaustAirNodeNum(0), PlenumExhaustAirNodeNum(0), ReturnPlenumIndex(0), - PurchAirArrayIndex(0), ZoneRecircAirNodeNum(0), MaxHeatSuppAirTemp(0.0), MinCoolSuppAirTemp(0.0), - MaxHeatSuppAirHumRat(0.0), MinCoolSuppAirHumRat(0.0), HeatingLimit(LimitType::Unassigned), MaxHeatVolFlowRate(0.0), MaxHeatSensCap(0.0), CoolingLimit(LimitType::Unassigned), - MaxCoolVolFlowRate(0.0), MaxCoolTotCap(0.0), HeatSchedPtr(0), CoolSchedPtr(0), DehumidCtrlType(HumControl::Unassigned), CoolSHR(0.0), HumidCtrlType(HumControl::Unassigned), - OARequirementsPtr(0), DCVType(DCV::Unassigned), EconomizerType(Econ::Unassigned), OutdoorAir(false), OutdoorAirNodeNum(0), HtRecType(HeatRecovery::Unassigned), HtRecSenEff(0.0), - HtRecLatEff(0.0), OAFlowFracSchPtr(0), MaxHeatMassFlowRate(0.0), MaxCoolMassFlowRate(0.0), EMSOverrideMdotOn(false), - EMSValueMassFlowRate(0.0), EMSOverrideOAMdotOn(false), EMSValueOAMassFlowRate(0.0), - EMSOverrideSupplyTempOn(false), EMSValueSupplyTemp(0.0), EMSOverrideSupplyHumRatOn(false), - EMSValueSupplyHumRat(0.0), MinOAMassFlowRate(0.0), - OutdoorAirMassFlowRate(0.0), OutdoorAirVolFlowRateStdRho(0.0), SupplyAirMassFlowRate(0.0), SupplyAirVolFlowRateStdRho(0.0), - FinalMixedAirTemp(0.0), FinalMixedAirHumRat(0.0), HtRecSenOutput(0.0), HtRecLatOutput(0.0), OASenOutput(0.0), OALatOutput(0.0), - SenOutputToZone(0.0), LatOutputToZone(0.0), SenCoilLoad(0.0), LatCoilLoad(0.0), OAFlowMaxCoolOutputError(0), - OAFlowMaxHeatOutputError(0), SaturationOutputError(0), OAFlowMaxCoolOutputIndex(0), OAFlowMaxHeatOutputIndex(0), - SaturationOutputIndex(0), AvailStatus(0), CoolErrIndex(0), HeatErrIndex(0), SenHeatEnergy(0.0), LatHeatEnergy(0.0), TotHeatEnergy(0.0), - SenCoolEnergy(0.0), LatCoolEnergy(0.0), TotCoolEnergy(0.0), ZoneSenHeatEnergy(0.0), ZoneLatHeatEnergy(0.0), ZoneTotHeatEnergy(0.0), - ZoneSenCoolEnergy(0.0), ZoneLatCoolEnergy(0.0), ZoneTotCoolEnergy(0.0), OASenHeatEnergy(0.0), OALatHeatEnergy(0.0), - OATotHeatEnergy(0.0), OASenCoolEnergy(0.0), OALatCoolEnergy(0.0), OATotCoolEnergy(0.0), HtRecSenHeatEnergy(0.0), - HtRecLatHeatEnergy(0.0), HtRecTotHeatEnergy(0.0), HtRecSenCoolEnergy(0.0), HtRecLatCoolEnergy(0.0), HtRecTotCoolEnergy(0.0), - SenHeatRate(0.0), LatHeatRate(0.0), TotHeatRate(0.0), SenCoolRate(0.0), LatCoolRate(0.0), TotCoolRate(0.0), ZoneSenHeatRate(0.0), - ZoneLatHeatRate(0.0), ZoneTotHeatRate(0.0), ZoneSenCoolRate(0.0), ZoneLatCoolRate(0.0), ZoneTotCoolRate(0.0), OASenHeatRate(0.0), - OALatHeatRate(0.0), OATotHeatRate(0.0), OASenCoolRate(0.0), OALatCoolRate(0.0), OATotCoolRate(0.0), HtRecSenHeatRate(0.0), - HtRecLatHeatRate(0.0), HtRecTotHeatRate(0.0), HtRecSenCoolRate(0.0), HtRecLatCoolRate(0.0), HtRecTotCoolRate(0.0), TimeEconoActive(0.0), - TimeHtRecActive(0.0), ZonePtr(0), HVACSizingIndex(0) + PurchAirArrayIndex(0), ZoneRecircAirNodeNum(0), MaxHeatSuppAirTemp(0.0), MinCoolSuppAirTemp(0.0), MaxHeatSuppAirHumRat(0.0), + MinCoolSuppAirHumRat(0.0), HeatingLimit(LimitType::Unassigned), MaxHeatVolFlowRate(0.0), MaxHeatSensCap(0.0), + CoolingLimit(LimitType::Unassigned), MaxCoolVolFlowRate(0.0), MaxCoolTotCap(0.0), HeatSchedPtr(0), CoolSchedPtr(0), + DehumidCtrlType(HumControl::Unassigned), CoolSHR(0.0), HumidCtrlType(HumControl::Unassigned), OARequirementsPtr(0), + DCVType(DCV::Unassigned), EconomizerType(Econ::Unassigned), OutdoorAir(false), OutdoorAirNodeNum(0), + HtRecType(HeatRecovery::Unassigned), HtRecSenEff(0.0), HtRecLatEff(0.0), OAFlowFracSchPtr(0), MaxHeatMassFlowRate(0.0), + MaxCoolMassFlowRate(0.0), EMSOverrideMdotOn(false), EMSValueMassFlowRate(0.0), EMSOverrideOAMdotOn(false), EMSValueOAMassFlowRate(0.0), + EMSOverrideSupplyTempOn(false), EMSValueSupplyTemp(0.0), EMSOverrideSupplyHumRatOn(false), EMSValueSupplyHumRat(0.0), + MinOAMassFlowRate(0.0), OutdoorAirMassFlowRate(0.0), OutdoorAirVolFlowRateStdRho(0.0), SupplyAirMassFlowRate(0.0), + SupplyAirVolFlowRateStdRho(0.0), HtRecSenOutput(0.0), HtRecLatOutput(0.0), OASenOutput(0.0), OALatOutput(0.0), SenOutputToZone(0.0), + LatOutputToZone(0.0), SenCoilLoad(0.0), LatCoilLoad(0.0), OAFlowMaxCoolOutputError(0), OAFlowMaxHeatOutputError(0), + SaturationOutputError(0), OAFlowMaxCoolOutputIndex(0), OAFlowMaxHeatOutputIndex(0), SaturationOutputIndex(0), AvailStatus(0), + CoolErrIndex(0), HeatErrIndex(0), SenHeatEnergy(0.0), LatHeatEnergy(0.0), TotHeatEnergy(0.0), SenCoolEnergy(0.0), LatCoolEnergy(0.0), + TotCoolEnergy(0.0), ZoneSenHeatEnergy(0.0), ZoneLatHeatEnergy(0.0), ZoneTotHeatEnergy(0.0), ZoneSenCoolEnergy(0.0), + ZoneLatCoolEnergy(0.0), ZoneTotCoolEnergy(0.0), OASenHeatEnergy(0.0), OALatHeatEnergy(0.0), OATotHeatEnergy(0.0), OASenCoolEnergy(0.0), + OALatCoolEnergy(0.0), OATotCoolEnergy(0.0), HtRecSenHeatEnergy(0.0), HtRecLatHeatEnergy(0.0), HtRecTotHeatEnergy(0.0), + HtRecSenCoolEnergy(0.0), HtRecLatCoolEnergy(0.0), HtRecTotCoolEnergy(0.0), SenHeatRate(0.0), LatHeatRate(0.0), TotHeatRate(0.0), + SenCoolRate(0.0), LatCoolRate(0.0), TotCoolRate(0.0), ZoneSenHeatRate(0.0), ZoneLatHeatRate(0.0), ZoneTotHeatRate(0.0), + ZoneSenCoolRate(0.0), ZoneLatCoolRate(0.0), ZoneTotCoolRate(0.0), OASenHeatRate(0.0), OALatHeatRate(0.0), OATotHeatRate(0.0), + OASenCoolRate(0.0), OALatCoolRate(0.0), OATotCoolRate(0.0), HtRecSenHeatRate(0.0), HtRecLatHeatRate(0.0), HtRecTotHeatRate(0.0), + HtRecSenCoolRate(0.0), HtRecLatCoolRate(0.0), HtRecTotCoolRate(0.0), TimeEconoActive(0.0), TimeHtRecActive(0.0), ZonePtr(0), + HVACSizingIndex(0), SupplyTemp(0.0), SupplyHumRat(0.0), MixedAirTemp(0.0), MixedAirHumRat(0.0) { } }; @@ -317,17 +326,19 @@ namespace PurchasedAirManager { // Object Data - void SimPurchasedAir(EnergyPlusData &state, std::string const &PurchAirName, + void SimPurchasedAir(EnergyPlusData &state, + std::string const &PurchAirName, Real64 &SysOutputProvided, Real64 &MoistOutputProvided, // Moisture output provided (kg/s), dehumidification = negative - bool FirstHVACIteration, + bool FirstHVACIteration, int ControlledZoneNum, int ActualZoneNum, int &CompIndex); void GetPurchasedAir(EnergyPlusData &state); - void InitPurchasedAir(EnergyPlusData &state, int PurchAirNum, + void InitPurchasedAir(EnergyPlusData &state, + int PurchAirNum, bool FirstHVACIteration, // unused1208 int ControlledZoneNum, int ActualZoneNum); @@ -342,19 +353,19 @@ namespace PurchasedAirManager { int ActualZoneNum); void CalcPurchAirMinOAMassFlow(EnergyPlusData &state, - int PurchAirNum, // index to ideal loads unit - int ActualZoneNum, // index to actual zone number - Real64 &OAMassFlowRate // outside air mass flow rate [kg/s] from volume flow using std density + int PurchAirNum, // index to ideal loads unit + int ActualZoneNum, // index to actual zone number + Real64 &OAMassFlowRate // outside air mass flow rate [kg/s] from volume flow using std density ); void CalcPurchAirMixedAir(EnergyPlusData &state, int PurchAirNum, // index to ideal loads unit Real64 OAMassFlowRate, // outside air mass flow rate [kg/s] Real64 SupplyMassFlowRate, // supply air mass flow rate [kg/s] - Real64 &MixedAirTemp, // Mixed air dry bulb temperature [C] - Real64 &MixedAirHumRat, // Mixed air humidity ratio [kgWater/kgDryAir] - Real64 &MixedAirEnthalpy, // Mixed air enthalpy [J/kg] - OpMode OperatingMode // current operating mode, Off, Heating, Cooling, or DeadBand + Real64 &MixedAirTemp, // Mixed air dry bulb temperature [C] + Real64 &MixedAirHumRat, // Mixed air humidity ratio [kgWater/kgDryAir] + Real64 &MixedAirEnthalpy, // Mixed air enthalpy [J/kg] + OpMode OperatingMode // current operating mode, Off, Heating, Cooling, or DeadBand ); void UpdatePurchasedAir(EnergyPlusData &state, int PurchAirNum, bool FirstHVACIteration); @@ -377,7 +388,8 @@ namespace PurchasedAirManager { } // namespace PurchasedAirManager -struct PurchasedAirManagerData : BaseGlobalStruct { +struct PurchasedAirManagerData : BaseGlobalStruct +{ int NumPurchAir = 0; int NumPlenumArrays = 0; // total number of plenum arrays bool GetPurchAirInputFlag = true; @@ -390,7 +402,8 @@ struct PurchasedAirManagerData : BaseGlobalStruct { Array1D_bool InitPurchasedAirMyEnvrnFlag; Array1D_bool InitPurchasedAirMySizeFlag; Array1D_bool InitPurchasedAirOneTimeUnitInitsDone; // True if one-time inits for PurchAirNum are completed - Array1D TempPurchAirPlenumArrays; // Used to save the indices of scalable sizing object for zone HVAC + Array1D + TempPurchAirPlenumArrays; // Used to save the indices of scalable sizing object for zone HVAC void clear_state() override { diff --git a/src/EnergyPlus/ScheduleManager.hh b/src/EnergyPlus/ScheduleManager.hh index 13a08269c1c..0d197fb98fc 100644 --- a/src/EnergyPlus/ScheduleManager.hh +++ b/src/EnergyPlus/ScheduleManager.hh @@ -218,8 +218,8 @@ namespace ScheduleManager { int GetDayScheduleIndex(EnergyPlusData &state, std::string &ScheduleName); - void - GetScheduleValuesForDay(EnergyPlusData &state, int const ScheduleIndex, Array2S DayValues, Optional_int_const JDay = _, Optional_int_const CurDayofWeek = _); + void GetScheduleValuesForDay( + EnergyPlusData &state, int const ScheduleIndex, Array2S DayValues, Optional_int_const JDay = _, Optional_int_const CurDayofWeek = _); void GetSingleDayScheduleValues(EnergyPlusData &state, int const DayScheduleIndex, // Index of the DaySchedule for values @@ -231,7 +231,8 @@ namespace ScheduleManager { Real64 &Value // The new value for the schedule ); - void ProcessIntervalFields(EnergyPlusData &state, Array1S_string const Untils, + void ProcessIntervalFields(EnergyPlusData &state, + Array1S_string const Untils, Array1S const Numbers, int const NumUntils, int const NumNumbers, @@ -243,7 +244,8 @@ namespace ScheduleManager { ScheduleInterpolation interpolationKind // enumeration on how to interpolate values in schedule ); - void DecodeHHMMField(EnergyPlusData &state, std::string const &FieldValue, // Input field value + void DecodeHHMMField(EnergyPlusData &state, + std::string const &FieldValue, // Input field value int &RetHH, // Returned "hour" int &RetMM, // Returned "minute" bool &ErrorsFound, // True if errors found in this field @@ -254,30 +256,35 @@ namespace ScheduleManager { bool isMinuteMultipleOfTimestep(int minute, int numMinutesPerTimestep); - void ProcessForDayTypes(EnergyPlusData &state, std::string const &ForDayField, // Field containing the "FOR:..." + void ProcessForDayTypes(EnergyPlusData &state, + std::string const &ForDayField, // Field containing the "FOR:..." Array1D_bool &TheseDays, // Array to contain returned "true" days Array1D_bool &AlReady, // Array of days already done bool &ErrorsFound // Will be true if error found. ); - bool CheckScheduleValueMinMax(EnergyPlusData &state, int const ScheduleIndex, // Which Schedule being tested + bool CheckScheduleValueMinMax(EnergyPlusData &state, + int const ScheduleIndex, // Which Schedule being tested std::string const &MinString, // Minimum indicator ('>', '>=') Real64 const Minimum // Minimum desired value ); - bool CheckScheduleValueMinMax(EnergyPlusData &state, int const ScheduleIndex, // Which Schedule being tested + bool CheckScheduleValueMinMax(EnergyPlusData &state, + int const ScheduleIndex, // Which Schedule being tested std::string const &MinString, // Minimum indicator ('>', '>=') Real64 const Minimum, // Minimum desired value std::string const &MaxString, // Maximum indicator ('<', ',=') Real64 const Maximum // Maximum desired value ); - bool CheckScheduleValueMinMax(EnergyPlusData &state, int const ScheduleIndex, // Which Schedule being tested + bool CheckScheduleValueMinMax(EnergyPlusData &state, + int const ScheduleIndex, // Which Schedule being tested std::string const &MinString, // Minimum indicator ('>', '>=') Real32 const Minimum // Minimum desired value ); - bool CheckScheduleValueMinMax(EnergyPlusData &state, int const ScheduleIndex, // Which Schedule being tested + bool CheckScheduleValueMinMax(EnergyPlusData &state, + int const ScheduleIndex, // Which Schedule being tested std::string const &MinString, // Minimum indicator ('>', '>=') Real32 const Minimum, // Minimum desired value std::string const &MaxString, // Maximum indicator ('<', ',=') @@ -302,7 +309,8 @@ namespace ScheduleManager { Optional_string_const MaxString = _ // Maximum indicator ('<', ',=') ); - bool CheckDayScheduleValueMinMax(EnergyPlusData &state, int const ScheduleIndex, // Which Day Schedule being tested + bool CheckDayScheduleValueMinMax(EnergyPlusData &state, + int const ScheduleIndex, // Which Day Schedule being tested Real32 const Minimum, // Minimum desired value std::string const &MinString, // Minimum indicator ('>', '>=') Optional Maximum = _, // Maximum desired value @@ -333,7 +341,8 @@ namespace ScheduleManager { bool const isItLeapYear // true if it is a leap year containing February 29 ); - Real64 ScheduleHoursGT1perc(EnergyPlusData &state, int const ScheduleIndex, // Which Schedule being tested + Real64 ScheduleHoursGT1perc(EnergyPlusData &state, + int const ScheduleIndex, // Which Schedule being tested int const StartDayOfWeek, // Day of week for start of year bool const isItLeapYear // true if it is a leap year containing February 29 ); @@ -342,11 +351,11 @@ namespace ScheduleManager { } // namespace ScheduleManager -struct ScheduleManagerData : BaseGlobalStruct { +struct ScheduleManagerData : BaseGlobalStruct +{ void clear_state() override { - } }; diff --git a/testfiles/HVACTemplate-5ZonePurchAir.idf b/testfiles/HVACTemplate-5ZonePurchAir.idf index 2e801a79d0c..4992701fe7c 100644 --- a/testfiles/HVACTemplate-5ZonePurchAir.idf +++ b/testfiles/HVACTemplate-5ZonePurchAir.idf @@ -1930,6 +1930,16 @@ Output:Variable,*,Zone Ideal Loads Heat Recovery Active Time,hourly; + Output:Variable,*,Zone Ideal Loads Supply Air Temperature,hourly; + + Output:Variable,*,Zone Ideal Loads Supply Air Humidity Ratio,hourly; + + Output:Variable,*,Zone Ideal Loads Mixed Air Temperature,hourly; + + Output:Variable,*,Zone Ideal Loads Mixed Air Humidity Ratio,hourly; + + Output:Variable,*,System Node Mass Flow Rate,hourly; + Output:Variable,SPACE2-1 Ideal Loads Outdoor Air Inlet,System Node Standard Density Volume Flow Rate,hourly; Output:Variable,SPACE3-1 Ideal Loads Outdoor Air Inlet,System Node Standard Density Volume Flow Rate,hourly; @@ -1969,4 +1979,3 @@ Output:Table:SummaryReports, AllSummary; !- Report 1 Name - diff --git a/testfiles/HVACTemplate-5ZonePurchAir.rvi b/testfiles/HVACTemplate-5ZonePurchAir.rvi index 077889bc131..91238e9addb 100644 --- a/testfiles/HVACTemplate-5ZonePurchAir.rvi +++ b/testfiles/HVACTemplate-5ZonePurchAir.rvi @@ -13,5 +13,9 @@ Zone Ideal Loads Supply Air Latent Heating Rate Zone Ideal Loads Supply Air Total Heating Rate Zone Ideal Loads Economizer Active Time Zone Ideal Loads Heat Recovery Active Time +Zone Ideal Loads Supply Air Temperature +Zone Ideal Loads Supply Air Humidity Ratio +Zone Ideal Loads Mixed Air Temperature +Zone Ideal Loads Mixed Air Humidity Ratio System Node Standard Density Volume Flow Rate 0 diff --git a/tst/EnergyPlus/unit/PurchasedAirManager.unit.cc b/tst/EnergyPlus/unit/PurchasedAirManager.unit.cc index dd44c9a3689..b22c3556d7c 100644 --- a/tst/EnergyPlus/unit/PurchasedAirManager.unit.cc +++ b/tst/EnergyPlus/unit/PurchasedAirManager.unit.cc @@ -65,11 +65,13 @@ #include #include #include +#include #include #include #include #include #include +#include using namespace EnergyPlus; using namespace ObjexxFCL; @@ -520,6 +522,173 @@ TEST_F(ZoneIdealLoadsTest, IdealLoads_ExhaustNodeTest) EXPECT_EQ(PurchAir(1).SupplyAirMassFlowRate, Node(PurchAir(1).ZoneExhaustAirNodeNum).MassFlowRate); } +TEST_F(ZoneIdealLoadsTest, IdealLoads_IntermediateOutputVarsTest) +{ + + std::string const idf_objects = delimited_string({ + + "Zone,", + " EAST ZONE, !- Name", + " 0, !- Direction of Relative North{ deg }", + " 0, !- X Origin{ m }", + " 0, !- Y Origin{ m }", + " 0, !- Z Origin{ m }", + " 1, !- Type", + " 1, !- Multiplier", + " autocalculate, !- Ceiling Height{ m }", + " autocalculate; !- Volume{ m3 }", + + "ZoneHVAC:IdealLoadsAirSystem,", + " ZONE 1 IDEAL LOADS, !- Name", + " , !- Availability Schedule Name", + " Zone Inlet Node, !- Zone Supply Air Node Name", + " Zone Exhaust Node, !- Zone Exhaust Air Node Name", + " , !- System Inlet Air Node Name", + " 50, !- Maximum Heating Supply Air Temperature{ C }", + " 13, !- Minimum Cooling Supply Air Temperature{ C }", + " 0.015, !- Maximum Heating Supply Air Humidity Ratio{ kgWater / kgDryAir }", + " 0.009, !- Minimum Cooling Supply Air Humidity Ratio{ kgWater / kgDryAir }", + " NoLimit, !- Heating Limit", + " autosize, !- Maximum Heating Air Flow Rate{ m3 / s }", + " , !- Maximum Sensible Heating Capacity{ W }", + " NoLimit, !- Cooling Limit", + " autosize, !- Maximum Cooling Air Flow Rate{ m3 / s }", + " , !- Maximum Total Cooling Capacity{ W }", + " , !- Heating Availability Schedule Name", + " , !- Cooling Availability Schedule Name", + " ConstantSupplyHumidityRatio, !- Dehumidification Control Type", + " , !- Cooling Sensible Heat Ratio{ dimensionless }", + " ConstantSupplyHumidityRatio, !- Humidification Control Type", + " Office Outdoor Air Spec, !- Design Specification Outdoor Air Object Name", + " , !- Outdoor Air Inlet Node Name", + " , !- Demand Controlled Ventilation Type", + " NoEconomizer, !- Outdoor Air Economizer Type", + " Sensible, !- Heat Recovery Type", + " 0.7, !- Sensible Heat Recovery Effectiveness{ dimensionless }", + " 0.65; !- Latent Heat Recovery Effectiveness{ dimensionless }", + + "DesignSpecification:OutdoorAir,", + " Office Outdoor Air Spec, !- Name", + " Flow/Zone, !- Outdoor Air Method", + " 0.0, !- Outdoor Air Flow per Person {m3/s-person}", + " 0.00305, !- Outdoor Air Flow per Zone Floor Area {m3/s-m2}", + " 0.0, !- Outdoor Air Flow per Zone {m3/s}", + " 0.0, !- Outdoor Air Flow Air Changes per Hour {1/hr}", + " Min OA Sched; !- Outdoor Air Schedule Name", + + "Schedule:Compact,", + " Min OA Sched, !- Name", + " Fraction, !- Schedule Type Limits Name", + " Through: 12/31, !- Field 1", + " For: WeekDays CustomDay1 CustomDay2, !- Field 2", + " Until: 8:00,0.0, !- Field 3", + " Until: 21:00,1.0, !- Field 5", + " Until: 24:00,0.0, !- Field 7", + " For: Weekends Holiday, !- Field 9", + " Until: 24:00,0.0, !- Field 10", + " For: SummerDesignDay, !- Field 12", + " Until: 24:00,1.0, !- Field 13", + " For: WinterDesignDay, !- Field 15", + " Until: 24:00,1.0; !- Field 16", + + "ZoneHVAC:EquipmentConnections,", + " EAST ZONE, !- Zone Name", + " ZoneEquipment, !- Zone Conditioning Equipment List Name", + " Zone Inlet Node, !- Zone Air Inlet Node or NodeList Name", + " Zone Exhaust Node, !- Zone Air Exhaust Node or NodeList Name", + " Zone Node, !- Zone Air Node Name", + " Zone Outlet Node; !- Zone Return Air Node Name", + + "ZoneHVAC:EquipmentList,", + " ZoneEquipment, !- Name", + " SequentialLoad, !- Load Distribution Scheme", + " ZoneHVAC:IdealLoadsAirSystem, !- Zone Equipment 1 Object Type", + " ZONE 1 IDEAL LOADS, !- Zone Equipment 1 Name", + " 1, !- Zone Equipment 1 Cooling Sequence", + " 1; !- Zone Equipment 1 Heating or No - Load Sequence", + + "AirLoopHVAC:ReturnPlenum,", + " DOAS Zone Return Plenum, !- Name", + " PLENUM ZONE, !- Zone Name", + " Plenum Node, !- Zone Node Name", // illegal use of non-unique zone node name + " Plenum Outlet Node, !- Outlet Node Name", + " , !- Induced Air Outlet Node or NodeList Name", + " Zone Exhaust Node; !- Inlet 1 Node Name", + + }); + + ASSERT_TRUE(process_idf(idf_objects)); // read idf objects + + state->dataGlobal->DoWeathSim = true; + + bool ErrorsFound = false; + GetZoneData(*state, ErrorsFound); + Zone(1).SurfaceFirst = 1; + Zone(1).SurfaceLast = 1; + ScheduleManager::Schedule.allocate(1); + AllocateHeatBalArrays(*state); + EXPECT_FALSE(ErrorsFound); // expect no errors + auto & PurchAir(state->dataPurchasedAirMgr->PurchAir); + + + bool FirstHVACIteration(true); + bool SimZone(true); + bool SimAir(false); + + EnergyPlus::SizingManager::GetOARequirements(*state); + ManageZoneEquipment(*state, + FirstHVACIteration, + SimZone, + SimAir); // read zone equipment configuration and list objects and simulate ideal loads air system + + + EXPECT_EQ(PurchAir(1).Name, "ZONE 1 IDEAL LOADS"); + // Expecting SupplyTemp to be the same as Zone supply temp + EXPECT_EQ(PurchAir(1).SupplyTemp, Node(PurchAir(1).ZoneSupplyAirNodeNum).Temp); + EXPECT_EQ(PurchAir(1).SupplyHumRat, Node(PurchAir(1).ZoneSupplyAirNodeNum).HumRat); + + // Test for intermediate variables, MixedAirTemp, MixedAirHumRat + Node(PurchAir(1).ZoneRecircAirNodeNum).Temp = 24; + Node(PurchAir(1).ZoneRecircAirNodeNum).HumRat = 0.00929; + Node(PurchAir(1).ZoneRecircAirNodeNum).Enthalpy = Psychrometrics::PsyHFnTdbW( + Node(PurchAir(1).ZoneRecircAirNodeNum).Temp, + Node(PurchAir(1).ZoneRecircAirNodeNum).HumRat + ); + Node(PurchAir(1).OutdoorAirNodeNum).Temp = 3; + Node(PurchAir(1).OutdoorAirNodeNum).HumRat = 0.004586; + Node(PurchAir(1).OutdoorAirNodeNum).Enthalpy = Psychrometrics::PsyHFnTdbW( + Node(PurchAir(1).OutdoorAirNodeNum).Temp, + Node(PurchAir(1).OutdoorAirNodeNum).HumRat + ); + PurchAir(1).MixedAirTemp = 0; + PurchAir(1).MixedAirHumRat = 0; + Real64 MixedAirEnthalpy = 0; + Real64 OAMassFlowRate = 10; + Real64 SupplyMassFlowRate = 11; + CalcPurchAirMixedAir(*state, + 1, // index to ideal loads unit + OAMassFlowRate, // outside air mass flow rate [kg/s] + SupplyMassFlowRate, // supply air mass flow rate [kg/s] + PurchAir(1).MixedAirTemp, // Mixed air dry bulb temperature [C] + PurchAir(1).MixedAirHumRat, // Mixed air humidity ratio [kgWater/kgDryAir] + MixedAirEnthalpy, // Mixed air enthalpy [J/kg] + OpMode::Cool // current operating mode, Off, Heating, Cooling, or DeadBand + ); +// Calculations: +// Stream 1: Recirc stream: T1: 24 C; W1: 0.00929 kg/kg; h1: 47764.36 J/kg; m_dot1: 11 kg/s +// Stream 2: Outdoor Air stream: T2: 3 C; W2:0.004586 kg/kg; h2: 14509.40 J/kg; m_dot2: 10 kg/s + +// Mixed stream: +// When SupplyMassFlowRate > OAMassFlowRate +// RecircMassFlowRate = SupplyMassFlowRate - OAMassFlowRate = 1 kg/s +// h_mix_stream = (RecircMassFlowRate X h_Recirc + m_dotOA X h_OA)/SupplyFlowRate = 17532.58 J/kg +// W_mix_stream = (RecircMassFlowRate X W_Recirc + m_dotOA X W_OA)/SupplyFlowRate = 0.005013 kg/kg +// T_mix_stream = T as fn (h_mix_stream,W_mix_stream) = 4.924 C + + EXPECT_EQ(PurchAir(1).MixedAirTemp,4.9240554165264818); + EXPECT_EQ(PurchAir(1).MixedAirHumRat,0.0050136363636363633); +} + TEST_F(ZoneIdealLoadsTest, IdealLoads_EMSOverrideTest) {