Skip to content

Comments

Enhancement to Simplified Shading#9404

Merged
Myoldmopar merged 51 commits intodevelopfrom
enhanceSimplifiedShading
Aug 15, 2022
Merged

Enhancement to Simplified Shading#9404
Myoldmopar merged 51 commits intodevelopfrom
enhanceSimplifiedShading

Conversation

@yujiex
Copy link
Collaborator

@yujiex yujiex commented Apr 27, 2022

Pull request overview

Currently, EnergyPlus models shading devices in WindowMaterial:Shade and WindowMaterial:ComplexShade. Even for the non-complex shade, users need to specify at least nine input fields including solar and visible transmittance and reflectance, infrared hemispherical emissivity and transmittance, thickness, conductivity, etc. This level of complexity could hinder the application of the shading model in EnergyPlus: when the required input fields are difficult to acquire, users might choose to not model shading devices at all. One such case could be converting models from other simulation tools with less detailed shading methods. The omission of shading devices could lead to an overestimation of cooling loads in the summer and an underestimation of the heating load in winter.

The proposed new feature will enable a simplified way to specify the properties of a shading device with a multiplier applied to the incident solar radiation. The multiplier can be a single fixed value or a schedule of values. An idd object SurfaceProperty:IncidentSolarMultiplier will be added for users to specify the multiplier to discount the incident solar, and as a result discount the transmitted solar from the outside to the inside. This multiplier resembles the shading-fraction in DOE-2, which can adjust the solar heat gain through windows with a multiplier schedule.

This post on unmethours.com shows a need for such a simplified shading method in EnergyPlus: https://unmethours.com/question/342/what-assumptions-do-you-make-for-modeling-blinds/

Main Approach

The state.dataEnvrn->BeamSolarRad, state.dataEnvrn->DifSolarRad, and state.dataEnvrn->GndSolarRad are multiplied by the incident solar multiplier for the corresponding surface. The multiplier is one for most surfaces, except for the ones with defined SurfaceProperty:IncidentSolarMultiplier and non-default multiplier values.

For example, originally, the sky incident solar is computed like this

state.dataSurface->SurfSkySolarInc(SurfNum) =
                state.dataEnvrn->DifSolarRad * state.dataSolarShading->SurfAnisoSkyMult(SurfNum);

In this feature branch, it is computed with an additional term

state.dataSurface->SurfSkySolarInc(SurfNum) =
                state.dataEnvrn->DifSolarRad * mult(SurfNum) * state.dataSolarShading->SurfAnisoSkyMult(SurfNum);

where mult(SurfNum) is the surface-dependent incident solar multiplier. In the code, it is called SurfIncSolarMultiplier

The multipliers are applied in the calculation of the following quantities. Generally, when there is a SurfNum specified, the multiplier is applied. The SurfNum will decide the value of the multiplier.

  • Complex Fenestration
state.dataSurface->SurfSkySolarInc(SurfNum)
GndReflSolarRad
state.dataSurface->SurfWinSkyGndSolarInc(SurfNum)
state.dataSurface->SurfWinBmGndSolarInc(SurfNum)
state.dataSurface->SurfSkySolarInc(SurfNum)
state.dataSurface->SurfGndSolarInc(SurfNum)
  • Fixed shading
state.dataHeatBal->SurfQRadSWOutIncidentBeam(SurfNum)
state.dataHeatBal->SurfQRadSWOutIncidentSkyDiffuse(SurfNum)
state.dataHeatBal->SurfQRadSWOutIncBmToDiffReflGnd(SurfNum)
state.dataHeatBal->SurfQRadSWOutIncSkyDiffReflGnd(SurfNum)
  • All solar surfaces
currBeamSolar(SurfNum)
state.dataHeatBal->SurfQRadSWOutIncidentSkyDiffuse(SurfNum)
state.dataHeatBal->SurfQRadSWOutIncBmToDiffReflGnd(SurfNum)
state.dataHeatBal->SurfQRadSWOutIncSkyDiffReflGnd(SurfNum)
state.dataHeatBal->SurfQRadSWOutIncBmToBmReflObs(SurfNum)
state.dataHeatBal->SurfQRadSWOutIncBmToDiffReflObs(SurfNum)
state.dataHeatBal->SurfQRadSWOutIncSkyDiffReflObs(SurfNum)
  • daylighting devices: TDD pipe
currBeamSolar(SurfNum)
state.dataSurface->SurfSkySolarInc(SurfNum)
  • daylighting shelf
currBeamSolar(SurfNum)
ShelfSolarRad
DifSolarInc
GndReflSolarRad
state.dataSurface->SurfWinBmSolar(SurfNum)
state.dataSurface->SurfWinDifSolar(SurfNum)
  • OpaqOrIntMassSurface (for future extend to opaq surfaces)
state.dataHeatBalSurf->SurfOpaqQRadSWOutAbs(SurfNum)
state.dataHeatBalSurf->SurfOpaqQRadSWInAbs(SurfNum)
state.dataHeatBalSurf->SurfOpaqInsFaceBeamSolAbsorbed(SurfNum)
  • Frame and divider
BeamFaceInc
BeamFrHorFaceInc
BeamFrVertFaceInc
state.dataSurface->SurfWinFrameQRadOutAbs(SurfNum)
state.dataSurface->SurfWinFrameQRadInAbs(SurfNum)
BeamDivHorFaceInc
BeamDivVertFaceInc
BeamDivHorFaceIncIn
BeamDivVertFaceIncIn
  • Reporting of solar enclosure surfaces
state.dataHeatBal->SurfBmIncInsSurfAmountRep(SurfNum)
state.dataHeatBal->SurfBmIncInsSurfIntensRep(SurfNum)
state.dataHeatBal->SurfBmIncInsSurfIntensRep(SurfNum)
state.dataSurface->SurfWinExtBeamAbsByShade(SurfNum)
SkySolarTrans
GndSolarTrans
  • regular window
state.dataSurface->SurfWinBmSolar(SurfNum)
state.dataSurface->SurfWinDifSolar(SurfNum)

Visualization of the results

A new test file "1ZoneEvapCooler_4Win_incidentSolarMultiplier.idf" is created to examine the effect of applying the incident solar multiplier. The model is adapted from 1ZoneEvapCooler, with 4 additional windows. The "Sun Exposure" of the roof is changed to "NoSun". The solar reflectance of the wall and roof surfaces are all set to 100%. These intend to facilitate comparison by directly adjusting the .epw

image

The following plot compares the model outputs of the "1ZoneEvapCooler_4Win_incidentSolarMultiplier.idf", with different shading multiplier values in the objectSurfaceProperty:IncidentSolarMultiplier. The output variable compared here is the three components of the incident solar: ZN001:WALL001:WIN001:Surface Outside Face Incident Beam Solar Radiation Rate, ZN001:WALL001:WIN001:Surface Outside Face Incident Ground Diffuse Solar Radiation Rate, and ZN001:WALL001:WIN001:Surface Outside Face Incident Sky Diffuse Solar Radiation Rate, and the total incident solar, ZN001:WALL001:WIN001:Surface Outside Face Incident Solar Radiation Rate per Area (the bottom right facet in the following figure).

  SurfaceProperty:IncidentSolarMultiplier,
    Zn001:Wall001:Win001,    !- Surface Name
    0.5,                     !- Shading Multiplier      <- vary shading multipliers here
    SolarMultConst;          !- Shading Multiplier Schedule Name

  Schedule:Constant,SolarMultConst,Fraction,1.0;

IncSolOneZoneAllWin_DirectAdjust

The transmitted solar radiation for different incident solar multiplier values is shown in the following figure. The variables plotted in the three columns are:
ZN001:WALL001:WIN001:Surface Window Transmitted Beam Solar Radiation Rate [W] (Hourly),
ZN001:WALL001:WIN001:Surface Window Transmitted Diffuse Solar Radiation Rate [W] (Hourly),
and ZN001:WALL001:WIN001:Surface Window Transmitted Solar Radiation Rate [W] (Hourly)

TransSolOneZoneAllWin_DirectAdjust

The following plot shows the zone sensible cooling energy for different multiplier values as well as directly reducing epw solar radiation input to half.

sensibleCoolingOneZoneAllWin_DirectAdjust

NOTE: ENHANCEMENTS MUST FOLLOW A SUBMISSION PROCESS INCLUDING A FEATURE PROPOSAL AND DESIGN DOCUMENT PRIOR TO SUBMITTING CODE

Pull Request Author

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

  • Title of PR should be user-synopsis style (clearly understandable in a standalone changelog context)
  • Label the PR with at least one of: Defect, Refactoring, NewFeature, Performance, and/or DoNoPublish
  • Pull requests that impact EnergyPlus code must also include unit tests to cover enhancement or defect repair
  • Author should provide a "walkthrough" of relevant code changes using a GitHub code review comment process
  • If any diffs are expected, author must demonstrate they are justified using plots and descriptions
  • If changes fix a defect, the fix should be demonstrated in plots and descriptions
  • If any defect files are updated to a more recent version, upload new versions here or on DevSupport
  • If IDD requires transition, transition source, rules, ExpandObjects, and IDFs must be updated, and add IDDChange label
  • If structural output changes, add to output rules file and add OutputChange label
  • If adding/removing any LaTeX docs or figures, update that document's CMakeLists file dependencies

Reviewer

This will not be exhaustively relevant to every PR.

  • Perform a Code Review on GitHub
  • If branch is behind develop, merge develop and build locally to check for side effects of the merge
  • If defect, verify by running develop branch and reproducing defect, then running PR and reproducing fix
  • If feature, test running new feature, try creative ways to break it
  • CI status: all green or justified
  • Check that performance is not impacted (CI Linux results include performance check)
  • Run Unit Test(s) locally
  • Check any new function arguments for performance impacts
  • Verify IDF naming conventions and styles, memos and notes and defaults
  • If new idf included, locally check the err file and other outputs

@yujiex yujiex added NewFeature Includes code to add a new feature to EnergyPlus IDDChange Code changes impact the IDD file (cannot be merged after IO freeze) labels Apr 27, 2022
@yujiex yujiex self-assigned this Apr 27, 2022
Copy link
Contributor

@shorowit shorowit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nice enhancement that some users will greatly appreciate! Thanks for working on this.


## Approach ##

With the added *WindowMaterial:SimplifiedShade* object, users will be able to input a fractional adjustment α between 0 and 1, either as a constant value or as a schedule. The fractional adjustment will be multiplied to the solar transmittance (`state.dataMaterial->Material(MaterNum).Trans`) and visual transmittance (`state.dataMaterial->Material(MaterNum).TransVis`) of the corresponding windows before entering heat balance calculation. The solar transmittance and visible transmittance of the *WindowMaterial:Glazing* object is from the input fields “Solar Transmittance at Normal Incidence” and “Visible Transmittance at Normal Incidence”. For *WindowMaterial:Glazing:RefractionExtinctionMethod* object, the solar and visible transmittance is derived from user input thickness, solar and visible extinction coefficient, and refraction. For the simple glazing object, the adjustment will be applied to the Solar Heat Gain Coefficient and the Visible Transmittance.
Copy link
Contributor

@shorowit shorowit Apr 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a question about this language: "For the simple glazing object, the adjustment will be applied to the Solar Heat Gain Coefficient and the Visible Transmittance."

I'm not sure that I understand what this means exactly. Can you confirm that these adjustments would not result in the same effect as if someone had adjusted the inputs to the WindowMaterial:SimpleGlazingSystem object in the same way? I primarily want to make sure that different angular properties or solar correlations, derived using SHGC, will not be chosen for the window simply based on whether this shading object is used.

I also wonder why this approach is suggested for the simple glazing system. Is it not possible to modify solar/visible transmittance directly, as is done for detailed windows?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback :)

My understanding is that if the adjustment factor is 0.5, the SHGC and U-value from user input are both 0.7, then the actual SHGC and U-value in downstream heat balance calculation will be 0.35 and 0.7. It will function the same way as if users input 0.35 and 0.7 as the SHGC and U-value, without configuring the simplified shading.

It is possible to make the user directly modify the U and SHGC inputs in WindowMaterial:SimpleGlazingSystem, but maybe a more unified shading object is a bit more direct when they model the shading device?

As for the angular properties, I haven't thought of this before. But if we want to maintain the correlation curve, we could keep track of the information and use the correlation curve from the un-adjusted U-value, SHGC combination. With the above example, we'll use curve E instead of curve J in the following diagram. What do you feel about this approach?

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that if the adjustment factor is 0.5, the SHGC and U-value from user input are both 0.7, then the actual SHGC and U-value in downstream heat balance calculation will be 0.35 and 0.7. It will function the same way as if users input 0.35 and 0.7 as the SHGC and U-value, without configuring the simplified shading.

My point is that I don't think it should behave the same way, because it can result in different detailed window properties being used. I assume the detailed window properties should remain the same whether this shading object is used or not.

As for the angular properties, I haven't thought of this before. But if we want to maintain the correlation curve, we could keep track of the information and use the correlation curve from the un-adjusted U-value, SHGC combination. With the above example, we'll use curve E instead of curve J in the following diagram. What do you feel about this approach?

Angular properties are just one example. See the description of the simple window model. For example, I assume the layer solar transmittance, layer solar reflectance, and layer visible properties would also need to use the unadjusted values. It feels like trying to use the unadjusted values everywhere they should be used is a risky approach, in that some may be missed. I can't help but wonder if there's a simpler implementation approach (like simply reducing the direct/diffuse solar that the window sees), but I say this without any knowledge of the code. Perhaps @EnergyArchmage or @nealkruis has an opinion here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we will just adjust the $T_{sol}$ computed as below (https://bigladdersoftware.com/epx/docs/9-6/engineering-reference/window-calculation-module.html#step-4.-determine-layer-solar-transmittance), not adjusting SHGC itself, so that all other calculations use the original un-adjusted values? Any thoughts? @shorowit

image

@nealkruis
Copy link
Member

  1. Is there a reason not to allow specification of both transmittance and reflectance? I imagine most of the radiation that is not transmitted by shades is absorbed, not reflected.
  2. Can we just have it always be scheduled? The choice of fixed vs. scheduled can easily be solved with a constant schedule.

@shorowit
Copy link
Contributor

Is there a reason not to allow specification of both transmittance and reflectance? I imagine most of the radiation that is not transmitted by shades is absorbed, not reflected.

@nealkruis When organizations like RESNET and Building America require interior shading multipliers, do you really think they intend for the solar to be absorbed and not reflected? My assumption is that they have set the shading multiplier to account for how much solar energy is transmitted and absorbed, though I've never been able to track down where these factors originated. I would be shocked if any software tool is assuming that the solar not transmitted by shades is absorbed rather than reflected.

@nealkruis
Copy link
Member

These are very hypothetical shading devices. I'm not sure where the assumptions in RESNET / BA originated, though I suspect they largely come from the limitations in modeling approaches in DOE-2.

In reality, I imagine most shades are more absorptive than reflective, and I don't think it hurts to be able to specify both. It only adds flexibility.

@shorowit
Copy link
Contributor

I agree that the flexibility doesn't hurt. Just wanted to make sure we're on the same page about how software are currently using the simplified interior shading multipliers, which is driving the motivation here. Sounds like we are.

@JasonGlazer
Copy link
Contributor

I believe the intent is that WindowShadingControl would have no impact. Also, I presume this would not apply to the EquivalentLayer windows. I also assume this cannot be combined with traditional WindowMaterial:Shade, WindowMaterial:Blind, WindowMaterial:Screen. I'm not sure about WindowMaterial:SimpleGlazingSystem. What ever the restrictions, they should be made clear in the NFP.

Many, many references to "shade" or "shading" are in the IOref (although many of those don't apply to windows) but I hope as part of this work some review would be made and documentation updated in a few key places to explain whether this new input object applies or not.

In addition, I would recommend new errors or warnings should be added when this is attempted to be used with something WindowShadingControl or other input objects related to more detailed window shading.

@rraustad
Copy link
Collaborator

This big beautiful message says it all, at least I hope it says it all.

    if (WrongWindowLayering) {
        ShowSevereError(
            state, "CheckAndSetConstructionProperties: Error in window construction " + state.dataConstruction->Construct(ConstrNum).Name + "--");
        ShowContinueError(state, "  For multi-layer window constructions the following rules apply:");
        ShowContinueError(state, "    --The first and last layer must be a solid layer (glass or shade/screen/blind),");
        ShowContinueError(state, "    --Adjacent glass layers must be separated by one and only one gas layer,");
        ShowContinueError(state, "    --Adjacent layers must not be of the same type,");
        ShowContinueError(state, "    --Only one shade/screen/blind layer is allowed,");
        ShowContinueError(state, "    --An exterior shade/screen/blind must be the first layer,");
        ShowContinueError(state, "    --An interior shade/blind must be the last layer,");
        ShowContinueError(state, "    --An interior screen is not allowed,");
        ShowContinueError(state, "    --For an exterior shade/screen/blind or interior shade/blind, there should not be a gas layer");
        ShowContinueError(state, "    ----between the shade/screen/blind and adjacent glass,");
        ShowContinueError(state, "    --A between-glass screen is not allowed,");
        ShowContinueError(state, "    --A between-glass shade/blind is allowed only for double and triple glazing,");
        ShowContinueError(state, "    --A between-glass shade/blind must have adjacent gas layers of the same type and width,");
        ShowContinueError(state, "    --For triple glazing the between-glass shade/blind must be between the two inner glass layers,");
        ShowContinueError(state, "    --The slat width of a between-glass blind must be less than the sum of the widths");
        ShowContinueError(state, "    ----of the gas layers adjacent to the blind.");
        ErrorsFound = true;
    }

@yujiex
Copy link
Collaborator Author

yujiex commented Apr 28, 2022

Can we just have it always be scheduled? The choice of fixed vs. scheduled can easily be solved with a constant schedule.

Right, a constant schedule should cover the constant value case. I felt it's more of a design choice.
From your experience, do you feel the users will be more comfortable configuring a constant schedule or would they like it more as a input field?

@yujiex
Copy link
Collaborator Author

yujiex commented Apr 28, 2022

  1. Is there a reason not to allow specification of both transmittance and reflectance? I imagine most of the radiation that is not transmitted by shades is absorbed, not reflected.

I guess we could add in the reflectance adjustment as well. If users don't want to adjust it, the default value of 1.0 will be used.

@yujiex
Copy link
Collaborator Author

yujiex commented Apr 28, 2022

I believe the intent is that WindowShadingControl would have no impact.

Yes, WindowShadingControl will not take effect on this simplified shading.

Also, I presume this would not apply to the EquivalentLayer windows.

Yes, EquivalentLayer windows already has built-in shadings, so the adjustment in this proposed feature will not apply.

I also assume this cannot be combined with traditional WindowMaterial:Shade, WindowMaterial:Blind, WindowMaterial:Screen.

Yes, it is not combined with any existing shading objects.

I'm not sure about WindowMaterial:SimpleGlazingSystem. What ever the restrictions, they should be made clear in the NFP.

Right, I'll add notes to the NFP that if there's already some other WindowMaterial:Shade or blinds defined for the window, don't use the simplified shading on it.

Many, many references to "shade" or "shading" are in the IOref (although many of those don't apply to windows) but I hope as part of this work some review would be made and documentation updated in a few key places to explain whether this new input object applies or not.

Good point, I'll make sure to clarify in the documentation, which part this new simplified shading applies.

In addition, I would recommend new errors or warnings should be added when this is attempted to be used with something WindowShadingControl or other input objects related to more detailed window shading.

I'll add warnings or error messages regarding the compatibility of this shading object and other shadings or windows.

@mjwitte
Copy link
Contributor

mjwitte commented May 2, 2022

  1. If the "Shading Multiplier" can be scheduled, then the proposed method of adjusting material properties of simple glazing inputs will not work as expected. Window properties are pre-calculated to save computation time. Lurking in the Engineering Reference, Section 7.7.5 Glazing System Properties (v2022.1, pdf p. 302): "The glazing system properties at each angle are used to generate polynomial curve fits with 6 coefficients as a function of cosine of incident angle. The polynomial curves are then used in the simulation to calculate optical properties at each timestep." These are calculated for each window construction (shaded and unshaded).
  2. Daylighting factors for each window (shaded and unshaded) are also pre-calculated for use during the simulation.
  3. I believe the DOE-2 keyword is SHADING-SCHEDULE. From the DOE2.2 manual (March 2009) this "defines hourly values of a multiplier on the solar gain through the window." From the DOE2.1e manual "the resultant solar heat gain calculated from the transmission/absorption coefficients will be multiplied by the schedule." There is also a CONDUCT-SCHEDULE that multiplies the glass conductance.
  4. So, it seems the only way to have a schedulable value is to use it as a modifier on the incident solar (as was suggested above), because there is no single value in the EnergyPlus heat balance that represents the solar heat gain from a given window. Modifying the incident solar should be equivalent to what the DOE-2 model is doing, and it removes the need to worry about whether the solar is reduced by reflection of absorption. (Actually, it implies that it is all reflected away.)
  5. You may want to consider adding a conductance schedule to model the insulating effect of window shades. But this will be trickier to implement in an equivalent fashion in EnergyPlus. The DOE-2 GLASS-CONDUCTANCE is "the heat conductance of the total window except for the outside film coefficient."
  6. Instead of having a field for "Shading Multiplier Input Method", you could have "Shading Multiplier" (with a default of 1.0) and "Shading Multiplier Schedule Name" (where blank means always 1.0) and the use the product of the fixed value and the schedule.
  7. Because this is not intended to work with WindowShadingControls, it should not be included in \reference WindowShadesScreensAndBlinds. It's just a window material layer which will need some special treatment to remove it from the layers and then apply it to the construction.
  8. A better approach might be to make this a SurfaceProperty:* object since it is likely the different window surfaces may have different shading schedules or values. In fact, this sounds a lot like the existing SurfaceProperty:LocalEnvironment "External Shading Fraction Schedule Name".

@mjwitte
Copy link
Contributor

mjwitte commented May 2, 2022

Prompted by @shorowit comment here, I did some testing on SurfaceProperty:LocalEnvironment "External Shading Fraction Schedule Name". It wouldn't be right for this feature, because it has limitations noted here. Ultimately this feature should reduce the incident solar after sunlit fraction has been accounted for by the shadow calculations.

But I might still suggest that this feature be something like SurfaceProperty:SimplifiedWindowShade that could be applied to a single fenestration surface, or possibly groups of fenestration surfaces (just to make life interesting, similar to the way SurfaceProperty:ConvectionCoefficients:MultipleSurface can be applied to AllExteriorWindows, for example.

@yujiex
Copy link
Collaborator Author

yujiex commented May 3, 2022

  1. If the "Shading Multiplier" can be scheduled, then the proposed method of adjusting material properties of simple glazing inputs will not work as expected. Window properties are pre-calculated to save computation time. Lurking in the Engineering Reference, Section 7.7.5 Glazing System Properties (v2022.1, pdf p. 302): "The glazing system properties at each angle are used to generate polynomial curve fits with 6 coefficients as a function of cosine of incident angle. The polynomial curves are then used in the simulation to calculate optical properties at each timestep." These are calculated for each window construction (shaded and unshaded).
  2. Daylighting factors for each window (shaded and unshaded) are also pre-calculated for use during the simulation.

Very good point. It does seem difficult to directly adjust window properties. We'll need to adjust some downstream quantities which are updated at every timestep, as you suggested below.

  1. I believe the DOE-2 keyword is SHADING-SCHEDULE. From the DOE2.2 manual (March 2009) this "defines hourly values of a multiplier on the solar gain through the window." From the DOE2.1e manual "the resultant solar heat gain calculated from the transmission/absorption coefficients will be multiplied by the schedule." There is also a CONDUCT-SCHEDULE that multiplies the glass conductance.

Maybe we can discuss this more in the technicality meeting? I'm not sure if adding adjustments for transmittance, reflectance, and conductance will make the object too complicated, which defeats the purpose of the simplification.

  1. So, it seems the only way to have a schedulable value is to use it as a modifier on the incident solar (as was suggested above), because there is no single value in the EnergyPlus heat balance that represents the solar heat gain from a given window. Modifying the incident solar should be equivalent to what the DOE-2 model is doing, and it removes the need to worry about whether the solar is reduced by reflection of absorption. (Actually, it implies that it is all reflected away.)

Indeed. This is the closest to our intential to discount solar heat gain with a fraction schedule.

  1. You may want to consider adding a conductance schedule to model the insulating effect of window shades. But this will be trickier to implement in an equivalent fashion in EnergyPlus. The DOE-2 GLASS-CONDUCTANCE is "the heat conductance of the total window except for the outside film coefficient."

Em, maybe we could also discuss about it in the meeting. Not sure if we want to perfectly match the DOE-2 behavior, or what do people think about having a conductance here or let users use the regular shading inputs instead.

  1. Instead of having a field for "Shading Multiplier Input Method", you could have "Shading Multiplier" (with a default of 1.0) and "Shading Multiplier Schedule Name" (where blank means always 1.0) and the use the product of the fixed value and the schedule.

"Shading Multiplier Input Method" is intended to guard against the case when both a value and a schedule are given.

@yujiex
Copy link
Collaborator Author

yujiex commented May 3, 2022

Because this is not intended to work with WindowShadingControls, it should not be included in \reference WindowShadesScreensAndBlinds. It's just a window material layer which will need some special treatment to remove it from the layers and then apply it to the construction.

Yeah, I guess this reference should not be here, as the WindowShadingControls shouldn't apply here.

@yujiex
Copy link
Collaborator Author

yujiex commented May 3, 2022

But I might still suggest that this feature be something like SurfaceProperty:SimplifiedWindowShade that could be applied to a single fenestration surface, or possibly groups of fenestration surfaces (just to make life interesting, similar to the way SurfaceProperty:ConvectionCoefficients:MultipleSurface can be applied to AllExteriorWindows, for example.

This is probably a good way to approach this. We could also discuss it in the meeting.

@hongtz68
Copy link
Contributor

hongtz68 commented May 4, 2022

Excellent comments, folks. Talk to you soon at the technicalities call.

@shorowit
Copy link
Contributor

shorowit commented May 4, 2022

I mentioned this on the Technicalities call, but just wanted to write down that we're essentially trying to replace our current approach for modeling simple shading multipliers, which involves:

  • Creating a shading surface of the same size of the window, with a slight offset
  • Using an EMS actuator to adjust the transmissivity of the shading surface throughout the year

This gives us the desired effect, but it's 1) complicated for a user to implement, and 2) introduces runtime impacts because of all the additional shadowing calculations.

@mjwitte
Copy link
Contributor

mjwitte commented May 4, 2022

@shorowit I'm surprised your current approach is working. See #5185

@shorowit
Copy link
Contributor

shorowit commented May 4, 2022

Ah, my memory has failed me. I conflated two different things. It turns out that we use a fixed schedule (not EMS actuated schedule) for the shading surface transmittance, that's why we don't hit the above issue. But then we use EMS to actuate the View Factor To Ground that the window sees, in order to also adjust the solar reflected from the ground. We've performed tests to verify that we get identical results to using an EPW file with modified solar radiation. (In our general use case, we can't rely on modifying the EPW solar radiation values to achieve the desired result because we need to support different shading multipliers for different windows.)

So this might be another nuance to consider in the implementation of this feature. To be clear, we would like the total solar radiation (direct, diffuse, and ground reflected) seen by the window to be adjusted by the user input.

@yujiex
Copy link
Collaborator Author

yujiex commented May 4, 2022

I mentioned this on the Technicalities call, but just wanted to write down that we're essentially trying to replace our current approach for modeling simple shading multipliers, which involves:

  • Creating a shading surface of the same size of the window, with a slight offset
  • Using an EMS actuator to adjust the transmissivity of the shading surface throughout the year
    This gives us the desired effect, but it's 1) complicated for a user to implement, and 2) introduces runtime impacts because of all the additional shadowing calculations.

Thanks for the notes. Yes, the intention of this feature would be to not create a physical layer but achieve the desired outdoor-indoor solar gain discount.

In our general use case, we can't rely on modifying the EPW solar radiation values to achieve the desired result because we need to support different shading multipliers for different windows.

Yes indeed. This would mean all windows have the same shading, which is not what we wanted. But good as a testing mechanism: we could compare two cases, one with a simplified shading multiplier, one without the shading multiplier but with modified solar radiation in the epw file.

To be clear, we would like the total solar radiation (direct, diffuse, and ground reflected) seen by the window to be adjusted by the user input.

Yes, this is my current understanding too.

@yujiex
Copy link
Collaborator Author

yujiex commented May 5, 2022

Thanks for all the comments in the technical call and the comments in the PR. Regarding the issues touched, I summarized a few points here

  • There are two ways to implement this multiplier: one way is as Mike and Scott suggested to modify the incident Solar, the other way is to modify the direct and diffuse solar gain from the interior surface of the window inward. I’ll check out which way is cleaner to implement.
  • For the constant value/schedule fields, we’ll use Mike’s suggested approach and remove the field "Shading Multiplier Input Method", and user will use the constant multiplied by the schedule as the final adjustment factor.
  • We’ll only have the adjustment factor on solar and visible transmittance. If users need to control conductance and reflectance as well, they will need to use the regular shading object.
  • About the “simplified” wording, I still can’t come up with a better one. Maybe we’ll just stick with this and clarify in the documentation that this is not a direct simplification of the current shading, but a fractional adjustment.
  • If this shading is defined for a window, then other types of regular shading or blinds as well as WindowShadingControls will not be allowed. If users defined both, then a warning or error message will be thrown.

@JasonGlazer
Copy link
Contributor

  • About the “simplified” wording, I still can’t come up with a better one. Maybe we’ll just stick with this and clarify in the documentation that this is not a direct simplification of the current shading, but a fractional adjustment.

Presuming that this input object does not represent a physically possible system, the use of the term "simple" is misleading since it implies that it is good for users that are beginning to use EnergyPlus and don't have all the input required for a different input object. In this case, conceptually this is not simple at all since it is modifying something that might not be even physically possible. Instead of the user being able to use this input object with a "simple" mental model of what is going on they actually need a deeper understanding than a typical user. I would recommend getting rid of the words "simple" or "simplified" completely in the name of the input object and in this pull request title and just use the term "Multiplier". You might also consider the term "ResearchSpecial" as part of the name of the input object just to discourage its use like we have with other input objects that we are only adding for a special case.

@EnergyArchmage
Copy link
Contributor

I would suggest using two simplified glazing systems, one with shade deployed and one without the shade. And then interpolating between them as is done for switchable electrochromic glazing modeling.

@mjwitte
Copy link
Contributor

mjwitte commented May 5, 2022

Is this intended to be used only with WindowMaterial:SimpleGlazingSystem? Or any type of window construction?

@shorowit
Copy link
Contributor

shorowit commented May 5, 2022

I would hope that it can be used with any window construction.

Real64 GndSolarRadInc = max(state.dataEnvrn->BeamSolarRad * state.dataEnvrn->SOLCOS(3) + state.dataEnvrn->DifSolarRad, 0.0);
for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
state.dataSurface->SurfSkySolarInc(SurfNum) = state.dataEnvrn->DifSolarRad * state.dataSolarShading->SurfAnisoSkyMult(SurfNum);
Real64 SurfIncSolarMultiplier = GetSurfIncidentSolarMultiplier(state, SurfNum);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the multiplier 1.0 for all surfaces other than exterior windows? In that case, you probably don't want to call this function for every surface. What you want to do is have an array initialized to 1.0 for every surface and then at the beginning of every time step, call this function only for exterior windows and overwrite their entries with the scheduled value.

Copy link
Collaborator Author

@yujiex yujiex Aug 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the multiplier 1.0 for all surfaces other than exterior windows?

Yes. That's the intention. Only for exterior surfaces with user-defined incidentSolarMultiplier object can equal to values other than 1.0.

I will rearrange the code and overwrite the values for exterior window instead of calling this function on all surfaces.

yujiex added 9 commits August 7, 2022 15:14
- put surface location and type check before material group about presence of
  other shading
- split error message to surface type (window, wall, etc.) and location
  (ext, interior), adjust unit test
- when the schedule index is not found but the input field is not empty
- Also fixed a typo in the name checking part
Query incident solar multiplier for a surface only once every timestep
iteration, instead of querying whenever a SurfNum is encountered
also moved check for typo in schedule name at the beginning of filling in the data
@yujiex
Copy link
Collaborator Author

yujiex commented Aug 12, 2022

Hi, @EnergyArchmage would you be available to look at whether the incident solar multiplier implementation makes sense? Sorry for tagging you so late.

\type real
\units dimensionless
\minimum 0
\maximum 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this project started out as providing a simplified shading solution. But the final approach is fairly general and it could be used to amplify incident solar as well as reduce it. It seems to me that the maximum limit of 1.0 is a bit arbitrary. If you want to allow magical reduction of solar, why not allow magical increases as well? E.g. users could quickly see what would happen if the windows transmitted 20% more solar. Or maybe they know a neighboring building is reflecting a ton of solar during certain times.

@EnergyArchmage
Copy link
Contributor

I have studied the code and don't see any problems with the implementation.

@hongtz68
Copy link
Contributor

Thanks Brent for your review and comments. Very appreciate it.

Copy link
Member

@Myoldmopar Myoldmopar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general this looks good, and ready. But I'm holding back on marking it approved until I hear back about the > 1.0 comment. There's a tiny conflict that I can resolve locally during testing if no other changes end up being needed.

}
for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
state.dataSurface->SurfSkySolarInc(SurfNum) = state.dataEnvrn->DifSolarRad * state.dataSolarShading->SurfAnisoSkyMult(SurfNum);
auto const &SurfIncSolarMultiplier = state.dataSurface->Surface(SurfNum).IncSolMultiplier;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

state.dataSurface->Surface(SurfNum).IncSolMultiplier is just a float right? If so, we for sure don't need the auto shorthand. And I don't think we really want it to be a reference either. I guess neither of these are really functional changes, so I don't think it's worth holding this up. I'll keep moving.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It is just a real number. Should just use Real64 instead of the ref. I'll change it now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, there was also something in the Clang-Format test, so get that fixed up too and this could be ready assuming the >1 comment is resolved.

\type real
\units dimensionless
\minimum 0
\maximum 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@EnergyArchmage you had suggested we could go higher than 1.0 for some interesting simulation studies. Should this be > 0? I haven't seen whether the schedule in the next field allows for > 1 or not, but the comment suggests it should be 0 < x < 1.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@EnergyArchmage @Myoldmopar An interesting and constructive comment on the multiplier value being greater than 1 to allow other use cases. Indeed it is possible but it stretches the original design purpose which is to simulate a simplified shading effect for windows. I suggest we keep it as it is and come back in future to expand it for other use cases including Brent's mentioned case, shading for opaque walls or special dynamic coating for surfaces etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't recall that multiplier = 0.0 would be a problem in the code. Could be useful for elimination parametric studies.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 and 1 should both be inclusive. 0 corresponds to a full-shading case and 1 corresponds to no shading.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

multiplier = 0 should be allowed to model special cases such as 'opaque' windows or windows covered by aluminum foil.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Myoldmopar I didn't find the comment suggesting the incident solar multiplier greater than 0 (not inclusive). Could you please point me there? I'll change it to inclusive.

@Myoldmopar
Copy link
Member

Myoldmopar commented Aug 15, 2022

To do:

  • Clang format
  • Conflict
  • Make sure > 1.0 comment is settled
  • Optionally change the auto & declarations to plain Real64 -- if I'm understanding it correctly just from code inspection.

@Myoldmopar
Copy link
Member

Thanks @yujiex ! It looks like everything is resolved. I'm going to pull in develop since I just merged a PR and test locally now.

@yujiex
Copy link
Collaborator Author

yujiex commented Aug 15, 2022

Thanks @yujiex ! It looks like everything is resolved. I'm going to pull in develop since I just merged a PR and test locally now.

Thanks, @Myoldmopar. Ben and I are doing some local testing on the shading multipliers by comparing this feature branch with some basecases one with a EMS actuator controlling ground view factor, and one that modifies the .epw weather input solar radiation value. Since neither of the base cases are perfect: the EMS one had some issue of incident solar component not adding up to total incident solar, the epw-modifying one differs with this feature branch in wall and roof incident solar as well (ideally we want them to differ only in window incident solar), the differences shown with these verifications might not indicate a problem in the implementation.

Do you think we can merge in the current state of the feature branch and if we later find better testing base cases, or fixed the EMS one and if the better testing basecases show some problem in the implementation, we could open up another PR to fix the issue? The idd part probably does not need to be modified in that case.

@hongtz68
Copy link
Contributor

@yujiex @Myoldmopar Since Brent also reviewed and confirmed the implementation is fine, let us merge in the code. If later we confirm and need to fix any issues, we can post a CR. The EMS exercise has taken quite some time and it may take additional weeks or months.

@Myoldmopar
Copy link
Member

Everything tests fine here, merging this one, and yes, if there is any follow-up stuff, that's fine. Thanks all.

Comment on lines +2631 to +2633
for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
state.dataSurface->Surface(SurfNum).IncSolMultiplier = GetSurfIncidentSolarMultiplier(state, SurfNum);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this has been merged, but I'm noticing this as I resolve conflicts over in the space heat balance branch. There should be a global flag for AnySolarMultipliers that can be used to skip this entire loop if they are not being used (which is the common case).
Also, I would assume these apply only to exterior windows? If so, the loop can be for(int SurfNum : state.dataSurface->AllExtSolWindowSurfaceList).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense. I'll add in a global flag to skip the whole loop, and also restrict the looping to within state.dataSurface->AllExtSolWindowSurfaceList

state.dataSurface->SurfSkySolarInc(SurfNum) = state.dataEnvrn->DifSolarRad * state.dataSolarShading->SurfAnisoSkyMult(SurfNum);
Real64 SurfIncSolarMultiplier = state.dataSurface->Surface(SurfNum).IncSolMultiplier;
state.dataSurface->SurfSkySolarInc(SurfNum) =
state.dataEnvrn->DifSolarRad * SurfIncSolarMultiplier * state.dataSolarShading->SurfAnisoSkyMult(SurfNum);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of introducing an extra multiplication for every surface, why not move the GetSurfIncidentSolarMultiplier to be after this loop and modify the final results instead, and only if there are AnySolarMultipliers, then this function could be renamed ModifySurfIncidentSolar and just apply the corrections as needed. I'm not sure if this can be done everywhere this is being applied, but we want to limit as much extra computation as possible for the common case which has no multipliers.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is written this way so that it is easier for me to keep track: whenever a surface has something computed using state.dataEnvrn->DifSolarRad, state.dataEnvrn->BeamSolarRad, or state.dataEnvrn->GndSolarRad, the multiplier is applied when the surface has an incident solar multiplier defined. Now that hopefully I've captured all the places where the multiplier needs to be added. I can certainly make the modification and move the solar adjustment to after the loop. I'm not sure if directly modifying GetSurfIncidentSolarMultiplier would work, as different variables are adjusted in different places the multiplier is used. But at least I can do something like this. What do you think? @mjwitte

if (state.dataGlobal->AnySolarMultipliers) {
  for (int SurfNum : state.dataSurface->AllExtSolWindowSurfaceList) {
    Real64 SurfIncSolarMultiplier = state.dataSurface->Surface(SurfNum).IncSolMultiplier;
    variableToAdjust *= SurfIncSolarMultiplier;
  }
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yujiex Yes, that's what I was suggesting. I'll leave it to you to evaluate the best approach.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A similar approach is used for things like TDD diffuser and dome in other parts of the code, if I remember correctly.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the pointer. I'll check out the TDD diffuser and dome code.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure the local variable helps here since it's used only once. Just use a 1-liner.

variableToAdjust *= state.dataSurface->Surface(SurfNum).IncSolMultiplier;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a few more terms to adjust (didn't list them all here), so I assume with a temp variable saves a little time in retrieving the multiplier value

@yujiex
Copy link
Collaborator Author

yujiex commented Aug 16, 2022

I just did an experiment to see the impact of the multiplication of the SurfIncSolarMultiplier, using the 15zonePSZ.idf file in the performance_test folder. I compared the current branch with one removing all * SurfIncSolarMultiplier terms and Real64 SurfIncSolarMultiplier = state.dataSurface->Surface(SurfNum).IncSolMultiplier;. I ran each case for 30 times and recorded the time for every simulation run.

The following is the t-test result. The difference between the average run time with and without the multiplication terms is not statistically significant.

data:  with_mult_times_in_seconds and no_mult_times_in_seconds
t = 1.6269, df = 57.825, p-value = 0.1092
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.01912275  0.18505609
sample estimates:
mean of x mean of y 
 13.74913  13.66617 

The following is a quantile comparison

with multiplication:
      0%      25%      50%      75%     100% 
13.12300 13.64975 13.74100 13.81950 14.33600 
without multiplication:
       0%      25%      50%      75%     100% 
13.27500 13.57125 13.65000 13.70975 14.36400 

Is this type of performance difference critical?

When I am actually trying to make the rearrangement, it seems kind of error-prone: previously I just needed to keep track of three terms, in the modified case, I will need to keep track of all downstream terms computed from the three solar components and remember to adjust all of them.

Any thoughts? @mjwitte @Myoldmopar

@mjwitte
Copy link
Contributor

mjwitte commented Aug 16, 2022

Linux CI is several commits away from reporting the "official" performance measure for this, so it's hard to know if there's a significant impact. How about a compromise? For loops that have more than a few instances of ...SolarRad * SurfIncSolarMultiplier, how about this at the top of the loop:

Real64 surfMultBeamSolarRad= state.dataEnvrn->BeamSolarRad * state.dataSurface->Surface(SurfNum).IncSolMultiplier;
Real64 surfMultDifSolarRad= state.dataEnvrn->DifSolarRad * state.dataSurface->Surface(SurfNum).IncSolMultiplier;

@yujiex
Copy link
Collaborator Author

yujiex commented Aug 16, 2022

Linux CI is several commits away from reporting the "official" performance measure for this, so it's hard to know if there's a significant impact. How about a compromise? For loops that have more than a few instances of ...SolarRad * SurfIncSolarMultiplier, how about this at the top of the loop:

Real64 surfMultBeamSolarRad= state.dataEnvrn->BeamSolarRad * state.dataSurface->Surface(SurfNum).IncSolMultiplier;
Real64 surfMultDifSolarRad= state.dataEnvrn->DifSolarRad * state.dataSurface->Surface(SurfNum).IncSolMultiplier;

I'll try to do it this way. Thanks for the suggestion.
Yesterday I was considering refactoring out the loop part and looping through exterior windows and its complement separately, one with multiplication, one without. However that seems too much change as well, plus getting the complement of exterior windows would also cost some computation. Your approach should be better.

Although do you think the compilers will already do a simplification like this one you mentioned?

// inside one iteration
x1 = BeamSolarRad * mult * a1
x2 = BeamSolarRad * mult * a2
x3 = BeamSolarRad * mult * a3
y1 = DifSolarRad * mult * b1
y2 = DifSolarRad * mult * b2
y3 = DifSolarRad * mult * b3

Do you think the compiler might already optimize it (like this one: https://en.wikipedia.org/wiki/Common_subexpression_elimination) and store the result of BeamSolarRad * mult and DifSolarRad * mult instead of computing it three times (unless it thinks it would be slower due to register management and memory accessing cost)? @mjwitte @amirroth Oh is our goal just the release build performance or do we also care about debug performance?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

IDDChange Code changes impact the IDD file (cannot be merged after IO freeze) NewFeature Includes code to add a new feature to EnergyPlus

Projects

None yet

Development

Successfully merging this pull request may close these issues.