Please read my disclaimer.

I'm proud to announce UncertaintyWrapper at the Cheese Shop. This work was supported by my employer, SunPower Corp. and is currently offered with a standard 3-clause BSD license. The documentation, source code and releases are also available our SunPower org GitHub page.

So what does `uncertainty_wrapper`

do? Let's say you have a Python function, to calculate solar position, and the function uses a C/C++ library via the Python `ctypes`

library. Or maybe you just have a really complicated set of calculations that you repeat 8760 times, and you want it to run super fast, so you don't want it to calculate derivatives and uncertainty at every internal step, just the final output. Oh and by the way, you want all 8760 calculations vectorized, _ie_: done concurrently as much as possible.

Heres an example using PVLIB of just the first 24 hours.

# import numpy as np # v1.11.0 import pandas as pd # v0.18.0 import pytz # v2016.1 import pvlib # v0.2.2 from uncertainty_wrapper import unc_wrapper_args # v0.3.1 PST = pytz.timezone('US/Pacific') # Pacific Standard Time times = pd.DatetimeIndex(start='2015/1/1', end='2015/1/2', freq='1h', tz=PST) # date range # repeat arguments for the number of observations latitude, longitude, pressure, altitude, temperature = [np.repeat(x, times.size) for x in (37., -122., 101325., 0., 22.)] # standard deviation of 1% assuming normal distribution covariance = np.tile(np.diag([0.0001] * 5), (times.size, 1, 1)) # tile this for the number of observations @unc_wrapper_args(1, 2, 3, 4, 5) # indices specify positions of independent variables: # 1: latitude, 2: longitude, 3: pressure, 4: altitude, 5: temperature def spa(times, latitude, longitude, pressure, altitude, temperature): location = pvlib.location.Location(latitude[0], longitude[0], PST, altitude=altitude[0]) dataframe = pvlib.solarposition.spa_c(times, location, pressure[0], temperature[0]) retvals = dataframe.to_records() zenith = retvals['apparent_zenith'] zenith = np.where(zenith<90, zenith, np.nan) azimuth = retvals['azimuth'] return zenith, azimuth ze, az, cov, jac = spa(times, latitude, longitude, pressure, altitude, temperature, __covariance__=covariance) df = pd.DataFrame({'zenith': ze, 'az': az}, index=times) # easier to view as dataframe print df # az zenith # 2015-01-01 00:00:00-08:00 349.297715 NaN # 2015-01-01 01:00:00-08:00 40.210628 NaN # 2015-01-01 02:00:00-08:00 66.719304 NaN # 2015-01-01 03:00:00-08:00 80.930185 NaN # 2015-01-01 04:00:00-08:00 90.852887 NaN # 2015-01-01 05:00:00-08:00 99.212426 NaN # 2015-01-01 06:00:00-08:00 107.181217 NaN # 2015-01-01 07:00:00-08:00 115.450451 NaN # 2015-01-01 08:00:00-08:00 124.564183 84.113440 # 2015-01-01 09:00:00-08:00 135.023137 74.984664 # 2015-01-01 10:00:00-08:00 147.247403 67.475783 # 2015-01-01 11:00:00-08:00 161.371578 62.273878 # 2015-01-01 12:00:00-08:00 176.922804 60.008978 # 2015-01-01 13:00:00-08:00 192.742327 61.017538 # 2015-01-01 14:00:00-08:00 207.519768 65.144340 # 2015-01-01 15:00:00-08:00 220.494108 71.839001 # 2015-01-01 16:00:00-08:00 231.600910 80.422988 # 2015-01-01 17:00:00-08:00 241.184075 89.948123 # 2015-01-01 18:00:00-08:00 249.726361 NaN # 2015-01-01 19:00:00-08:00 257.751550 NaN # 2015-01-01 20:00:00-08:00 265.873170 NaN # 2015-01-01 21:00:00-08:00 275.014534 NaN # 2015-01-01 22:00:00-08:00 287.078877 NaN # 2015-01-01 23:00:00-08:00 307.283646 NaN # 2015-01-02 00:00:00-08:00 348.921385 NaN # covariance at 8AM idx = 8 print times[idx] # Timestamp('2015-01-01 08:00:00-0800', tz='US/Pacific', offset='H') nf = 2 # number of dependent variables: [ze, az] print cov[(nf * idx):(nf * (idx + 1)), (nf * idx):(nf * (idx + 1))] # [[ 0.6617299 -0.6152971 ] # [-0.6152971 0.62483904]] # standard deviation print np.sqrt(cov[(nf * idx), (nf * idx)]) / ze[idx] # 0.0096710802029002577 # Jacobian at 9AM nargs = 5 # number of independent args print jac[nf*(idx-1):nf*idx, nargs*(idx-1):nargs*idx] # [[ 5.56456716e-01 -6.45065654e-01 -1.37538277e-06 0.00000000e+00 4.72409055e-04] # [ 8.29163154e-02 6.47436098e-01 0.00000000e+00 0.00000000e+00 0.00000000e+00]] #

First this tells us that the standard deviation of the zenith is 1% if the input has a standard deviation of 1%. That's reasonable. This also tells that zenith is more sensitive to latitude and longitude than pressure or temperature and more sensitive to latitude than azimuth is.