Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update thermal histories refactoring #8873

Merged
merged 34 commits into from
Aug 27, 2021
Merged

Conversation

xuanluo113
Copy link
Contributor

@xuanluo113 xuanluo113 commented Jul 6, 2021

Pull request overview

  • Add a SimpleCTFOnly flag to the simulation to apply shift-only update thermal history
  • Shift thermal history terms by array pointers instead of by values
  • Refactoring of the update thermal histories functions (reverse loop execution orders, move sour or sink checks out of the loop, better namings of arrays, etc.)

Note:

The ESO small diffs of 26 tests are caused by the floating-point rounding diff due to the change of floating-point addition order of this loop.
In develop branch, the SurfCTFConstInPart is added up in surface sequence with the CTF fluxes and the Source fluxes of all historical terms. To avoid checking if construction has a source or sink present at each term, the CTF fluxes are added up first altogether and the source fluxed are added later on. The difference in the order of addition is causing a 10E-14 difference in SurfCTFConstInPart from the second time step of the simulation to the end, and that further causes the regression diffs all over.

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

@xuanluo113 xuanluo113 added Performance Includes code changes that are directed at improving the runtime performance of EnergyPlus Refactoring Includes code changes that don't change the functionality of the program, just perform refactoring labels Jul 6, 2021
@xuanluo113 xuanluo113 added this to the EnergyPlus 9.6 Release milestone Jul 6, 2021
@xuanluo113 xuanluo113 self-assigned this Jul 6, 2021
state.dataHeatBalSurf->SumSurfaceHeatEmission = 0.0;

for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
if (Surface(SurfNum).ExtBoundCond == ExternalEnvironment) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

If this loop is executed frequently, it may be worthwhile to make a std::vector of all surfaces that have ExternalEnvironment as their boundary condition.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The condition Surface(SurfNum).ExtBoundCond == ExternalEnvironment is used frequently but is always paired with and/or with other conditions. A lot of those happen in 'HTSurfaceFirst' to last or 'WinFirst` to last.
As for this loop alone, it gets executed every zone time step. Not sure if it's frequent enough.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well ... do they occur frequently enough that we want to sort the Window surfaces within each Zone into Exterior and Interior Windows? And same for Opaque surfaces?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure if it's worth it. Half of the time the check is paired with ExternalEnvironment || Ground or ExternalEnvironment || OtherSideCoefNoCalcExt or ExternalEnvironment || SurfaceClass == wall, and half of the time the condition is checked in an enclosure loop where we don't have the sorted zone surface priviledge.

for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
if (Surface(SurfNum).ExtBoundCond == ExternalEnvironment) {
state.dataHeatBalSurf->SumSurfaceHeatEmission += state.dataHeatBalSurf->QHeatEmiReport(SurfNum) * state.dataGlobal->TimeStepZoneSec;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Another question about this specifically. Are Surface heat emissions calculated and reported by default or only if the user asks for them?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

displayHeatEmissionsSummary is True with AllSummary declared in Output:Table:SummaryReports, and AllSummary is somewhat frequently declared for tabular reports. But yes I should escape this loop when displayHeatEmissionsSummary is False.

Currently displayHeatEmissionsSummary is read at the end of the first zone time step (where"Output:Table:SummaryReports" is read). I should bring this piece of input processing upfront. (Maybe all getIDFInput functions should.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TBD next branch.

(state.dataHeatBalSurf->QdotRadNetSurfInRepPerArea(SurfNum) = state.dataHeatBalSurf->SurfNetLWRadToSurf(SurfNum)) * surfaceArea;
state.dataHeatBalSurf->QRadNetSurfInReport(SurfNum) = state.dataHeatBalSurf->QdotRadNetSurfInRep(SurfNum) * state.dataGlobal->TimeStepZoneSec;

if (Surface(SurfNum).Class != SurfaceClass::Window) { // not a window...
Copy link
Collaborator

Choose a reason for hiding this comment

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

I also noticed that this test was there and was going to mention it. Glad you caught it.

@xuanluo113
Copy link
Contributor Author

TBD:

  1. Array3D TH(surfNum, side, histTerm) -> Array1D<Array1D> SurfTempHistIn(surfNum, term)
    -> Array1D<Array1D> SurfTempHistOut(surfNum, term)
  2. Same for QH, THM, QHM
  3. Tune loop ordering and vectorization in UpdateThermalHistoris
  4. Merge SurfTempIn and SurfTempOut variables (many to one)
  5. [Optional] std::vector<std::vector>
  6. [Optional] construct.SourceSinkPresent -> combine the loops

@amirroth
Copy link
Collaborator

amirroth commented Jul 10, 2021

TBD:

  1. Array3D TH(surfNum, side, histTerm) -> Array1D SurfTempHistIn(surfNum, term)
    -> Array1D SurfTempHistOut(surfNum, term)
  2. Same for QH, THM, QHM

Yes, you should definitely do this except:

  • The outer Array1D, not the inner one, should be CTFTerm and the inner one should be SurfNum. (maybe this is what you mean by "tune loop ordering"). This way SurfInsideTempCurr is just SurfInsideTempHist(1) and same for SurfOutsideTempCurr. In other words, you won't need those two separate Curr arrays.
  • You should use Array1D<Array1D<Real64>&>. It's important for the inside Array1D to be a reference so that you can move those references around to do history shifting as opposed to copying values.

Also, I don't really understand what THM and QHM are supposed to do.

  1. Tune loop ordering and vectorization in UpdateThermalHistoris
  2. Merge SurfTempIn and SurfTempOut variables (many to one)
  3. [Optional] std::vectorstd::vector
  4. [Optional] construct.SourceSinkPresent -> combine the loops

Tmin = minval(TH(2, 1, {Zone(ZoneNum).HTSurfaceFirst, Zone(ZoneNum).HTSurfaceLast}));
Tmax = maxval(TH(2, 1, {Zone(ZoneNum).HTSurfaceFirst, Zone(ZoneNum).HTSurfaceLast}));
Tmin = minval(state.dataHeatBalSurf->SurfInTempHistCurr({Zone(ZoneNum).HTSurfaceFirst, Zone(ZoneNum).HTSurfaceLast}));
Tmax = maxval(state.dataHeatBalSurf->SurfInTempHistCurr({Zone(ZoneNum).HTSurfaceFirst, Zone(ZoneNum).HTSurfaceLast}));
Copy link
Collaborator

@amirroth amirroth Jul 10, 2021

Choose a reason for hiding this comment

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

If you are looking for both minval and maxval in a given range, it is faster to look for both of them together than to look for them separately.

for (SurfNum = Zone(ZoneNum).HTSurfFirst; SurfNum <= Zone(ZoneNum).HTSurfLast; ++SurfNum)  {
    Real64 SurfTemp = SurfInTempCurr(SurfNum); 
    if (SurfTemp < Tmin) Tmin = SurfTemp;
    else if (SurfTemp > Tmax) Tmin = SurfTemp;
}

Not only are you traversing the elements once instead of twice, but you are also only checking for Tmax those elements that are greater than Tmin.

@xuanluo113
Copy link
Contributor Author

@amirroth 👍 * 100 for Array1D<Array1D&>

@xuanluo113
Copy link
Contributor Author

xuanluo113 commented Jul 17, 2021

Note:

The ESO small diffs of 26 tests are caused by the floating-point rounding diff due to the change of floating-point addition order of this loop.
In develop branch, the SurfCTFConstInPart is added up in surface sequence with the CTF fluxes and the Source fluxes of all historical terms. To avoid checking if construction has a source or sink present at each term, the CTF fluxes are added up first altogether and the source fluxed are added later on. The difference in the order of addition is causing a 10E-14 difference in SurfCTFConstInPart from the second time step of the simulation to the end, and that further causes the regression diffs all over.

@xuanluo113
Copy link
Contributor Author

@amirroth Please see the latest commit. I'm working on the UpdateThermalHistoriesSimpleCTF to allow the address shift to replace the copying. The SimpleCTF is used when ! AnyInternalHeatSourceInInput and !AnyConstrOverridesInModel and no CTFTimeStep > TimeStepZone (code block). The above three scenarios are rarely used.

@xuanluo113
Copy link
Contributor Author

@amirroth Current copying is element by element because when CTFTimeStep > TimeStepZone, say TimeStepZone = 10 min and CTFTimeStep is 1 hour, THMaster and TH are copied every 6 time step, and during in-between time steps, THMaster is not copied and TH is copied by interpolation.

@xuanluo113 xuanluo113 marked this pull request as ready for review August 2, 2021 21:12
@xuanluo113 xuanluo113 requested a review from mjwitte August 2, 2021 21:12
@xuanluo113
Copy link
Contributor Author

@mjwitte Hi Mike, would you mind reviewing this branch, please? Code changes are described in PR overview. CI is clean (small diffs explained in PR overview). 1.68% speedup in CI suites.

Copy link
Contributor

@mjwitte mjwitte left a comment

Choose a reason for hiding this comment

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

Excellent chunk of work! Just a few questions.

Real64 DeltaTemp(0.0); // temporary temperature difference (Tsurf - Tair)
int SurfLoop; // local for separate looping across surfaces in the zone that has SurfNum
Real64 Tmin(std::numeric_limits<float>::min()); // temporary min surf temp
Real64 Tmax(std::numeric_limits<float>::max()); // temporary max surf temp
Copy link
Contributor

Choose a reason for hiding this comment

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

What does std::numeric_limits<float>::max() do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since Tmin and Tmax are used to find the min and max in an array in one loop, by comparing values, I initialized them with the maximum and minimum floating-point numbers in C++ (previously they were initialized with zeros). Then I realized I put them in the wrong order and I just fixed that.

Comment on lines 579 to 580
state.dataHeatBalSurf->SurfOpaqInsFaceCondFlux = 0.0;
state.dataHeatBalSurf->SurfOpaqOutFaceCondFlux = 0.0;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should these be zeroed in a loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes.

state.dataHeatBalSurf->SurfOpaqInsFaceCond(SurfNum) = surface.Area * SurfInsideFluxHistCurr;
state.dataHeatBalSurf->SurfOpaqInsFaceCondFlux(SurfNum) = SurfInsideFluxHistCurr; // for reporting
state.dataHeatBalSurf->SurfInsideFluxHist(1)(SurfNum) = SurfInsideFluxHistCurr;
state.dataHeatBalSurf->SurfOpaqInsFaceCondGainRep(SurfNum) = std::abs(state.dataHeatBalSurf->SurfOpaqInsFaceCond(SurfNum));
Copy link
Contributor

Choose a reason for hiding this comment

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

This line looks wrong. SurfOpaqInsFaceCondGainRep is set in line 5674 inside if (state.dataHeatBalSurf->SurfOpaqInsFaceCond(SurfNum) >= 0.0)
Delete this line?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right. Done.

Comment on lines 4914 to 4918
if (state.dataHeatBalSurf->SurfOpaqInsFaceCond(SurfNum) >= 0.0) {
state.dataHeatBalSurf->SurfOpaqInsFaceCondGainRep(SurfNum) = state.dataHeatBalSurf->SurfOpaqInsFaceCond(SurfNum);
} else {
state.dataHeatBalSurf->SurfOpaqInsFaceCondLossRep(SurfNum) = -state.dataHeatBalSurf->SurfOpaqInsFaceCond(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 think this can be deleted here. The same update is done later in ReportSurfaceHeatBalance. Is there a reason this is needed here also?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. Deleted. Thanks!

@xuanluo113
Copy link
Contributor Author

@mjwitte Mike. I think this branch is ready to be merged. I pulled upstream develop so far and things are working fine.

Copy link
Contributor

@mjwitte mjwitte left a comment

Choose a reason for hiding this comment

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

@xuanluo0113 Ran an annual simulation with RadLoTempHydrHeatCoolMultiZone just to be sure we aren't missing any cumulative diffs, and the ABUPS outputs are identical vs develop. I've merged in develop for one last CI round (if I wait long enough for that). And I'm running one last set of unit tests locally. Otherwise this looks great.

@mjwitte mjwitte merged commit 34456e3 into NREL:develop Aug 27, 2021
@mjwitte mjwitte deleted the vec-refactoring branch August 27, 2021 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Performance Includes code changes that are directed at improving the runtime performance of EnergyPlus Refactoring Includes code changes that don't change the functionality of the program, just perform refactoring
Projects
No open projects
Bug Fixes
Awaiting triage
Development

Successfully merging this pull request may close these issues.

None yet

8 participants