-
Notifications
You must be signed in to change notification settings - Fork 35
Description
I've been running some hundreds of millions of iterations of pvmismatch calculations and am interested in optimizing for calculation speed. I noticed that some of the PVcell property methods get called many times for each calcCell()
invocation, and it seems to me that all but one of each is redundant. For the test script
import pvmismatch
cell = pvmismatch.PVcell()
here is the profiler results for master
:
For instance, Isat1
is called 18 times. I tried out a simple caching mechanism that intercepts property calls and only runs the calculations once:
def cached(f):
def wrapper(self):
key = f.__name__
if key in self._cache:
return self._cache[key]
value = f(self)
self._cache[key] = value
return value
return wrapper
Which, after adding a _cache = {}
definition to the PVcell class and self._cache.clear()
to its __setattr__
method, lets you decorate property methods like this:
@property
@cached
def Isat1(self):
...
Profiler results using the cache on each of the properties (except looks like I forgot Vt
):
And some timings:
# master
%timeit cell = pvmismatch.PVcell()
227 µs ± 8.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# cached
%timeit cell = pvmismatch.PVcell()
111 µs ± 2.75 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
I haven't spent enough time with pvmismatch to be sure of all the conditions where the cache should be invalidated, but it seems like there's some potential for speedup with minimally invasive surgery. The code I used for these tests is here: https://github.com/kanderso-nrel/PVMismatch/tree/pvcell_cache
I wanted to get some feedback on the idea before going too far with it. If folks are in support, I'm happy to open a PR.