Skip to content

Commit d6a2763

Browse files
committed
bump to v0.3 Proterozoic Eon
* update documents with new tests, fix unc_wrapper_args docs * add docs for unc_wrapper manually * fix test_solpos for list of datetimes * change some names: wrapper->wrapped_function unc_wrapper->wrapper g->f_ y->x_ gkwargs->kwargs_ * update history
1 parent 50bd714 commit d6a2763

File tree

4 files changed

+82
-30
lines changed

4 files changed

+82
-30
lines changed

README.rst

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,22 @@ History
2525
Releases are named after
2626
`geological eons, periods and epochs <https://en.wikipedia.org/wiki/Geologic_time_scale>`_.
2727

28+
`v0.3 <https://github.com/SunPower/UncertaintyWrapper/releases/tag/v0.3>`_ `Proterozoic Eon <https://en.wikipedia.org/wiki/Proterozoic>`_
29+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30+
31+
* new ``unc_wrapper_args()`` allows selection of independent variables that the
32+
partial derivatives are with respect to and also grouping those arguments
33+
together so that in the original function they can stay unpacked.
34+
* return values are grouped correctly so that they can remain unpacked in
35+
original function. These allow Uncertainty Wrapper to be used with
36+
`Pint's wrapper <http://pint.readthedocs.org/en/0.6/wrapping.html>`_
37+
* covariance now specified as dimensionaless fraction of square of arguments
38+
* more complex tests: IV curve and solar position (requires
39+
`NREL's solpos <http://rredc.nrel.gov/solar/codesandalgorithms/solpos/>`_)
40+
41+
2842
`v0.2.1 <https://github.com/SunPower/UncertaintyWrapper/releases/tag/v0.2>`_ `Eoarchean Era <https://en.wikipedia.org/wiki/Eoarchean>`_
29-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
43+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3044

3145
* update documentation
3246

uncertainty_wrapper/__init__.py

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
.. math::
66
7-
dF_{ij} = J_{ij} * S_{x_i}{x_j} * J_{ij}^{T}
7+
dF_{ij} = J_{ij} * S_{x_i, x_j} * J_{ij}^{T}
88
99
Diagonals of :math:`dF_{ij}` are standard deviations squared.
1010
@@ -19,8 +19,8 @@
1919
logging.basicConfig()
2020
LOGGER = logging.getLogger(__name__)
2121
LOGGER.setLevel(logging.DEBUG)
22-
__VERSION__ = '0.2.1'
23-
__RELEASE__ = u"Eoarchean Era"
22+
__VERSION__ = '0.3'
23+
__RELEASE__ = u"Proterozoic Eon"
2424
__URL__ = u'https://github.com/SunPower/UncertaintyWrapper'
2525
__AUTHOR__ = u"Mark Mikofski"
2626
__EMAIL__ = u'[email protected]'
@@ -109,16 +109,25 @@ def jflatten(j):
109109

110110

111111
def unc_wrapper_args(*covariance_keys):
112-
def unc_wrapper(f):
112+
"""
113+
Wrap function, pop ``__covariance__`` argument from keyword arguments,
114+
propagate uncertainty given covariance using Jacobian estimate and append
115+
calculated covariance and Jacobian matrices to return values. User supplied
116+
covariance keys can be any of the argument names used in the function. If
117+
empty then assume the arguments are already grouped. If ``None`` then use
118+
all of the arguments. See tests for examples.
119+
120+
:param covariance_keys: names of arguments that correspond to covariance
121+
:return: function value, covariance and Jacobian
122+
"""
123+
def wrapper(f):
113124
"""
114-
Wrap function, pop ``__covariance__`` argument from keyword arguments,
115-
propagate uncertainty given covariance using Jacobian estimate. and append
116-
calculated covariance and Jacobian matrices to return values.
125+
117126
"""
118127
argspec = inspect.getargspec(f)
119128

120129
@wraps(f)
121-
def wrapper(*args, **kwargs):
130+
def wrapped_function(*args, **kwargs):
122131
cov_keys = covariance_keys
123132
cov = kwargs.pop('__covariance__', None) # pop covariance
124133
if argspec.defaults is not None:
@@ -133,15 +142,15 @@ def wrapper(*args, **kwargs):
133142
else:
134143
x = kwargs.pop(argspec.args[0])
135144

136-
def g(y, **gkwargs):
145+
def f_(x_, **kwargs_):
137146
if cov_keys:
138-
gkwargs.update(zip(cov_keys, y))
139-
return np.array(f(**gkwargs))
147+
kwargs_.update(zip(cov_keys, x_))
148+
return np.array(f(**kwargs_))
140149
# assumes independent and dependent vars already grouped
141-
return f(y, **gkwargs)
150+
return f(x_, **kwargs_)
142151

143-
avg = g(x, **kwargs)
144-
jac = jacobian(g, x, **kwargs)
152+
avg = f_(x, **kwargs)
153+
jac = jacobian(f_, x, **kwargs)
145154
# covariance must account for all observations
146155
if cov is not None and cov.ndim == 3:
147156
# if covariance is an array of covariances, flatten it.
@@ -151,7 +160,8 @@ def g(y, **gkwargs):
151160
cov *= x.T.flatten() ** 2
152161
cov = np.dot(np.dot(jac, cov), jac.T)
153162
return avg, cov, jac
154-
return wrapper
155-
return unc_wrapper
163+
return wrapped_function
164+
return wrapper
156165

166+
# short cut for functions with arguments already grouped
157167
unc_wrapper = unc_wrapper_args()

uncertainty_wrapper/docs/api.rst

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,16 @@ Flatten Jacobian
3131
Wrapper
3232
~~~~~~~
3333

34-
.. autofunction:: unc_wrapper
34+
.. autofunction:: unc_wrapper_args
35+
36+
37+
Wrapper Shortcut
38+
````````````````
39+
40+
.. function:: unc_wrapper
41+
42+
This is basically :func:`unc_wrapper_args()` with no argument which assumes that
43+
all independent arguments are already grouped together.
3544

3645
Tests
3746
-----
@@ -42,3 +51,13 @@ Test Uncertainty Wrapper
4251
~~~~~~~~~~~~~~~~~~~~~~~~
4352

4453
.. autofunction:: test_unc_wrapper
54+
55+
Test IV curve
56+
~~~~~~~~~~~~~
57+
58+
.. autofunction:: test_IV
59+
60+
Test Solar Position
61+
~~~~~~~~~~~~~~~~~~~
62+
63+
.. autofunction:: test_solpos

uncertainty_wrapper/tests/__init__.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from uncertainty_wrapper import unc_wrapper, unc_wrapper_args
1010
import logging
1111
from scipy.constants import Boltzmann as KB, elementary_charge as QE
12-
from datetime import datetime
12+
from datetime import datetime, timedelta
1313
from solar_utils import *
1414
import pytz
1515

@@ -103,35 +103,44 @@ def Voc(x, E0=1000, T0=298.15, kB=KB, qe=QE):
103103

104104

105105
def test_IV():
106+
"""
107+
Test calculation of photovoltaic cell IV curve using 2-diode model.
108+
"""
106109
f = unc_wrapper(IV)
107110
return f(X, VD, __covariance__=COV)
108111

109112

110113
@unc_wrapper_args('lat', 'lon', 'press', 'tamb', 'seconds')
111-
def solar_position(lat, lon, press, tamb, dt, seconds=0):
114+
def solar_position(lat, lon, press, tamb, timestamps, seconds=0):
112115
"""
113116
calculate solar position
114117
"""
115118
seconds = np.sign(seconds) * np.ceil(np.abs(seconds))
116-
# seconds = np.where(x >0 0, np.ceil(seconds), np.floor(seconds))
117-
utcoffset = dt.utcoffset() or 0.0
118-
dst = dt.dst() or 0.0
119-
loc = [lat, lon, (utcoffset.total_seconds() - dst.total_seconds()) / 3600.0]
120-
naive = dt.replace(tzinfo=None)
121-
timestamps = np.datetime64(naive) + np.timedelta64(int(seconds * 1e6), 'us')
122-
timestamps = timestamps.reshape((-1,))
123-
ntimestamps = timestamps.size
119+
# seconds = np.where(x > 0, np.ceil(seconds), np.floor(seconds))
120+
try:
121+
ntimestamps = len(timestamps)
122+
except TypeError:
123+
ntimestamps = 1
124+
timestamps = [timestamps]
124125
an, am = np.zeros((ntimestamps, 2)), np.zeros((ntimestamps, 2))
125126
for n, ts in enumerate(timestamps):
126-
dt = ts.item().timetuple()[:6]
127-
LOGGER.debug('datetime: %r', datetime(*dt).strftime('%Y/%m/%d-%H:%M:%S.%f'))
127+
utcoffset = ts.utcoffset() or 0.0
128+
dst = ts.dst() or 0.0
129+
tz = (utcoffset.total_seconds() - dst.total_seconds()) / 3600.0
130+
loc = [lat, lon, tz]
131+
dt = ts + timedelta(seconds=seconds.item())
132+
dt = dt.timetuple()[:6]
133+
LOGGER.debug('datetime: %r', datetime(*dt).strftime('%Y/%m/%d-%H:%M:%S'))
128134
LOGGER.debug('lat: %f, lon: %f, tz: %d', *loc)
129135
LOGGER.debug('p = %f[mbar], T = %f[C]', press, tamb)
130136
an[n], am[n] = solposAM(loc, dt, [press, tamb])
131137
return an[:, 0], an[:, 1], am[:, 0], am[:, 1]
132138

133139

134140
def test_solpos():
141+
"""
142+
Test solar position calculation using NREL's SOLPOS.
143+
"""
135144
dt = PST.localize(datetime(2016, 4, 13, 12, 30, 0))
136145
return solar_position(37.405, -121.95, 1013.25, 20.0, dt,
137146
__covariance__=np.diag([0.0001] * 5))

0 commit comments

Comments
 (0)