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

cache last X calculations, and be smarter about checking cache before recalculating #60

Open
mikofski opened this issue Jan 17, 2018 · 1 comment

Comments

@mikofski
Copy link
Contributor

mikofski commented Jan 17, 2018

This is definitely relevant to #48 and is a spinoff of @bmeyers original cache idea in the rejected PR #42 , and a continuation of the accepted PR #43, that closed the relevant issues #34 and #35 about copies, and of course the ability to delay calculation #59.

The idea is simple, every time you make a calculation in __setattr__ or in calcCells():

  1. check the cache for a similar cell, it's hash should be identical
  2. if the cell doesn't exist yet, then calculate it and store the cell in a cache, like @bmeyers does in Better memory #42 except just store the entire PVcell, no need to serialize it (the cell) right now

The cache should be in pvconstants and should probably have a limit of 100 or 1000 cells. Any strategy can be used to determine which cells to keep in the cache, for example, a count could be kept of how many times each cell was called, and then the least popular cells are culled as needed.

This cache could be repeated for modules and strings as well.

sample code:

from pvmismatch import *

# pvconstants
pvconst = pvconstants.PVconstants()
# monkey patch for example
pvconst.cache = {'pvcells': {}, 'pvmods': {}, 'pvstrs': {}}
pvconst.cache_maxsize = 100

PARAMS = ['Rs', 'Rsh', 'Isat1_T0', 'Isat2_T0', 'Isc0_T0', 'aRBD', 'bRBD', 'VRBD', 'nRBD', 'Eg', 'alpha_Isc', 'Tcell', 'Ee']

def hash_cell(cell, params=PARAMS):
    """cell params is a dictionary with cell params"""
    cell_params = vars(cell)
    cell_hash = str()
    for k in params:
        cell_hash += hex(hash(cell_params[k]))[2:]  # omit '0x'
    return '0x%s' % cell_hash

This works! Generate two different PVcells that are identical, but have different memory locations, and the calculated hash is the same.

>>> pvc = pvcell.PVcell()
>>> cell_hash = hash_cell(pvc)
'0x22f50b4c78e2706476d29247d00a1c997714032461851a3c0257edda00dc9c779a6b50b10061000d96c02215ef60x10df5081cebee80591bad56da435c033333333333334011802e8b2dc60be864cccccccccc012a1'
>>> pvconst.cache['pvcells'][cell_hash ] = pvc  # cache cell for future
>>> id(pvc)
1880798536480  # different
>>> hash(pvc)
117549908530  # different

>>> pvsys = pvsystem.PVsystem()
>>> new_cell_hash = hash_cell(pvsys.pvstrs[0].pvmods[0].pvcells[0])
'0x22f50b4c78e2706476d29247d00a1c997714032461851a3c0257edda00dc9c779a6b50b10061000d96c02215ef60x10df5081cebee80591bad56da435c033333333333334011802e8b2dc60be864cccccccccc012a1'
>>> new_cell_hash in pvconst.cache['pvcells']
True
>>> id(pvsys.pvstrs[0].pvmods[0].pvcells[0])
1880798601344  # different
hash(pvsys.pvstrs[0].pvmods[0].pvcells[0])
117549912584  # different

then in PVmodules

# in #48 update method
def update(self, cell_dicts):
    for pvc, params in cell_dicts.item():
        cell_params = vars(self.pvcells[pvc])
        cell_params.pop('Icell')
        cell_params.pop('Vcell')
        cell_params.pop('Pcell')
        cell_params.pop('pvconst')
        cell_params.pop('_calc_now')
        cell_params.update(params)
        cell_hash = pvconstants.hash_cell(cell_params)
        if cell_hash in self.pvconst.cache['pvcells']:
            # use cache
             self.pvcells[pvc] = self.pvconst.cache['pvcells'][cell_hash]
        else:
            # make a new cell
            self.pvcells[pvc] = pvcell.PVcell(**params, pvconst=self.pvconst)
            self.pvconst.cache['pvcells'][cell_hash] = self.pvcells[pvc]           
@mikofski
Copy link
Contributor Author

@bmeyers check this out, you can use a unique hash for cells as the keys in a dictionary of cells that are cached. This makes returning memoized cells zeroth order because they are actually stored by their unique hash, and because the same key can't be stored twice, you can never have a duplicate in the cache.

You make the unique hash by appending hex strings of the hash of each value to make a super long string that is unique to a set of parameters, as long as you always append them in the same order.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant