NREL / EnergyPlus

EnergyPlus™ is a whole building energy simulation program that engineers, architects, and researchers use to model both energy consumption and water use in buildings.
https://energyplus.net
Other
1.14k stars 392 forks source link

ZoneHVAC:PackagedTerminal units report cooling/heating energy differently from UnitarySystem #9093

Open rraustad opened 3 years ago

rraustad commented 3 years ago

Issue overview

Follow up to #9052.

Testing shows the report variables for parent energy are different. It appears that the packaged terminal model reports correctly since there can be a latent cooling rate during heating mode when outdoor air is considered. Suggest adopting the method used by PTHP.

PTHP:

Zone Packaged Terminal Heat Pump Total Cooling Rate
Zone Packaged Terminal Heat Pump Sensible Cooling Rate
Zone Packaged Terminal Heat Pump Latent Cooling Rate
Zone Packaged Terminal Heat Pump Total Heating Rate
Zone Packaged Terminal Heat Pump Sensible Heating Rate
Zone Packaged Terminal Heat Pump Latent Heating Rate

state.dataPTHP->PTUnit(PTUnitNum).TotCoolEnergyRate = std::abs(min(0.0, QTotUnitOut));
state.dataPTHP->PTUnit(PTUnitNum).TotHeatEnergyRate = std::abs(max(0.0, QTotUnitOut));
state.dataPTHP->PTUnit(PTUnitNum).SensCoolEnergyRate = std::abs(min(0.0, QSensUnitOutNoATM));
state.dataPTHP->PTUnit(PTUnitNum).SensHeatEnergyRate = std::abs(max(0.0, QSensUnitOutNoATM));
state.dataPTHP->PTUnit(PTUnitNum).LatCoolEnergyRate = std::abs(min(0.0, (QTotUnitOut - QSensUnitOutNoATM)));
state.dataPTHP->PTUnit(PTUnitNum).LatHeatEnergyRate = std::abs(max(0.0, (QTotUnitOut - QSensUnitOutNoATM)));

UnitarySystem:

Unitary System Total Cooling Rate
Unitary System Sensible Cooling Rate
Unitary System Latent Cooling Rate
Unitary System Total Heating Rate
Unitary System Sensible Heating Rate
Unitary System Latent Heating Rate

    if (state.dataUnitarySystems->HeatingLoad) {
        if (QTotUnitOut > 0.0) { // heating
            this->m_TotCoolEnergyRate = 0.0;
            this->m_SensCoolEnergyRate = 0.0;
            this->m_LatCoolEnergyRate = 0.0;
            this->m_TotHeatEnergyRate = QTotUnitOut;
            this->m_SensHeatEnergyRate = std::abs(max(0.0, QSensUnitOut));
            this->m_LatHeatEnergyRate = std::abs(max(0.0, (QTotUnitOut - QSensUnitOut)));
        } else {
            this->m_TotCoolEnergyRate = std::abs(QTotUnitOut);
            this->m_SensCoolEnergyRate = std::abs(min(0.0, QSensUnitOut));
            this->m_LatCoolEnergyRate = std::abs(min(0.0, (QTotUnitOut - QSensUnitOut)));
            this->m_TotHeatEnergyRate = 0.0;
            this->m_SensHeatEnergyRate = 0.0;
            this->m_LatHeatEnergyRate = 0.0;
        }
    } else {
        if (QTotUnitOut <= 0.0) { // cooling
            this->m_TotCoolEnergyRate = std::abs(min(0.0, QTotUnitOut));
            this->m_SensCoolEnergyRate = std::abs(min(0.0, QSensUnitOut));
            this->m_LatCoolEnergyRate = std::abs(min(0.0, (QTotUnitOut - QSensUnitOut)));
            this->m_TotHeatEnergyRate = 0.0;
            this->m_SensHeatEnergyRate = 0.0;
            this->m_LatHeatEnergyRate = 0.0;
        } else {
            this->m_TotCoolEnergyRate = 0.0;
            this->m_SensCoolEnergyRate = 0.0;
            this->m_LatCoolEnergyRate = 0.0;
            this->m_TotHeatEnergyRate = QTotUnitOut;
            this->m_SensHeatEnergyRate = std::abs(max(0.0, QSensUnitOut));
            this->m_LatHeatEnergyRate = std::abs(max(0.0, (QTotUnitOut - QSensUnitOut)));
        }
    }

The major difference is in the latent cooling or heating energy since total and sensible cooling or heating occur when the unit is in cooling or heating mode, respectively. Figure compares example file PackagedTerminalHeatPump from V9.5 to V9.6.

image

Details

Some additional details for this issue (if relevant):

Checklist

Add to this list or remove from it as applicable. This is a simple templated set of guidelines.

rraustad commented 2 years ago

Investigation shows it's not the reporting, since these equations do look exactly alike, but the calculation of the rate variables. PTUnits use the old method of calculating delivered capacity.

SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
SpecHumIn = state.dataLoopNodes->Node(InletNode).HumRat;
QLatUnitOut = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate, kg/s (dehumid = negative)
QSensUnitOutNoATM = AirMassFlow * (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat) -
                                   PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
QTotUnitOut = AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy - state.dataLoopNodes->Node(InletNode).Enthalpy);

while UnitarySystem uses the new method.

                CalcZoneSensibleLatentOutput(AirMassFlow,
                                             state.dataLoopNodes->Node(OutletNode).Temp,
                                             state.dataLoopNodes->Node(OutletNode).HumRat,
                                             state.dataLoopNodes->Node(this->NodeNumOfControlledZone).Temp,
                                             state.dataLoopNodes->Node(this->NodeNumOfControlledZone).HumRat,
                                             SensibleOutput,
                                             LatentOutput,
                                             TotalOutput);

When this difference is accounted for there are no differences in results.