Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 240 additions & 0 deletions design/FY2026/NFP_SkyLW_Actuator.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4071,6 +4071,10 @@ \subsubsection{Outputs}\label{outputs-36-1}

This output is the heat energy added after material layer N from the EMS heat flux actuator (Component type: ``CondFD Surface Material Layer''; Control type: ``Heat Flux''). Energy is aggregated on the electricity meter and is only valid for the CondFD solution algorithm.

\paragraph{CondFD EMS Sky Longwave Radiation Override Heat Flux}

This output is the user-specified net sky longwave radiation heat flux applied to the exterior surface via the EMS actuator (Component type: ``CondFD Surface''; Control type: ``Sky Longwave Radiation Override''). Reports 0.0 when not actuated. Only valid for exterior CondFD surfaces.

\subsection{Construction:AirBoundary}\label{constructionairboundary}

Construction:AirBoundary indicates an open boundary between two zones. It may be used for base surfaces and fenestration surfaces.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2517,6 +2517,20 @@ described below.
used to add energy (i.e. positive numbers only), and the energy used
is added to the electric heating sub-meter.

A separate actuator, called “CondFD Surface,” is available for exterior
surfaces that use the Conduction Finite Difference solution algorithm.
Unlike the material-layer actuators above, this actuator operates on the
surface as a whole and is identified by the surface name alone (not
SurfName:MatName).

- “Sky Longwave Radiation Override”. Has units of [W/m2]. Replaces
the default sky longwave radiation term (h_sky * (T_sky - T_surf))
in the exterior face heat balance with a user-specified net heat
flux. Positive values indicate net radiation into the surface;
negative values indicate net radiation leaving the surface (cooling).
Only applies to exterior CondFD surfaces. The actuated component
unique name is the surface name (e.g. “ZN001:ROOF001”).

Conduction Finite Difference Outputs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -2548,6 +2562,15 @@ CondFD EMS Heat Source Energy After Layer N

This output reports the heat energy added after material layer N

- Zone,Average,CondFD EMS Sky Longwave Radiation Override Heat Flux [W/m2]

CondFD EMS Sky Longwave Radiation Override Heat Flux
''''''''''''''''''''''''''''''''''''''''''''''''''''

This output reports the user-specified net sky longwave radiation heat
flux applied to the exterior surface via the EMS actuator. Reports 0.0
when not actuated.

Air Movement
------------

Expand Down
86 changes: 70 additions & 16 deletions src/EnergyPlus/HeatBalFiniteDiffManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,24 @@ namespace HeatBalFiniteDiffManager {
OutputProcessor::Group::Building,
OutputProcessor::EndUseCat::Heating);
}

// Setup EMS Actuator for Sky LW Radiation Override (per-surface)
if (state.dataSurface->Surface(SurfNum).ExtBoundCond == DataSurfaces::ExternalEnvironment) {
EnergyPlus::SetupEMSActuator(state,
"CondFD Surface",
state.dataSurface->Surface(SurfNum).Name,
"Sky Longwave Radiation Override",
"[W/m2]",
SurfaceFD(SurfNum).enetActuator.isActuated,
SurfaceFD(SurfNum).enetActuator.actuatedValue);
SetupOutputVariable(state,
"CondFD EMS Sky Longwave Radiation Override Heat Flux",
Constant::Units::W_m2,
SurfaceFD(SurfNum).enetActuator.actuatedValue,
OutputProcessor::TimeStepType::Zone,
OutputProcessor::StoreType::Average,
state.dataSurface->Surface(SurfNum).Name);
}
}

int TotNodes = ConstructFD(state.dataSurface->Surface(SurfNum).Construction).TotNodes; // Full size nodes, start with outside face.
Expand Down Expand Up @@ -1707,6 +1725,7 @@ namespace HeatBalFiniteDiffManager {
Real64 const Toa(state.dataMstBal->TempOutsideAirFD(Surf));
Real64 const Tgnd(Tgndsurface);
Real64 const Tsurr(TsurrSurface);
auto const &enetAct = s_hbfd->SurfaceFD(Surf).enetActuator;

if (surface.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CondFD) {

Expand All @@ -1724,8 +1743,13 @@ namespace HeatBalFiniteDiffManager {
if (mat->ROnly || mat->group == Material::Group::AirGap) { // R Layer or Air Layer **********
// Use algebraic equation for TDT based on R
Real64 const Rlayer(mat->Resistance);
TDT_i = (TDT_p + (QRadSWOutFD + hgnd * Tgnd + (hconvo + hrad) * Toa + hsky * Tsky + hsurr * Tsurr) * Rlayer) /
(1.0 + (hconvo + hgnd + hrad + hsky + hsurr) * Rlayer);
if (enetAct.isActuated) {
TDT_i = (TDT_p + (QRadSWOutFD + hgnd * Tgnd + (hconvo + hrad) * Toa + enetAct.actuatedValue + hsurr * Tsurr) * Rlayer) /
(1.0 + (hconvo + hgnd + hrad + hsurr) * Rlayer);
} else {
TDT_i = (TDT_p + (QRadSWOutFD + hgnd * Tgnd + (hconvo + hrad) * Toa + hsky * Tsky + hsurr * Tsurr) * Rlayer) /
(1.0 + (hconvo + hgnd + hrad + hsky + hsurr) * Rlayer);
}

} else { // Regular or phase change material layer

Expand Down Expand Up @@ -1793,27 +1817,46 @@ namespace HeatBalFiniteDiffManager {
if (s_hbfd->CondFDSchemeType == CondFDScheme::CrankNicholsonSecondOrder) { // Second Order equation
Real64 const Cp_DelX_RhoS_2Delt(Cp * DelX * RhoS / (2.0 * Delt));
Real64 const kt_2DelX(kt / (2.0 * DelX));
Real64 const hsum(0.5 * (hconvo + hgnd + hrad + hsky + hsurr));
TDT_i = (QRadSWOutFD + Cp_DelX_RhoS_2Delt * TD_i + kt_2DelX * (TDT_p - TD_i + TD(i + 1)) + hgnd * Tgnd +
(hconvo + hrad) * Toa + hsky * Tsky + hsurr * Tsurr - hsum * TD_i) /
(hsum + kt_2DelX + Cp_DelX_RhoS_2Delt);
if (enetAct.isActuated) {
Real64 const hsum(0.5 * (hconvo + hgnd + hrad + hsurr));
TDT_i = (QRadSWOutFD + Cp_DelX_RhoS_2Delt * TD_i + kt_2DelX * (TDT_p - TD_i + TD(i + 1)) + hgnd * Tgnd +
(hconvo + hrad) * Toa + enetAct.actuatedValue + hsurr * Tsurr - hsum * TD_i) /
(hsum + kt_2DelX + Cp_DelX_RhoS_2Delt);
} else {
Real64 const hsum(0.5 * (hconvo + hgnd + hrad + hsky + hsurr));
TDT_i = (QRadSWOutFD + Cp_DelX_RhoS_2Delt * TD_i + kt_2DelX * (TDT_p - TD_i + TD(i + 1)) + hgnd * Tgnd +
(hconvo + hrad) * Toa + hsky * Tsky + hsurr * Tsurr - hsum * TD_i) /
(hsum + kt_2DelX + Cp_DelX_RhoS_2Delt);
}
} else if (s_hbfd->CondFDSchemeType == CondFDScheme::FullyImplicitFirstOrder) { // First Order
Real64 const Two_Delt_DelX(2.0 * Delt_DelX);
Real64 const Cp_DelX2_RhoS(Cp * pow_2(DelX) * RhoS);
Real64 const Two_Delt_kt(2.0 * Delt * kt);
TDT_i = (Two_Delt_DelX * (QRadSWOutFD + hgnd * Tgnd + (hconvo + hrad) * Toa + hsky * Tsky + hsurr * Tsurr) +
Cp_DelX2_RhoS * TD_i + Two_Delt_kt * TDT_p) /
(Two_Delt_DelX * (hconvo + hgnd + hrad + hsky + hsurr) + Two_Delt_kt + Cp_DelX2_RhoS);
if (enetAct.isActuated) {
TDT_i = (Two_Delt_DelX * (QRadSWOutFD + hgnd * Tgnd + (hconvo + hrad) * Toa + enetAct.actuatedValue + hsurr * Tsurr) +
Cp_DelX2_RhoS * TD_i + Two_Delt_kt * TDT_p) /
(Two_Delt_DelX * (hconvo + hgnd + hrad + hsurr) + Two_Delt_kt + Cp_DelX2_RhoS);
} else {
TDT_i = (Two_Delt_DelX * (QRadSWOutFD + hgnd * Tgnd + (hconvo + hrad) * Toa + hsky * Tsky + hsurr * Tsurr) +
Cp_DelX2_RhoS * TD_i + Two_Delt_kt * TDT_p) /
(Two_Delt_DelX * (hconvo + hgnd + hrad + hsky + hsurr) + Two_Delt_kt + Cp_DelX2_RhoS);
}
}

} else { // HMovInsul > 0.0: Transparent insulation on outside
// Transparent insulation additions

// Movable Insulation Layer Outside surface temp

Real64 const TInsulOut(
(QRadSWOutMvInsulFD + hgnd * Tgnd + HMovInsul * TDT_i + (hconvo + hrad) * Toa + hsky * Tsky + hsurr * Tsurr) /
(hconvo + hgnd + HMovInsul + hrad + hsky + hsurr)); // Temperature of outside face of Outside Insulation
Real64 TInsulOut;
if (enetAct.isActuated) {
TInsulOut = (QRadSWOutMvInsulFD + hgnd * Tgnd + HMovInsul * TDT_i + (hconvo + hrad) * Toa + enetAct.actuatedValue +
hsurr * Tsurr) /
(hconvo + hgnd + HMovInsul + hrad + hsurr);
} else {
TInsulOut = (QRadSWOutMvInsulFD + hgnd * Tgnd + HMovInsul * TDT_i + (hconvo + hrad) * Toa + hsky * Tsky + hsurr * Tsurr) /
(hconvo + hgnd + HMovInsul + hrad + hsky + hsurr);
}
Real64 const Two_Delt_DelX(2.0 * Delt_DelX);
Real64 const Cp_DelX2_RhoS(Cp * pow_2(DelX) * RhoS);
Real64 const Two_Delt_kt(2.0 * Delt * kt);
Expand Down Expand Up @@ -1844,15 +1887,26 @@ namespace HeatBalFiniteDiffManager {
// One formulation that works for Fully Implicit and CrankNicholson and massless wall

Real64 const Toa_TDT_i(Toa - TDT_i);
Real64 const QNetSurfFromOutside(
QRadSWOutFD + (hgnd * (-TDT_i + Tgnd) + (hconvo + hrad) * Toa_TDT_i + hsky * (-TDT_i + Tsky) + hsurr * (-TDT_i + Tsurr)));
Real64 QNetSurfFromOutside;
if (enetAct.isActuated) {
QNetSurfFromOutside =
QRadSWOutFD + (hgnd * (-TDT_i + Tgnd) + (hconvo + hrad) * Toa_TDT_i + enetAct.actuatedValue + hsurr * (-TDT_i + Tsurr));
} else {
QNetSurfFromOutside =
QRadSWOutFD + (hgnd * (-TDT_i + Tgnd) + (hconvo + hrad) * Toa_TDT_i + hsky * (-TDT_i + Tsky) + hsurr * (-TDT_i + Tsurr));
}

// Same sign convention as CTFs
state.dataHeatBalSurf->SurfOpaqOutFaceCondFlux(Surf) = -QNetSurfFromOutside;

// Report all outside BC heat fluxes
state.dataHeatBalSurf->SurfQdotRadOutRepPerArea(Surf) =
-(hgnd * (TDT_i - Tgnd) + hrad * (-Toa_TDT_i) + hsky * (TDT_i - Tsky) + hsurr * (TDT_i - Tsurr));
if (enetAct.isActuated) {
state.dataHeatBalSurf->SurfQdotRadOutRepPerArea(Surf) =
-(hgnd * (TDT_i - Tgnd) + hrad * (-Toa_TDT_i) + (-enetAct.actuatedValue) + hsurr * (TDT_i - Tsurr));
} else {
state.dataHeatBalSurf->SurfQdotRadOutRepPerArea(Surf) =
-(hgnd * (TDT_i - Tgnd) + hrad * (-Toa_TDT_i) + hsky * (TDT_i - Tsky) + hsurr * (TDT_i - Tsurr));
}
state.dataHeatBalSurf->SurfQdotRadOutRep(Surf) = surface.Area * state.dataHeatBalSurf->SurfQdotRadOutRepPerArea(Surf);
state.dataHeatBalSurf->SurfQRadOutReport(Surf) = state.dataHeatBalSurf->SurfQdotRadOutRep(Surf) * state.dataGlobal->TimeStepZoneSec;

Expand Down
1 change: 1 addition & 0 deletions src/EnergyPlus/HeatBalFiniteDiffManager.hh
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ namespace HeatBalFiniteDiffManager {
// Includes the EMS heat source
Array1D<Real64> heatSourceEMSFluxLayerReport;
Array1D<Real64> heatSourceEMSFluxEnergyLayerReport;
MaterialActuatorData enetActuator; // Sky LW radiation EMS override [W/m2]

// Default Constructor
SurfaceDataFD() : SourceNodeNum(0), QSource(0.0), GSloopCounter(0), MaxNodeDelTemp(0.0), EnthalpyM(0.0), EnthalpyF(0.0), PhaseChangeState(0)
Expand Down
Loading
Loading