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.13k stars 389 forks source link

VRF FluidTCtrl heat pump total heating rate doesn't match zone VRF air terminal total heating rate #10625

Open yujiex opened 3 months ago

yujiex commented 3 months ago

Issue overview

In PR 10331, we fixed the mismatch between heating coil heating rate + supplemental heating rate and the air terminal heating rate. Now that this is fixed, however, the "Zone VRF Air Terminal Total Heating Rate" and "VRF Heat Pump Total Heating Rate" starts to show mismatches. Currently, "VRF Heat Pump Total Heating Rate" is very close to the coil heating rate itself, and is smaller than "Zone VRF Air Terminal Total Heating Rate". According to the documentation, "VRF Heat Pump Total Heating Rate" should match the sum of "Zone VRF Air Terminal Total Heating Rate" ("This value should match the sum of the individual zone terminal unit output variables for Zone VRF Air Terminal Total Heating Rate.")

image

Defect file

The following zip file contains the idf and epw defect file.zip This is the eplusout.csv output eplusout_7000W capacity.xlsx

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.

mjwitte commented 3 months ago

If I remember correctly, for most other zone equipment, the air terminal (or similar) output for cooling and heating is relative to the zone, so it would be net including fan heat effects. Perhaps it's just a documentation issue? Compare with the fancoil outputs to see how they are set up.

yujiex commented 3 months ago

If I remember correctly, for most other zone equipment, the air terminal (or similar) output for cooling and heating is relative to the zone, so it would be net including fan heat effects. Perhaps it's just a documentation issue? Compare with the fancoil outputs to see how they are set up.

Sorry I forgot the fan heat gain in the comparison with the air terminal. I just updated it. Now the air terminal exactly matches the coil + supp heating coil heating rate + fan heat gain. The problem now is the sum of all air terminals (only 1 here) doesn't match the heat pump total heating rate (the orange line). @mjwitte

image

mjwitte commented 3 months ago

"VRF Heat Pump Total Heating Rate" should match the total of the VRF heating coil heating rates. It's close, but the heat pump value is slightly larger than the coil output. Are there any line losses in this model that might explain the difference?

yujiex commented 3 months ago

"VRF Heat Pump Total Heating Rate" should match the total of the VRF heating coil heating rates. It's close, but the heat pump value is slightly larger than the coil output. Are there any line losses in this model that might explain the difference?

I see. The documentation should probably be updated.

I checked why the coil heating rate and heat pump heating rate is different, there are two factors

            auto f = [QCoilSenHeatingLoad, Ts_1, Tin, Garate, BF](Real64 FanSpdRto) {
                return FanSpdResidualHeat(FanSpdRto, QCoilSenHeatingLoad, Ts_1, Tin, Garate, BF);
            };

The following are some relevant code chunks regarding how the piping loss gets involved in the coil heating rate calculation.

// state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond) is computed here
            LimitTUCapacity(state,
                            VRFCond,
                            NumTUInList,
                            TotalTUHeatingCapacity,
                            state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad,
                            state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond),
                            TotalTUCoolingCapacity,
                            state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad,
                            state.dataHVACVarRefFlow->MaxCoolingCapacity(VRFCond));
...
            SimDXCoil(state,
                      "",
                      HVAC::CompressorOp::Off,
                      FirstHVACIteration,
                      this->HeatCoilIndex,
                      fanOp,
                      PartLoadRatio,
                      OnOffAirFlowRatio,
                      _,
                      state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond));
        ...
// from the above, the MaxCap here in CalcVRFHeatingCoil_FluidTCtrl is state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond)
void SimDXCoil(EnergyPlusData &state,...,MaxCap,...) {
    CalcVRFHeatingCoil_FluidTCtrl(state, compressorOp, DXCoilNum, PartLoadRatio, fanOp, _, MaxCap);
}
void CalcVRFHeatingCoil_FluidTCtrl() {
       ...
        if (present(MaxHeatCap)) {
            TotCapAdj = min(MaxHeatCap, TotCap * HeatingCapacityMultiplier);
            TotCap = min(MaxHeatCap, TotCap);
        } else {
            TotCapAdj = TotCap * HeatingCapacityMultiplier;
        }
        QCoilReq = PartLoadRatio * TotCap;
        ...
        ControlVRFIUCoil(state,
                         DXCoilNum,
                         QCoilReq,
                         thisDXCoil.InletAirTemp,
                         thisDXCoil.InletAirHumRat,
                         thisDXCoil.CondensingTemp,
                         AirMassFlowMin,
                         FanSpdRatio,
                         OutletAirHumRat,
                         OutletAirTemp,
                         OutletAirEnthalpy,
                         ActualSH,
                         ActualSC);
        AirMassFlow = FanSpdRatio * thisDXCoil.RatedAirMassFlowRate(Mode);
        ...
        thisDXCoil.TotalHeatingEnergyRate = AirMassFlow * (OutletAirEnthalpy - InletAirEnthalpy) * PartLoadRatio;
}

@mjwitte

yujiex commented 2 months ago

In the corresponding (PR)[https://github.com/NREL/EnergyPlus/pull/10627], in addition to the documentation update, I have changed the fan speed ratio solver to use enthalpy difference instead of temperature difference. This addresses the second factor in the comment above that contributed to the difference between heating coil heating rate and heat pump heating rate.

With this, I would anticipate the VRF HEAT PUMP:VRF Heat Pump Total Heating Rate output multiplied by the VRF HEAT PUMP:VRF Heat Pump Indoor Unit Piping Correction for Heating to match the output TU1 VRF DX HEATING COIL:Heating Coil Heating Rate output. However, they still don't quite match. The following the result table with some summary stats.

image

This is because the reported piping correction is different from the ones used in the calculation.

The following is the heating coil heating rate calculation image

Here we can see the piping correction is computed when the system is at the highest capacity (rated capacity) image

The reported piping correction is recomputed using the updated TotalTUHeatingCapacity value. image

The following are some relevant code snippets

thisDXCoil.TotalHeatingEnergyRate = AirMassFlow * (OutletAirEnthalpy - InletAirEnthalpy) * PartLoadRatio;
// OutletAirEnthalpy and FanSpdRatio are calculated here
        ControlVRFIUCoil(state,
                         DXCoilNum,
                         QCoilReq,
                         thisDXCoil.InletAirTemp,
                         thisDXCoil.InletAirHumRat,
                         thisDXCoil.CondensingTemp,
                         AirMassFlowMin,
                         FanSpdRatio,
                         OutletAirHumRat,
                         OutletAirTemp,
                         OutletAirEnthalpy,
                         ActualSH,
                         ActualSC);
        AirMassFlow = FanSpdRatio * thisDXCoil.RatedAirMassFlowRate(Mode);
// In normal operation thisDXCoil.TotalHeatingEnergyRate should match the demand, QCoilReq. We'll just look at how QCoilReq is determined
// QCoilReq is computed here
        QCoilReq = PartLoadRatio * TotCap;
// TotCap is either the rated capacity, or limited by MaxHeatCap
        TotCap = thisDXCoil.RatedTotCap(Mode);
        if (present(MaxHeatCap)) {
            TotCap = min(MaxHeatCap, TotCap);
        }
// MaxHeatCap is computed in this function, and stored here. The important input is `TotalTUHeatingCapacity`. 
// For the simple case here where there's 1 TU and 1 OU, then `TotalTUHeatingCapacity` would be the coil capacity limit
        if (TU_HeatingLoad > TotalTUHeatingCapacity) {
            LimitTUCapacity(state,
                            VRFCond,
                            NumTUInList,
                            TotalTUHeatingCapacity,
                            state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad,
                            state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond),
                            TotalTUCoolingCapacity,
                            state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad,
                            state.dataHVACVarRefFlow->MaxCoolingCapacity(VRFCond));
       }
...

TotalCondHeatingCapacity = this->HeatingCapacity;
TotalTUHeatingCapacity = TotalCondHeatingCapacity * this->PipingCorrectionHeating;
rraustad commented 2 months ago

I would think that "VRF Heat Pump Total Heating Rate" (a refrigerant side measure) would equal the sum of the TUs "VRF heating coil heating rates" (an air-side measure equal to refrigerant side heat transfer) and include piping losses. This data gets within 10 W so there is something not quite lining up. Is that a result of the component model converging?

yujiex commented 2 months ago

@rraustad from the above analysis of a few timestamps at the beginning of the simulation, it seems to me the difference after unifying the second bullet point in (this comment)[https://github.com/NREL/EnergyPlus/issues/10625#issuecomment-2253477353]), is because of the piping correction used in the calculation of QCoilReq (equal to coil heating rate during these few time steps) is at the rated condition (rated capacity / (rated capacity + piping loss)) while the reported piping correction uses the actual condition (total coil heating rate / (total coil heating rate + piping loss)

rraustad commented 2 months ago

Does this difference happen only when the TU capacity is being limited? Or all the time? See output "VRF Heat Pump Maximum Capacity Cooling (Heating) Rate".

yujiex commented 2 months ago

The difference is very small (1e-11 level) when the TU capacity is not limited (filter by colume K = L being false)

image

rraustad commented 2 months ago

I'm not sure what K = L means. I asked because I did not see piping losses being used in the LimitTUCapacity calculations.

rraustad commented 2 months ago

OK, I see. If I compare column P with G I see they match when the TU coil capacity is not limited. I would look at including piping losses in the calculations for LimitTUCapacity.

rraustad commented 2 months ago

It looks like piping losses are accounted for. So now I'm not sure why this is happening only when the TU capacity is limited. does MaxHeatingCapacity include piping losses?

            TotalTUCoolingCapacity = TotalCondCoolingCapacity * this->PipingCorrectionCooling;
            TotalTUHeatingCapacity = TotalCondHeatingCapacity * this->PipingCorrectionHeating;

        LimitTUCapacity(state,
                        VRFCond,
                        NumTUInList,
                        TotalTUHeatingCapacity,
                        state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad,
                        state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond),
                        TotalTUCoolingCapacity,
                        state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad,
                        state.dataHVACVarRefFlow->MaxCoolingCapacity(VRFCond));
yujiex commented 2 months ago

MaxHeatingCapacity should have included piping loss. For a simple 1-TU-1-OU configuration, I believe the MaxHeatingCapacity would just be the TotalTUHeatingCapacity.

rraustad commented 2 months ago

I think if you adjust MaxHeating/CoolingCapacity by piping losses the difference will be resolved. I guess you would do that inside the LimitTUCapacity function since this variable is an output report.

    this->HeatingCapacity =
        this->CoffEvapCap * this->RatedEvapCapacity * CurveValue(state, this->OUCoolingCAPFT(NumOfCompSpdInput), Tdischarge, Tsuction) +
        this->RatedCompPower * CurveValue(state,
                                          this->OUCoolingPWRFT(NumOfCompSpdInput),
                                          Tdischarge,
                                          Tsuction); // Include the piping loss, at the highest compressor speed

    this->PipingCorrectionHeating = TU_HeatingLoad_actual / (TU_HeatingLoad_actual + Pipe_Q_h);
    state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond) =
        this->HeatingCapacity; // for report, maximum condensing capacity the system can provide
yujiex commented 2 months ago

I'm not sure I understand. So state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond) is calculated in LimitTUCapacity. TotalTUHeatingCapacity has considered piping loss, so state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond) should have considered piping loss as well.

        if (TU_HeatingLoad > TotalTUHeatingCapacity) {
            LimitTUCapacity(state,
                            VRFCond,
                            NumTUInList,
                            TotalTUHeatingCapacity,
                            state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalHeatLoad,
                            state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond),
                            TotalTUCoolingCapacity,
                            state.dataHVACVarRefFlow->TerminalUnitList(TUListNum).TotalCoolLoad,
                            state.dataHVACVarRefFlow->MaxCoolingCapacity(VRFCond));
       }

and it is used in coil calculation as the capacity limit

            SimDXCoil(state,
                      "",
                      HVAC::CompressorOp::On,
                      FirstHVACIteration,
                      this->HeatCoilIndex,
                      fanOp,
                      PartLoadRatio,
                      _,
                      _,
                      state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond));

Or do you mean I should use un-adjust it and use the state.dataHVACVarRefFlow->MaxHeatingCapacity(VRFCond)) / this->PipingCorrectionHeating in SimDXCoil?

rraustad commented 2 months ago

All I know is something is wrong when the model limits TU coil capacity. It seems odd to pass the system limit, MaxHeatingCapacity(VRFCond), to the coil. I would think a coil capacity limit should be passed to the coil. For a 1 TU example file these are the same but for a 5 TU example file a single coil would likely never exceed the total system capacity (unless only 1 coil was operating).

yujiex commented 2 months ago

This MaxHeatingCapacity(VRFCond) is TU limit, and there's 1 coil for the TU, so acting like a coil limit too? This is the diagram from the engineering reference.

image

rraustad commented 2 months ago

OK, so maybe MaxHeatingCapacity(VRFCond) is the coil limit. Try multiplying by the piping losses to see if that fixes this. If not then I am not sure where else to look.

yujiex commented 2 months ago

Just tried it, this is the output. Still very different

image

rraustad commented 2 months ago

Is it just coincidence that the diff in column O is about the same as column L (1- column M) ? 6561.52 (1 - 0.98269556) = 113.3 vs column O at 111.9.

rraustad commented 2 months ago

This is a side note, but I recall something @Nigusse fixed about using COP in calculations in cooling (1 + ) vs heating (1 - ) here:

if (state.dataHVACVarRefFlow->VRF(VRFCond).HeatRecoveryUsed) {
    if (state.dataHVACVarRefFlow->CoolingLoad(VRFCond)) {
        RemainingCapacity = StartingCapacity * (1 + 1 / state.dataHVACVarRefFlow->VRF(VRFCond).CoolingCOP);
        if (AltCapacity > RemainingCapacity) {
            LimitCoilCapacity(NumTUInList, RemainingCapacity, AltArray, AltLimit);
        }
    }
    if (state.dataHVACVarRefFlow->HeatingLoad(VRFCond)) {
        RemainingCapacity = StartingCapacity / (1 + 1 / state.dataHVACVarRefFlow->VRF(VRFCond).HeatingCOP);
        if (AltCapacity > RemainingCapacity) {
            LimitCoilCapacity(NumTUInList, RemainingCapacity, AltArray, AltLimit);
        }
    }
}
yujiex commented 2 months ago

Is it just coincidence that the diff in column O is about the same as column L (1- column M) ? 6561.52 (1 - 0.98269556) = 113.3 vs column O at 111.9.

actually Column K * Column M now is very close to column G now, except for three large values. btw my runperiod is 1/1 to 1/10

image

eplusout.csv

rraustad commented 2 months ago

It looks like the TU coil capacity is limited for those 3 rows (i.e., K = L).

yujiex commented 2 months ago

looks like there might still be something related to the TU coil capacity being limited