Skip to content

Inconsistency between documentation and code in what temperature is used to determine crankcase heater on/off  #10052

@yujiex

Description

@yujiex

Issue overview

There are some differences between the code and the documentation on what temperature is used when comparing with a temperature threshold to determine the On/Off of a crankcase heater. In the documentation, water heaters use compressor temperature, others use outdoor temperature.

The documentation and temperature threshold idd field name

For the following objects, the outdoor dry-bulb temperature is used. The name of the temperature threshold is "Maximum Outdoor Dry-bulb Temperature for Crankcase Heater Operation". The documentation of the field is like this "This numeric field defines the crankcase heater capacity in Watts. When the outdoor air dry-bulb temperature is below the value specified in the input field Maximum Outdoor Dry-bulb Temperature for Crankcase Heater Operation (described below), the crankcase heater is enabled during the time that the compressor is not running".

  • Coil:Cooling:DX:CurveFit:Performance (calculated in CoilCoolingDXCurveFitPerformance::simulate)
  • Coil:Cooling:DX:SingleSpeed (calculated in function CalcDXHeatingCoil)
  • Coil:Cooling:DX:TwoStageWithHumidityControlMode (calculated in function CalcDoe2DXCoil)
  • Coil:Cooling:DX:MultiSpeed (calculated in function CalcMultiSpeedDXCoilCooling)
  • Coil:Cooling:DX:VariableSpeed (calculated in function CalcVarSpeedCoilCooling)
  • Coil:Heating:DX:SingleSpeed (calculated in function CalcDXHeatingCoil)
  • Coil:Heating:DX:MultiSpeed (calculated in function CalcMultiSpeedDXCoilHeating)
  • Coil:Heating:DX:VariableSpeed (calculated in function CalcVarSpeedCoilHeating)

For the following heat pump water heater object, the compressor ambient temperature is used. The name of the temperature threshold field is "Maximum Ambient Temperature for Crankcase Heater Operation". The documentation of the field is "The crankcase heater only operates when the compressor is off and the air surrounding the compressor is below the Maximum Ambient Temperature for Crankcase Heater Operation specified below."

  • Coil:WaterHeating:AirToWaterHeatPump:Pumped (in function CalcDoe2DXCoil)
  • Coil:WaterHeating:AirToWaterHeatPump:Wrapped (in function CalcDoe2DXCoil)
  • Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed (in function CalcVarSpeedHPWH)

The code

in CoilCoolingDXCurveFitPerformance.cc, the threshold checks are as follows

in CoilCoolingDXCurveFitPerformance::simulate: state.dataEnvrn->OutDryBulbTemp < this->maxOutdoorDrybulbForBasin

in DXCoils.cc, the threshold checks are as follows

in function CalcDoe2DXCoil: CompAmbTemp < thisDXCoil.MaxOATCrankcaseHeater
in function CalcVRFCoolingCoil: CompAmbTemp < thisDXCoil.MaxOATCrankcaseHeater
in function CalcDXHeatingCoil: CompAmbTemp < thisDXCoil.MaxOATCrankcaseHeater
in function CalcMultiSpeedDXCoilCooling: OutdoorDryBulb < thisDXCoil.MaxOATCrankcaseHeater
in function CalcMultiSpeedDXCoilHeating: OutdoorDryBulb < thisDXCoil.MaxOATCrankcaseHeater
in function CalcVRFCoolingCoil_FluidTCtrl: CompAmbTemp < thisDXCoil.MaxOATCrankcaseHeater
in function CalcVRFHeatingCoil_FluidTCtrl: OutdoorDryBulb < thisDXCoil.MaxOATCrankcaseHeater

For the ones using OutdoorDryBulb temporary variables:
InCalcVRFHeatingCoil_FluidTCtrl, the temporary variable OutdoorDryBulb is just outdoor temperature. In CalcMultiSpeedDXCoilCooling and CalcMultiSpeedDXCoilHeating, OutdoorDryBulb is not actually the outdoor temperature in some cases. They could be condenser inlet node temperature (state.dataLoopNodes->Node(thisDXCoil.CondenserInletNodeNum(DXMode)).Temp), zone temperature (secZoneHB.ZT), or outdoor dry bulb temperature (state.dataEnvrn->OutDryBulbTemp). The following are related code chunks (only taking lines related to OutdoorDryBulb


// --------------------------------------------------------------------------------
// in CalcMultiSpeedDXCoilCooling
// --------------------------------------------------------------------------------

    if (thisDXCoil.CondenserInletNodeNum(DXMode) != 0) {
        if (OutdoorPressure == state.dataLoopNodes->DefaultNodeValues.Press) {
            OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
        } else {
            OutdoorDryBulb = state.dataLoopNodes->Node(thisDXCoil.CondenserInletNodeNum(DXMode)).Temp;
        }
        if (thisDXCoil.IsSecondaryDXCoilInZone) {
            OutdoorDryBulb = secZoneHB.ZT;
        }
    } else if (thisDXCoil.IsSecondaryDXCoilInZone) {
        OutdoorDryBulb = secZoneHB.ZT;
    } else {
        OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
    }

// --------------------------------------------------------------------------------
// in CalcMultiSpeedDXCoilHeating
// --------------------------------------------------------------------------------

    if (thisDXCoil.CondenserInletNodeNum(1) != 0) {
        if (OutdoorPressure == state.dataLoopNodes->DefaultNodeValues.Press) {
            OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
        } else {
            OutdoorDryBulb = state.dataLoopNodes->Node(thisDXCoil.CondenserInletNodeNum(1)).Temp;
        }
        if (thisDXCoil.IsSecondaryDXCoilInZone) {
            OutdoorDryBulb = secZoneHB.ZT;
        }
    } else if (thisDXCoil.IsSecondaryDXCoilInZone) {
        OutdoorDryBulb = secZoneHB.ZT;
    } else {
        OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
    }

// --------------------------------------------------------------------------------
// in CalcVRFHeatingCoil_FluidTCtrl
// --------------------------------------------------------------------------------

    OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;

For the ones using CompAmbTemp, it's a bit more complex. The following are code chunks related to how the CompAmbTemp is calculated. For most cases, a temporary variable OutdoorDryBulb is calculated (which might not be the actual outdoor temperature), then conditionally assigned to CompAmbTemp.

// in the following chunks, only lines related to OutdoorDryBulb or CompAmbTemp are extracted
// --------------------------------------------------------------------------------
// in function CalcDoe2DXCoil
// --------------------------------------------------------------------------------

    if (thisDXCoil.CondenserType(Mode) != DataHeatBalance::RefrigCondenserType::WaterHeater) {
        if (thisDXCoil.CondenserInletNodeNum(Mode) != 0) {
            if (OutdoorPressure == state.dataLoopNodes->DefaultNodeValues.Press) {
                OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
            } else {
                OutdoorDryBulb = state.dataLoopNodes->Node(thisDXCoil.CondenserInletNodeNum(Mode)).Temp;
            }
        } else {
            OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
        }
        if (thisDXCoil.IsSecondaryDXCoilInZone) {
            OutdoorDryBulb = secZoneHB.ZT;
        }
    } else {
    }

    if (thisDXCoil.CondenserType(Mode) == DataHeatBalance::RefrigCondenserType::Air) {
        CompAmbTemp = OutdoorDryBulb;
        if (thisDXCoil.IsSecondaryDXCoilInZone) {
            CompAmbTemp = CondInletTemp; // assumes compressor is in same location as secondary coil
        }
    } else if (thisDXCoil.CondenserType(Mode) == DataHeatBalance::RefrigCondenserType::Evap) {
        CompAmbTemp = OutdoorDryBulb;
    } else if (thisDXCoil.CondenserType(Mode) == DataHeatBalance::RefrigCondenserType::WaterHeater) {
        CompAmbTemp = state.dataHVACGlobal->HPWHCrankcaseDBTemp;   // Temperature at HP water heater compressor
    }

// --------------------------------------------------------------------------------
// in CalcVRFCoolingCoil
// --------------------------------------------------------------------------------

    if (thisDXCoil.CondenserInletNodeNum(Mode) != 0) {
        OutdoorDryBulb = state.dataLoopNodes->Node(thisDXCoil.CondenserInletNodeNum(Mode)).Temp;
        if (thisDXCoil.CondenserType(Mode) == DataHeatBalance::RefrigCondenserType::Water) {
        } else {
            if (OutdoorPressure == state.dataLoopNodes->DefaultNodeValues.Press) {
                OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
            } else {
            }
        }
    } else {
        OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
    }

    if (thisDXCoil.CondenserType(Mode) == DataHeatBalance::RefrigCondenserType::Evap) {
        CompAmbTemp = OutdoorDryBulb;
    } else {                            // for air or water-cooled, inlet temp is stored in OutdoorDryBulb temp
        if (thisDXCoil.CondenserType(Mode) == DataHeatBalance::RefrigCondenserType::Water) {
            CompAmbTemp = state.dataEnvrn->OutDryBulbTemp; // for crankcase heater use actual outdoor temp for water-cooled
        } else {
            CompAmbTemp = OutdoorDryBulb;
        }
    }

// --------------------------------------------------------------------------------
// in CalcDXHeatingCoil
// --------------------------------------------------------------------------------

    if (thisDXCoil.CondenserInletNodeNum(1) != 0) {
        OutdoorDryBulb = state.dataLoopNodes->Node(thisDXCoil.CondenserInletNodeNum(1)).Temp;
        CompAmbTemp = OutdoorDryBulb;
        if (thisDXCoil.CondenserType(Mode) == DataHeatBalance::RefrigCondenserType::Water) {
            CompAmbTemp = state.dataEnvrn->OutDryBulbTemp;
        } else {
            if (OutdoorPressure == state.dataLoopNodes->DefaultNodeValues.Press) {
                OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
            } else {
            }
            if (thisDXCoil.IsSecondaryDXCoilInZone) {
                OutdoorDryBulb = secZoneHB.ZT;
                CompAmbTemp = OutdoorDryBulb;
            }
        }
    } else if (thisDXCoil.IsSecondaryDXCoilInZone) {
        OutdoorDryBulb = secZoneHB.ZT;
        CompAmbTemp = OutdoorDryBulb;
    } else {
        OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
        CompAmbTemp = OutdoorDryBulb;
    }

// --------------------------------------------------------------------------------
// in CalcMultiSpeedDXCoil
// --------------------------------------------------------------------------------

    if (thisDXCoil.CondenserInletNodeNum(Mode) != 0) {
        if (OutdoorPressure == state.dataLoopNodes->DefaultNodeValues.Press) {
            OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
        } else {
            OutdoorDryBulb = state.dataLoopNodes->Node(thisDXCoil.CondenserInletNodeNum(Mode)).Temp;
        }
        CompAmbTemp = OutdoorDryBulb;
        if (thisDXCoil.IsSecondaryDXCoilInZone) {
            OutdoorDryBulb = secZoneHB.ZT;
            CompAmbTemp = OutdoorDryBulb;
        }
    } else if (thisDXCoil.IsSecondaryDXCoilInZone) {
        OutdoorDryBulb = secZoneHB.ZT;
        CompAmbTemp = OutdoorDryBulb;
    } else {
        OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
        CompAmbTemp = OutdoorDryBulb;
    }
// --------------------------------------------------------------------------------
// in CalcVRFCoolingCoil_FluidTCtrl
// --------------------------------------------------------------------------------

    if (thisDXCoil.CondenserInletNodeNum(Mode) != 0) {
        OutdoorDryBulb = state.dataLoopNodes->Node(thisDXCoil.CondenserInletNodeNum(Mode)).Temp;
        if (thisDXCoil.CondenserType(Mode) == DataHeatBalance::RefrigCondenserType::Water) {
        } else {
            if (OutdoorPressure == state.dataLoopNodes->DefaultNodeValues.Press) {
                OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
            } else {
            }
        }
    } else {
        OutdoorDryBulb = state.dataEnvrn->OutDryBulbTemp;
    }

    if (thisDXCoil.CondenserType(Mode) == DataHeatBalance::RefrigCondenserType::Evap) {
        CompAmbTemp = OutdoorDryBulb;
    } else {                            // for air or water-cooled, inlet temp is stored in OutdoorDryBulb temp
        if (thisDXCoil.CondenserType(Mode) == DataHeatBalance::RefrigCondenserType::Water) {
            CompAmbTemp = state.dataEnvrn->OutDryBulbTemp; // for crankcase heater use actual outdoor temp for water-cooled
        } else {
            CompAmbTemp = OutdoorDryBulb;
        }
    }

in VariableSpeedCoils.cc, the threshold checks are as follows.

  • in function CalcVarSpeedHPWH: state.dataEnvrn->OutDryBulbTemp < state.dataVariableSpeedCoils->VarSpeedCoil(DXCoilNum).MaxOATCrankcaseHeater
  • in function CalcVarSpeedCoilHeating: state.dataVariableSpeedCoils->OutdoorDryBulb < state.dataVariableSpeedCoils->VarSpeedCoil(DXCoilNum).MaxOATCrankcaseHeater
  • in function CalcVarSpeedCoilCooling: state.dataVariableSpeedCoils->OutdoorDryBulb_CalcVarSpeedCoilCooling <state.dataVariableSpeedCoils->VarSpeedCoil(DXCoilNum).MaxOATCrankcaseHeater

For the second and third case in the VariableSpeedCoils.cc, the *->OutdoorDryBulb equals to condenser inlet node temperature if the node is defined, otherwise it will be outdoor temperature

Details

Some additional details for this issue (if relevant):

  • Platform (Operating system, version)
  • Version of EnergyPlus (if using an intermediate build, include SHA)
  • Unmethours link or helpdesk ticket number

Checklist

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

  • Defect file added (list location of defect file here)
  • Ticket added to Pivotal for defect (development team task)
  • Pull request created (the pull request will have additional tasks related to reviewing changes that fix this defect)

Metadata

Metadata

Assignees

Labels

DefectIncludes code to repair a defect in EnergyPlus

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions