-
Notifications
You must be signed in to change notification settings - Fork 392
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
Clean headers from A-C #9365
Clean headers from A-C #9365
Conversation
clean header Boilers
bool getBoilerInputFlag = true; | ||
Array1D<Boilers::BoilerSpecs> Boiler; | ||
|
||
void clear_state() override | ||
{ | ||
this->numBoilers = 0; | ||
this->getBoilerInputFlag = true; | ||
this->Boiler.deallocate(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we no longer have to call deallocate()
? Did we not have to call it to begin with?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need the deallocate anymore because we are creating a new instance. For the same reason, we don't need to manually go member-by-member resetting them to their original values anymore. It's so much nicer. Once we get all these clear_states cleaned out to the minimal new code, I think we will have a very rapid change where we don't really need the individual clear_state functions anymore. But we'll see...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So ... what is happening to the old instance? Does it get properly destroyed or are we leaking insane amounts of memory here? I admit I don't have a lot of experience with the *this =
idiom. It looks very strange and wrong to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be leaking anything. I made a prototype of this and called clear_state
50bn times and the memory usage on the process never went up, and I could see the destructor being called every time, so the assignment seems to be doing everything we need here. This paradigm was suggested by @lefticus, so I feel pretty good about it.
Now, that said, I think once we have all the clear_state
functions cleaned up to this level, we can just go back to where we are calling clear_state
, and change the call so that we don't need the intermediary clear_state
function, if in fact all it is doing is deleting the last one and creating a new one.
(As a final aside, just note that this function is only called during serial unit test runs, and in case someone is calling clear_state during serial runs of E+ via API)
MixedWindowsUserCurveNum(0) | ||
{ | ||
} | ||
int SimpleBuoyVertWallEqNum = ConvectionConstants::HcInt_FohannoPolidoriVerticalWall; // InConvClass_A3_VertWalls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Straight up one of the most ridiculous data structures in EnergyPlus.
Real64 CoeffA23 = 0.0; | ||
Real64 CoeffA24 = 0.0; | ||
Real64 CoeffA25 = 0.0; | ||
Real64 CoeffA26 = 0.0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What programming was like before arrays were invented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😄
src/EnergyPlus/BoilerSteam.hh
Outdated
PressErrIndex(0), FluidIndex(0), myFlag(true), myEnvrnFlag(true), FuelUsed(0.0), BoilerLoad(0.0), BoilerEff(0.0), | ||
BoilerMassFlowRate(0.0), BoilerOutletTemp(0.0), BoilerEnergy(0.0), FuelConsumed(0.0), BoilerInletTemp(0.0), | ||
BoilerFuelTypeForOutputVariable("") | ||
BoilerSpecs() : plantLoc{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this necessary? Why is plantLoc
default constructor not called automatically?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was part of a diff debug and has been removed
@@ -171,15 +164,12 @@ namespace BoilerSteam { | |||
|
|||
struct BoilerSteamData : BaseGlobalStruct | |||
{ | |||
int numBoilers = 0; | |||
bool getSteamBoilerInput = true; | |||
Array1D<BoilerSteam::BoilerSpecs> Boiler; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no reason for a 1D array of anything that isn't int
, Real64
, or bool
to be an Array1D
rather than an EPVector
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, we are definitely moving in that direction. We can go back through these few files and add an extra effort to make sure all the Array1Ds are transitioned. We were trying to balance the header file cleanup with how many lines we had to change in the cc files. Changing this to a vector will cause quite a lot of changes, but I'm OK adding that here if you want.
src/EnergyPlus/BranchInputManager.cc
Outdated
state.dataBranchInputManager->Branch.allocate(state.dataBranchInputManager->NumOfBranches); | ||
int NumOfBranches = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject); | ||
if (NumOfBranches > 0) { | ||
state.dataBranchInputManager->Branch.allocate(NumOfBranches); | ||
for (auto &e : state.dataBranchInputManager->Branch) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this loop necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't look like it should be now. But it's been in there since the C++ translation. Back in Fortran, right after Branch was allocated, the AssignedLoopName was set to a blank. I think ....maybe.... it was because in Fortran you couldn't rely on the fixed-length strings to be filled with blank spaces? Maybe...?
src/EnergyPlus/BranchInputManager.cc
Outdated
state.dataBranchInputManager->NumOfBranchLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject); | ||
state.dataBranchInputManager->BranchList.allocate(state.dataBranchInputManager->NumOfBranchLists); | ||
int NumOfBranchLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject); | ||
state.dataBranchInputManager->BranchList.allocate(NumOfBranchLists); | ||
for (auto &e : state.dataBranchInputManager->BranchList) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this loop necessary?
src/EnergyPlus/BranchInputManager.cc
Outdated
@@ -2743,7 +2743,7 @@ namespace BranchInputManager { | |||
} | |||
|
|||
// Build node names in branches | |||
for (Count = 1; Count <= state.dataBranchInputManager->NumOfBranches; ++Count) { | |||
for (Count = 1; Count <= (int)state.dataBranchInputManager->Branch.size(); ++Count) { | |||
BranchNodes(Count).UniqueNodeNames.allocate(state.dataBranchInputManager->Branch(Count).NumOfComponents * 2); | |||
BranchNodes(Count).UniqueNodeNames = std::string(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You just did an allocate
on this and now you assign it to a blank string because ... ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these all go back to the original Fortran code, I'm not sure if there is a way we can automatically detect these unnecessary things now...but maybe. Anytime we reset a string to a blank seems like a good starting point, since that seems like an odd thing to do inside the simulation. Then we could add some intelligence to snoop just a couple lines before that assignment to see if it detects an allocation of that variable (or any variable?). Could be a fun excursion.
state.dataChilledCeilingPanelSimple->CheckEquipName.allocate(state.dataChilledCeilingPanelSimple->NumCoolingPanels); | ||
state.dataChilledCeilingPanelSimple->CoolingPanel.allocate(NumCoolingPanels); | ||
state.dataChilledCeilingPanelSimple->CoolingPanelSysNumericFields.allocate(NumCoolingPanels); | ||
state.dataChilledCeilingPanelSimple->CheckEquipName.allocate(NumCoolingPanels); | ||
state.dataChilledCeilingPanelSimple->CheckEquipName = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this assignment operator set all elements of the array to true
? That is a terrible idiom. Is this a Fortran legacy thing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I suppose, and yes, this is a Fortran legacy thing. Really, if the CheckEquipName needs to stay, it has no need to be its own separate array. It should be a simple boolean on the chilled ceiling struct. That's one better pattern we can propagate in this effort for sure.
GPU diff, otherwise CI is clean here. I think it's time to start pushing this toward merge. I need to digest the comments above next. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, so a net of 2400 lines removed. No diffs. Awesome. This is making a bunch of big improvements in the headers and state classes. I think it could use another pass based on my comments and some comments from @amirroth. And then we can take the outcomes of this branch and apply them to the next group of files shortly. Thanks @brianlball !
@@ -161,10 +161,9 @@ namespace BoilerSteam { | |||
|
|||
SteamFluidIndex = 0; | |||
state.dataIPShortCut->cCurrentModuleObject = "Boiler:Steam"; | |||
state.dataBoilerSteam->numBoilers = | |||
state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject); | |||
int numBoilers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yay, every time an unnecessary variable is removed from state and replaced with a local variable, an angel smiles.
thisBoiler.FullLoadCoef(1) = state.dataIPShortCut->rNumericArgs(8); | ||
thisBoiler.FullLoadCoef(2) = state.dataIPShortCut->rNumericArgs(9); | ||
thisBoiler.FullLoadCoef(3) = state.dataIPShortCut->rNumericArgs(10); | ||
thisBoiler.FullLoadCoef[0] = state.dataIPShortCut->rNumericArgs(8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahhh, zero based indexing and square brackets, the way arrays were meant to be in C++ 😄
src/EnergyPlus/BoilerSteam.hh
Outdated
PressErrIndex(0), FluidIndex(0), myFlag(true), myEnvrnFlag(true), FuelUsed(0.0), BoilerLoad(0.0), BoilerEff(0.0), | ||
BoilerMassFlowRate(0.0), BoilerOutletTemp(0.0), BoilerEnergy(0.0), FuelConsumed(0.0), BoilerInletTemp(0.0), | ||
BoilerFuelTypeForOutputVariable("") | ||
BoilerSpecs() : plantLoc{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not necessary.
@@ -171,15 +164,12 @@ namespace BoilerSteam { | |||
|
|||
struct BoilerSteamData : BaseGlobalStruct | |||
{ | |||
int numBoilers = 0; | |||
bool getSteamBoilerInput = true; | |||
Array1D<BoilerSteam::BoilerSpecs> Boiler; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, we are definitely moving in that direction. We can go back through these few files and add an extra effort to make sure all the Array1Ds are transitioned. We were trying to balance the header file cleanup with how many lines we had to change in the cc files. Changing this to a vector will cause quite a lot of changes, but I'm OK adding that here if you want.
this->numBoilers = 0; | ||
this->getSteamBoilerInput = true; | ||
this->Boiler.deallocate(); | ||
*this = BoilerSteamData(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yay! So much DRYer!
this->DoCostEstimate = false; | ||
this->numMonetaryUnit = 0; | ||
this->selectedMonetaryUnit = 0; | ||
this->CurntBldg = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You didn't do anything wrong here, but I dislike that the default values on the struct are all 0.0, but in both cases where we instantiate them, we pass a 1.0 as one of the arguments. I think we should clean that up and just default assign it to 1.0 in the struct and then we don't have to have this initializer list anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think the default values have the same value as the reset now
Real64 CoeffA23 = 0.0; | ||
Real64 CoeffA24 = 0.0; | ||
Real64 CoeffA25 = 0.0; | ||
Real64 CoeffA26 = 0.0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😄
this->NumNodeConnectionErrors = 0; | ||
this->NumOfNodeConnections = 0; | ||
this->MaxNumOfNodeConnections = 0; | ||
this->NodeConnectionAlloc = 1000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This variable smells funny.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It smells funny for two reasons:
- We are carefully allocating out nodes during initialization in chunks, and I think we can rely on C++ to be smart enough to do this behind-the-scenes reservation. Anyway, the second reason is that
- This variable is only used in one function, so I'm moving it to a constexpr int inside that function.
this->varyingOrientationSchedIndex = 0; | ||
this->forceBeginEnvResetSuppress = false; | ||
this->oneTimeCompRptHeaderFlag = true; | ||
*this = EnvironmentData(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yay!!!!!!!!
this->printConsoleOutput = true; | ||
this->installRootOverride = false; | ||
this->numThread = 1; | ||
*this = DataGlobal(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Woo!!
@@ -288,8 +231,7 @@ struct ContaminantBalanceData : BaseGlobalStruct | |||
|
|||
Array1D<Real64> CONTRAT; // Zone CO2 at the previous time step used in Exact and Euler method | |||
Array1D<Real64> MixingMassFlowCO2; // Mixing MASS FLOW * CO2 | |||
int NumContControlledZones = 0; | |||
Real64 OutdoorCO2 = 0.0; // Outdoor CO2 level |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd love to go through this and clean up all the Array1D's, but I'm not going to add that to this PR.
this->MoreNodeInfo.deallocate(); | ||
this->MarkedNode.deallocate(); | ||
this->NodeSetpointCheck.deallocate(); | ||
*this = LoopNodeData(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😄
Just pushed a few commits that should get this ready to merge. This PR cleans up so much, assuming it's clean let's merge this in. If anyone has any remaining comments, speak up soon. |
@amirroth thanks for commenting on this. I responded, and am happy to keep pushing on this as needed to resolve them, but if some of them are more just notes to 📌 for later, I'll just carry on to get this merged in. |
Done, I think this should be ready to drop if clean then. |
All green, merging this one in. Thanks @brianlball for the changes, and @amirroth for the commentary. |
Whatever the runtime implications of initializing in the object declaration, it's much more readable and understandable (given that you have the comments right there too) than having all of those in a giant constructor blob. Definitely a good development in terms of code readability and developer/reviewer sanity! Thanks! |
Clean Headers from A-C