-
Notifications
You must be signed in to change notification settings - Fork 394
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
PVWatts Speed Up #8960
PVWatts Speed Up #8960
Conversation
src/EnergyPlus/PVWatts.cc
Outdated
PVWattsGenerator &GetOrCreatePVWattsGenerator(EnergyPlusData &state, std::string const &GeneratorName) | ||
{ | ||
// Find the generator, and create a new one if it hasn't been loaded yet. | ||
int ObjNum = | ||
state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Generator:PVWatts", UtilityRoutines::MakeUPPERCase(GeneratorName)); | ||
assert(ObjNum >= 0); | ||
if (ObjNum == 0) { | ||
ShowFatalError(state, "Cannot find Generator:PVWatts " + GeneratorName); | ||
} | ||
|
||
auto &PVWattsGenerators(state.dataPVWatts->PVWattsGenerators); | ||
|
||
auto it = PVWattsGenerators.find(ObjNum); | ||
auto it = PVWattsGenerators.find(GeneratorName); | ||
if (it == PVWattsGenerators.end()) { | ||
// It's not in the map, add it. | ||
PVWattsGenerators.insert(std::make_pair(ObjNum, PVWattsGenerator::createFromIdfObj(state, ObjNum))); | ||
PVWattsGenerator &pvw(PVWattsGenerators.find(ObjNum)->second); | ||
int ObjNum = | ||
state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Generator:PVWatts", UtilityRoutines::MakeUPPERCase(GeneratorName)); | ||
assert(ObjNum >= 0); | ||
if (ObjNum == 0) { | ||
ShowFatalError(state, "Cannot find Generator:PVWatts " + GeneratorName); | ||
} | ||
|
||
PVWattsGenerators.insert(std::make_pair(GeneratorName, PVWattsGenerator::createFromIdfObj(state, ObjNum))); | ||
PVWattsGenerator &pvw(PVWattsGenerators.find(GeneratorName)->second); | ||
pvw.setupOutputVariables(state); | ||
return pvw; |
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 lookup of the PVWatts object in the list was adding some time mostly because we called the input processor every time around to get the ObjNum
from the object name. Changed the std::map
that holds those to have the names as keys instead of ObjNum
and it shaved some time off.
private: | ||
bool system_inputs_are_setup; | ||
public: | ||
|
||
cm_pvwattsv5_1ts() | ||
{ | ||
add_var_info(_cm_vtab_pvwattsv5_1ts_weather); | ||
add_var_info(_cm_vtab_pvwattsv5_common); | ||
add_var_info(_cm_vtab_pvwattsv5_1ts_outputs); | ||
system_inputs_are_setup = false; | ||
} | ||
|
||
void exec() | ||
{ | ||
setup_system_inputs(); | ||
if (!system_inputs_are_setup) { | ||
setup_system_inputs(); | ||
system_inputs_are_setup = true; | ||
} | ||
double ts = as_number("time_step"); |
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 probably the biggest win. Using the 1-timestep model from SSC caused the panels to be initialized every timestep. This isn't a design flaw on their end because they take the unchanging properties of the PV system as inputs each timestep, so it could need to be reinitialized, but we know we're not changing those, so I hacked it to only initialize the first time.
if (!verify("precheck input", SSC_INPUT)) return false; | ||
// if (!verify("precheck input", SSC_INPUT)) return false; | ||
exec(); | ||
if (!verify("postcheck output", SSC_OUTPUT)) return false; | ||
// if (!verify("postcheck output", SSC_OUTPUT)) return false; |
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.
The "compute module" (cmod) in SSC verifies all inputs at each timestep are within valid ranges or enums. We're doing that validation with the idd, so no need to redo that here.
@amirroth There are typically few |
@nmerket The real question is not why should you use a |
@amirroth If you look at the |
@nmerket I was not accusing you of creating this pattern, only of perpetuating it. (Unless of course you also wrote PVWatts itself, in which case I guess I am accusing you of creating it). Either way, please don't double down by perpetuating the class factory pattern also. The factory pattern was created for "impure" object-oriented languages like C++ that don't have first-class types aka virtual constructors. But PVWatts is not even using factory to mimic virtual constructors, so it is not clear what role the factory pattern is playing here other than maybe showing other developers that the developer is cool because he/she has heard of this pattern and also knows how to use Here's the meta-point about map, the factory pattern, and many other things too. Note, this is not specific to you or PVWatts nor is this thread really specific to you or PVWatts, I have made similar comments elsewhere to other developers working on other modules. There is a lot of seemingly cool stuff in C++, STL and other template libraries, and certainly in various OOP and design pattern books. 90% of this stuff has fairly niche uses. I am not saying |
@nmerket This is a big speed improvement relative to v9.5, but I'm surprised that the simulation is still roughly twice as slow as v9.2 Any idea what the remaining slowdown is due to? |
@shorowit Digging a bit deeper into the profiling between versions, we're getting deep into changes in SAM at this point. In the version of the SSC code that ran in v9.2, the function irrad::calc takes up 114 ms of runtime, but in the newer version it takes 6.15s. That's almost the entire difference in runtime. That could be some combination of it being called more times and/or each call takes longer. (It's hard to tell the difference with a sampling profiler, which is all I have access to.) I can't see why it would be calling it more times, though, so I suspect that it's actually taking much longer to run. There are clear differences in the solarpos calculations. This really seems like a speed improvement that will need to be made in SSC upstream. |
Pulled develop in, and fixed the Clang format issue. Built and ran just fine. All tests pass and no unexpected regressions. Only diff is the PVWatts file, which shaved ~60% off on my design day run, even with the overhead of 20 threads running simulations simultaneously. This is a great, high-impact change. If further improvement can be made, cool, but it can happen later. I'm pushing my Clang format fix now and will merge. Thanks @nmerket |
Pull request overview
Fixes #8940
We noticed a performance hit when using PVWatts between v9.2 and v9.5. This was due to the way we're calling out to the SSC library now instead of embedding it in EnergyPlus directly. Apparently there's a noticeable amount of overhead in calling the SSC "compute modules". I've trimmed out what I could. Here are some timings for the residential file I'm working with:
1914It's not quite back to 9.2 level speed, but much improved anyway. I called it where I did because I was running out of big time sinks in the profiling. This should have zero diffs, but will run faster for buildings that use the PVWatts model.
cc @shorowit
Pull Request Author
Add to this list or remove from it as applicable. This is a simple templated set of guidelines.
Pull requests that impact EnergyPlus code must also include unit tests to cover enhancement or defect repairPVWatts unit tests already exist that test the code in question.If any diffs are expected, author must demonstrate they are justified using plots and descriptionsIf changes fix a defect, the fix should be demonstrated in plots and descriptionsIf any defect files are updated to a more recent version, upload new versions here or on DevSupportIf IDD requires transition, transition source, rules, ExpandObjects, and IDFs must be updated, and add IDDChange labelIf structural output changes, add to output rules file and add OutputChange labelIf adding/removing any LaTeX docs or figures, update that document's CMakeLists file dependenciesReviewer
This will not be exhaustively relevant to every PR.