|
4 | 4 |
|
5 | 5 | from nose.tools import ok_, eq_ |
6 | 6 | from carousel.core.calculations import Calc |
7 | | -from carousel.tests import PROJ_PATH |
| 7 | +from carousel.tests import PROJ_PATH, pvpower_models |
8 | 8 | import os |
| 9 | +import uncertainties |
| 10 | +from pvlib.solarposition import get_solarposition as solpos |
| 11 | +import logging |
| 12 | +import numpy as np |
| 13 | + |
| 14 | +LOGGER = logging.getLogger(__name__) |
9 | 15 |
|
10 | 16 |
|
11 | 17 | def test_calc_metaclass(): |
@@ -57,3 +63,57 @@ class CalcTest2(Calc): |
57 | 63 | ok_(isinstance(calc_test2, Calc)) |
58 | 64 | for k, v in calc_test2.parameters.iteritems(): |
59 | 65 | eq_(calc_test1.parameters[k], v) |
| 66 | + |
| 67 | + |
| 68 | +def test_static_calc_unc(): |
| 69 | + """ |
| 70 | + Test uncertainty propagation in static calculations using Uncertainties. |
| 71 | + """ |
| 72 | + |
| 73 | + # FIXME: this shouldn't have to run a model to test the uncertainty |
| 74 | + test_model_file = os.path.join(PROJ_PATH, 'models', |
| 75 | + 'sandia_performance_model-Tuscon.json') |
| 76 | + test_model = pvpower_models.SAPM(test_model_file) # create model |
| 77 | + test_model.command('start') # start simulation |
| 78 | + # get parameters from model |
| 79 | + dt = test_model.outputs.reg['timestamps'] # timestamps |
| 80 | + latitude = test_model.data.reg['latitude'].m # latitude [degrees] |
| 81 | + longitude = test_model.data.reg['longitude'].m # longitude [degrees] |
| 82 | + zenith = test_model.outputs.reg['solar_zenith'].m # zenith [degrees] |
| 83 | + s_ze_ze = test_model.outputs.reg.variance['solar_zenith']['solar_zenith'] |
| 84 | + azimuth = test_model.outputs.reg['solar_azimuth'].m # azimuth [degrees] |
| 85 | + s_az_az = test_model.outputs.reg.variance['solar_azimuth']['solar_azimuth'] |
| 86 | + # get uncertainties percentages in base units |
| 87 | + lat_unc = test_model.data.reg.uncertainty['latitude']['latitude'] |
| 88 | + lat_unc = lat_unc.to_base_units().m |
| 89 | + lon_unc = test_model.data.reg.uncertainty['longitude']['longitude'] |
| 90 | + lon_unc = lon_unc.to_base_units().m |
| 91 | + # create ufloat Uncertainties from parameters |
| 92 | + lat_unc = uncertainties.ufloat(latitude, np.abs(latitude * lat_unc)) |
| 93 | + lon_unc = uncertainties.ufloat(longitude, np.abs(longitude * lon_unc)) |
| 94 | + test_unc = [] # empty list to collect return values |
| 95 | + for n in xrange(96): |
| 96 | + # Uncertainties wrapped functions must return only scalar float |
| 97 | + f_ze_unc = uncertainties.wrap( |
| 98 | + lambda lat, lon: solpos(dt[n], lat, lon)['apparent_zenith'].item() |
| 99 | + ) |
| 100 | + f_az_unc = uncertainties.wrap( |
| 101 | + lambda lat, lon: solpos(dt[n], lat, lon)['azimuth'].item() |
| 102 | + ) |
| 103 | + ze_unc, az_unc = f_ze_unc(lat_unc, lon_unc), f_az_unc(lat_unc, lon_unc) |
| 104 | + LOGGER.debug( |
| 105 | + '%s: ze = %g +/- %g%%, az = %g +/- %g%%', dt[n].isoformat(), |
| 106 | + zenith[n], np.sqrt(s_ze_ze[n]) * 100, |
| 107 | + azimuth[n], np.sqrt(s_az_az[n]) * 100 |
| 108 | + ) |
| 109 | + LOGGER.debug( |
| 110 | + 'Uncertainties test %2d: ze = %g +/- %g%%, az = %g +/- %g%%', n, |
| 111 | + ze_unc.n, ze_unc.s / ze_unc.n * 100, |
| 112 | + az_unc.n, az_unc.s / az_unc.n * 100 |
| 113 | + ) |
| 114 | + assert np.isclose(zenith[n], ze_unc.n) |
| 115 | + assert np.isclose(np.sqrt(s_ze_ze[n]), ze_unc.s / ze_unc.n) |
| 116 | + assert np.isclose(azimuth[n], az_unc.n) |
| 117 | + assert np.isclose(np.sqrt(s_az_az[n]), az_unc.s / az_unc.n) |
| 118 | + test_unc.append({'ze': ze_unc, 'az': az_unc}) |
| 119 | + return test_model, test_unc |
0 commit comments