Skip to content

Commit

Permalink
ENH: BUG: add _calc_now flag to determine when cell is recalculated (…
Browse files Browse the repository at this point in the history
…GH59) (#61)

* fixes #59

* add class attr _calc_now
* override _calc_now with instance attribte at the end of constructor
* check if _calc_now is True to decide to call self.calcCell() instead
  of checking for pvconst
* use self.__dict__.update() instead of using
  super(PVcell, self).__setattr__(key, value)
* in update, remove TODO, b/c even tho __dict__.update() would bypass
  __setattr__() then would have to check for floats, and still set
  _calc_now = True to trigger recalc, so instead, just set
  _calc_now = False first to turn calculations off, until all attr are
  set, then recalc

* don't set pvcell.pvconst in pvstring

* just raise an exception if they don't match for now
* remove comments about "deepcopy" everywhere

* oops, recalculate means _calc_now = True, duh!

* remove commented legacy code in __setattr__, add comment in update re checking for floats

* add test for new _calc_now flag

* if _calc_now == False, then calcCell() is not called in __setattr__
* if _calc_now == True, then calcCell() is called in __setattr__
  • Loading branch information
mikofski authored and chetan201 committed Feb 5, 2018
1 parent 6abcafe commit c408b1e
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 21 deletions.
26 changes: 16 additions & 10 deletions pvmismatch/pvmismatch_lib/pvcell.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class PVcell(object):
:param pvconst: configuration constants object
:type pvconst: :class:`~pvmismatch.pvmismatch_lib.pvconstants.PVconstants`
"""

_calc_now = False #: if True ``calcCells()`` is called in ``__setattr__``

def __init__(self, Rs=RS, Rsh=RSH, Isat1_T0=ISAT1_T0, Isat2=ISAT2,
Isc0_T0=ISC0_T0, aRBD=ARBD, bRBD=BRBD, VRBD=VRBD_,
nRBD=NRBD, Eg=EG, alpha_Isc=ALPHA_ISC,
Expand All @@ -69,6 +72,8 @@ def __init__(self, Rs=RS, Rsh=RSH, Isat1_T0=ISAT1_T0, Isat2=ISAT2,
self.Icell = None #: cell currents on IV curve [A]
self.Vcell = None #: cell voltages on IV curve [V]
self.Pcell = None #: cell power on IV curve [W]
# set calculation flag
self._calc_now = True # overwrites the class attribute

def __str__(self):
fmt = '<PVcell(Ee=%g[suns], Tcell=%g[K], Isc=%g[A], Voc=%g[V])>'
Expand All @@ -78,27 +83,28 @@ def __repr__(self):
return str(self)

def __setattr__(self, key, value):
# check for floats
try:
value = np.float64(value)
except (TypeError, ValueError):
pass
pass # fail silently if not float, eg: pvconst or _calc_now
super(PVcell, self).__setattr__(key, value)
# after all attributes have been initialized, recalculate IV curve
# every time __setattr__() is called
if hasattr(self, 'pvconst'):
# recalculate IV curve
if self._calc_now:
Icell, Vcell, Pcell = self.calcCell()
super(PVcell, self).__setattr__('Icell', Icell)
super(PVcell, self).__setattr__('Vcell', Vcell)
super(PVcell, self).__setattr__('Pcell', Pcell)
self.__dict__.update(Icell=Icell, Vcell=Vcell, Pcell=Pcell)

def update(self, **kwargs):
"""
Update user-defined constants.
"""
# TODO: use __dict__.update(), check for floats and update IV curve
# self.__dict__.update(kwargs)
# turn off calculation flag until all attributes are updated
self._calc_now = False
# don't use __dict__.update() instead use setattr() to go through
# custom __setattr__() so that numbers are cast to floats
for k, v in iteritems(kwargs):
setattr(self, k, v)
self._calc_now = True # recalculate

@property
def Vt(self):
Expand Down Expand Up @@ -276,4 +282,4 @@ def plot(self):
plt.xlim(0, self.Voc)
plt.ylim(0, (self.Isc + 1) * self.Voc)
plt.grid()
return cell_plot
return cell_plot
4 changes: 1 addition & 3 deletions pvmismatch/pvmismatch_lib/pvmodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,8 @@ def __init__(self, cell_pos=STD96, pvcells=None, pvconst=PVconstants(),
self.Vbypass = Vbypass #: [V] trigger voltage of bypass diode
self.cellArea = cellArea #: [cm^2] cell area
if pvcells is None:
# faster to use copy instead of making each object in a for-loop
# use copy instead of deepcopy to keep same pvconst for all objects
# PVcell.calcCell() creates new np.ndarray if attributes change
pvcells = PVcell(pvconst=self.pvconst)
# expand pvcells to list
if isinstance(pvcells, PVcell):
pvcells = [pvcells] * self.numberCells
if len(pvcells) != self.numberCells:
Expand Down
15 changes: 9 additions & 6 deletions pvmismatch/pvmismatch_lib/pvstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,21 @@ def __init__(self, numberMods=NUMBERMODS, pvmods=None,
self.pvconst = pvconst
self.numberMods = numberMods
if pvmods is None:
# use deepcopy instead of making each object in for-loop, 2x faster
pvmods = PVmodule(pvconst=self.pvconst)
# expand pvmods to list
if isinstance(pvmods, PVmodule):
pvmods = [pvmods] * self.numberMods
# reset pvconsts in all pvcells and pvmodules
for p in pvmods:
for c in p.pvcells:
c.pvconst = self.pvconst
p.pvconst = self.pvconst
if len(pvmods) != self.numberMods:
# TODO: use pvmismatch exceptions
raise Exception("Number of modules doesn't match.")
# check that pvconst if given, is the same for all cells
# don't assign pvcell.pvconst here since it triggers a recalc
for p in pvmods:
for c in p.pvcells:
if c.pvconst is not self.pvconst:
raise Exception('PVconstant must be the same for all cells')
if p.pvconst is not self.pvconst:
raise Exception('PVconstant must be the same for all cells')
self.pvmods = pvmods
self.Istring, self.Vstring, self.Pstring = self.calcString()

Expand Down
2 changes: 1 addition & 1 deletion pvmismatch/pvmismatch_lib/pvsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def __init__(self, pvconst=PVconstants(), numberStrs=NUMBERSTRS,
if pvstrs is None:
pvstrs = PVstring(numberMods=self.numberMods, pvmods=pvmods,
pvconst=self.pvconst)
# use deep copy instead of making each object in a for-loop
# expand pvstrs to list
if isinstance(pvstrs, PVstring):
pvstrs = [pvstrs] * self.numberStrs
if len(pvstrs) != self.numberStrs:
Expand Down
17 changes: 16 additions & 1 deletion pvmismatch/tests/test_pvcell.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ def test_pvcell_calc_rbd():
pvc2 = PVcell(bRBD=-0.056)
ok_(isinstance(pvc2, PVcell))



def test_pvcell_calc_now_flag():
pvc = PVcell()
itest, vtest, ptest = pvc.Icell, pvc.Vcell, pvc.Pcell
pvc._calc_now = False
pvc.Rs = 0.001
assert np.allclose(itest, pvc.Icell)
assert np.allclose(vtest, pvc.Vcell)
assert np.allclose(ptest, pvc.Pcell)
icell, vcell, pcell = pvc.calcCell()
pvc._calc_now = True
assert np.allclose(icell, pvc.Icell)
assert np.allclose(vcell, pvc.Vcell)
assert np.allclose(pcell, pvc.Pcell)


if __name__ == "__main__":
test_calc_series()

0 comments on commit c408b1e

Please sign in to comment.