def test_analytical_azimuth(): times = pd.DatetimeIndex(start="1/1/2015 0:00", end="12/31/2015 23:00", freq="H").tz_localize('Etc/GMT+8') lat, lon = 37.8, -122.25 lat_rad = np.deg2rad(lat) output = solarposition.spa_python(times, lat, lon, 100) solar_azimuth = np.deg2rad(output['azimuth']) # spa solar_zenith = np.deg2rad(output['zenith']) # spencer eot = solarposition.equation_of_time_spencer71(times.dayofyear) hour_angle = np.deg2rad(solarposition.hour_angle(times, lon, eot)) decl = solarposition.declination_spencer71(times.dayofyear) zenith = solarposition.solar_zenith_analytical(lat_rad, hour_angle, decl) azimuth_1 = solarposition.solar_azimuth_analytical(lat_rad, hour_angle, decl, zenith) # pvcdrom and cooper eot = solarposition.equation_of_time_pvcdrom(times.dayofyear) hour_angle = np.deg2rad(solarposition.hour_angle(times, lon, eot)) decl = solarposition.declination_cooper69(times.dayofyear) zenith = solarposition.solar_zenith_analytical(lat_rad, hour_angle, decl) azimuth_2 = solarposition.solar_azimuth_analytical(lat_rad, hour_angle, decl, zenith) idx = np.where(solar_zenith < np.pi/2) assert np.allclose(azimuth_1[idx], solar_azimuth.as_matrix()[idx], atol=0.01) assert np.allclose(azimuth_2[idx], solar_azimuth.as_matrix()[idx], atol=0.017)
def time_sun_rise_set_transit_geometric_full_comparison(self, ndays): dayofyear = self.times_daily.dayofyear declination = solarposition.declination_spencer71(dayofyear) equation_of_time = solarposition.equation_of_time_spencer71(dayofyear) solarposition.sun_rise_set_transit_geometric( self.times_daily, self.lat, self.lon, declination, equation_of_time)
def test_equation_of_time(): times = pd.DatetimeIndex(start="1/1/2015 0:00", end="12/31/2015 23:00", freq="H") output = solarposition.spa_python(times, 37.8, -122.25, 100) eot = output['equation_of_time'] eot_rng = eot.max() - eot.min() # range of values, around 30 minutes eot_1 = solarposition.equation_of_time_spencer71(times.dayofyear) eot_2 = solarposition.equation_of_time_pvcdrom(times.dayofyear) assert np.allclose(eot_1 / eot_rng, eot / eot_rng, atol=0.3) # spencer assert np.allclose(eot_2 / eot_rng, eot / eot_rng, atol=0.4) # pvcdrom
def test_analytical_azimuth(): times = pd.DatetimeIndex(start="1/1/2015 0:00", end="12/31/2015 23:00", freq="H").tz_localize('Etc/GMT+8') lat, lon = 37.8, -122.25 lat_rad = np.deg2rad(lat) output = solarposition.spa_python(times, lat, lon, 100) solar_azimuth = np.deg2rad(output['azimuth']) # spa solar_zenith = np.deg2rad(output['zenith']) # spencer eot = solarposition.equation_of_time_spencer71(times.dayofyear) hour_angle = np.deg2rad(solarposition.hour_angle(times, lon, eot)) decl = solarposition.declination_spencer71(times.dayofyear) zenith = solarposition.solar_zenith_analytical(lat_rad, hour_angle, decl) azimuth_1 = solarposition.solar_azimuth_analytical(lat_rad, hour_angle, decl, zenith) # pvcdrom and cooper eot = solarposition.equation_of_time_pvcdrom(times.dayofyear) hour_angle = np.deg2rad(solarposition.hour_angle(times, lon, eot)) decl = solarposition.declination_cooper69(times.dayofyear) zenith = solarposition.solar_zenith_analytical(lat_rad, hour_angle, decl) azimuth_2 = solarposition.solar_azimuth_analytical(lat_rad, hour_angle, decl, zenith) idx = np.where(solar_zenith < np.pi/2) assert np.allclose(azimuth_1[idx], solar_azimuth.as_matrix()[idx], atol=0.01) assert np.allclose(azimuth_2[idx], solar_azimuth.as_matrix()[idx], atol=0.017) # test for NaN values at boundary conditions (PR #431) test_angles = np.radians(np.array( [[ 0., -180., -20.], [ 0., 0., -5.], [ 0., 0., 0.], [ 0., 0., 15.], [ 0., 180., 20.], [ 30., 0., -20.], [ 30., 0., -5.], [ 30., 0., 0.], [ 30., 180., 5.], [ 30., 0., 10.], [ -30., 0., -20.], [ -30., 0., -15.], [ -30., 0., 0.], [ -30., -180., 5.], [ -30., 180., 10.]])) zeniths = solarposition.solar_zenith_analytical(*test_angles.T) azimuths = solarposition.solar_azimuth_analytical(*test_angles.T, zenith=zeniths) assert not np.isnan(azimuths).any()
def test_analytical_azimuth(): times = pd.DatetimeIndex(start="1/1/2015 0:00", end="12/31/2015 23:00", freq="H").tz_localize('Etc/GMT+8') lat, lon = 37.8, -122.25 lat_rad = np.deg2rad(lat) output = solarposition.spa_python(times, lat, lon, 100) solar_azimuth = np.deg2rad(output['azimuth']) # spa solar_zenith = np.deg2rad(output['zenith']) # spencer eot = solarposition.equation_of_time_spencer71(times.dayofyear) hour_angle = np.deg2rad(solarposition.hour_angle(times, lon, eot)) decl = solarposition.declination_spencer71(times.dayofyear) zenith = solarposition.solar_zenith_analytical(lat_rad, hour_angle, decl) azimuth_1 = solarposition.solar_azimuth_analytical(lat_rad, hour_angle, decl, zenith) # pvcdrom and cooper eot = solarposition.equation_of_time_pvcdrom(times.dayofyear) hour_angle = np.deg2rad(solarposition.hour_angle(times, lon, eot)) decl = solarposition.declination_cooper69(times.dayofyear) zenith = solarposition.solar_zenith_analytical(lat_rad, hour_angle, decl) azimuth_2 = solarposition.solar_azimuth_analytical(lat_rad, hour_angle, decl, zenith) idx = np.where(solar_zenith < np.pi/2) assert np.allclose(azimuth_1[idx], solar_azimuth.values[idx], atol=0.01) assert np.allclose(azimuth_2[idx], solar_azimuth.values[idx], atol=0.017) # test for NaN values at boundary conditions (PR #431) test_angles = np.radians(np.array( [[ 0., -180., -20.], [ 0., 0., -5.], [ 0., 0., 0.], [ 0., 0., 15.], [ 0., 180., 20.], [ 30., 0., -20.], [ 30., 0., -5.], [ 30., 0., 0.], [ 30., 180., 5.], [ 30., 0., 10.], [ -30., 0., -20.], [ -30., 0., -15.], [ -30., 0., 0.], [ -30., -180., 5.], [ -30., 180., 10.]])) zeniths = solarposition.solar_zenith_analytical(*test_angles.T) azimuths = solarposition.solar_azimuth_analytical(*test_angles.T, zenith=zeniths) assert not np.isnan(azimuths).any()
def test_sun_rise_set_transit_geometric(expected_rise_set_spa, golden_mst): """Test geometric calculations for sunrise, sunset, and transit times""" times = expected_rise_set_spa.index latitude = golden_mst.latitude longitude = golden_mst.longitude eot = solarposition.equation_of_time_spencer71(times.dayofyear) # minutes decl = solarposition.declination_spencer71(times.dayofyear) # radians sr, ss, st = solarposition.sun_rise_set_transit_geometric( times, latitude=latitude, longitude=longitude, declination=decl, equation_of_time=eot) # sunrise: 2015-01-02 07:26:39.763224487, 2015-08-02 05:04:35.688533801 # sunset: 2015-01-02 16:41:29.951096777, 2015-08-02 19:09:46.597355085 # transit: 2015-01-02 12:04:04.857160632, 2015-08-02 12:07:11.142944443 test_sunrise = solarposition._times_to_hours_after_local_midnight(sr) test_sunset = solarposition._times_to_hours_after_local_midnight(ss) test_transit = solarposition._times_to_hours_after_local_midnight(st) # convert expected SPA sunrise, sunset, transit to local datetime indices expected_sunrise = pd.DatetimeIndex(expected_rise_set_spa.sunrise.values, tz='UTC').tz_convert(golden_mst.tz) expected_sunset = pd.DatetimeIndex(expected_rise_set_spa.sunset.values, tz='UTC').tz_convert(golden_mst.tz) expected_transit = pd.DatetimeIndex(expected_rise_set_spa.transit.values, tz='UTC').tz_convert(golden_mst.tz) # convert expected times to hours since midnight as arrays of floats expected_sunrise = solarposition._times_to_hours_after_local_midnight( expected_sunrise) expected_sunset = solarposition._times_to_hours_after_local_midnight( expected_sunset) expected_transit = solarposition._times_to_hours_after_local_midnight( expected_transit) # geometric time has about 4-6 minute error compared to SPA sunset/sunrise expected_sunrise_error = np.array( [0.07910089555555544, 0.06908014805555496]) # 4.8[min], 4.2[min] expected_sunset_error = np.array( [-0.1036246955555562, -0.06983406805555603]) # -6.2[min], -4.2[min] expected_transit_error = np.array( [-0.011150788888889096, 0.0036508177777765383]) # -40[sec], 13.3[sec] assert np.allclose(test_sunrise, expected_sunrise, atol=np.abs(expected_sunrise_error).max()) assert np.allclose(test_sunset, expected_sunset, atol=np.abs(expected_sunset_error).max()) assert np.allclose(test_transit, expected_transit, atol=np.abs(expected_transit_error).max())
def test_get_sun_rise_set_transit(golden): times = pd.DatetimeIndex(['2015-01-01 07:00:00', '2015-01-01 23:00:00'], tz='MST') result = golden.get_sun_rise_set_transit(times, method='pyephem') assert all(result.columns == ['sunrise', 'sunset', 'transit']) result = golden.get_sun_rise_set_transit(times, method='spa') assert all(result.columns == ['sunrise', 'sunset', 'transit']) dayofyear = 1 declination = declination_spencer71(dayofyear) eot = equation_of_time_spencer71(dayofyear) result = golden.get_sun_rise_set_transit(times, method='geometric', declination=declination, equation_of_time=eot) assert all(result.columns == ['sunrise', 'sunset', 'transit'])
def test_analytical_zenith(): times = pd.date_range(start="1/1/2015 0:00", end="12/31/2015 23:00", freq="H").tz_localize('Etc/GMT+8') lat, lon = 37.8, -122.25 lat_rad = np.deg2rad(lat) output = solarposition.spa_python(times, lat, lon, 100) solar_zenith = np.deg2rad(output['zenith']) # spa # spencer eot = solarposition.equation_of_time_spencer71(times.dayofyear) hour_angle = np.deg2rad(solarposition.hour_angle(times, lon, eot)) decl = solarposition.declination_spencer71(times.dayofyear) zenith_1 = solarposition.solar_zenith_analytical(lat_rad, hour_angle, decl) # pvcdrom and cooper eot = solarposition.equation_of_time_pvcdrom(times.dayofyear) hour_angle = np.deg2rad(solarposition.hour_angle(times, lon, eot)) decl = solarposition.declination_cooper69(times.dayofyear) zenith_2 = solarposition.solar_zenith_analytical(lat_rad, hour_angle, decl) assert np.allclose(zenith_1, solar_zenith, atol=0.015) assert np.allclose(zenith_2, solar_zenith, atol=0.025)
def test_bird(): """Test Bird/Hulstrom Clearsky Model""" times = pd.date_range(start='1/1/2015 0:00', end='12/31/2015 23:00', freq='H') tz = -7 # test timezone gmt_tz = pytz.timezone('Etc/GMT%+d' % -(tz)) times = times.tz_localize(gmt_tz) # set timezone # match test data from BIRD_08_16_2012.xls latitude = 40. longitude = -105. press_mB = 840. o3_cm = 0.3 h2o_cm = 1.5 aod_500nm = 0.1 aod_380nm = 0.15 b_a = 0.85 alb = 0.2 eot = solarposition.equation_of_time_spencer71(times.dayofyear) hour_angle = solarposition.hour_angle(times, longitude, eot) - 0.5 * 15. declination = solarposition.declination_spencer71(times.dayofyear) zenith = solarposition.solar_zenith_analytical( np.deg2rad(latitude), np.deg2rad(hour_angle), declination ) zenith = np.rad2deg(zenith) airmass = atmosphere.get_relative_airmass(zenith, model='kasten1966') etr = irradiance.get_extra_radiation(times) # test Bird with time series data field_names = ('dni', 'direct_horizontal', 'ghi', 'dhi') irrads = clearsky.bird( zenith, airmass, aod_380nm, aod_500nm, h2o_cm, o3_cm, press_mB * 100., etr, b_a, alb ) Eb, Ebh, Gh, Dh = (irrads[_] for _ in field_names) clearsky_path = os.path.dirname(os.path.abspath(__file__)) pvlib_path = os.path.dirname(clearsky_path) data_path = os.path.join(pvlib_path, 'data', 'BIRD_08_16_2012.csv') testdata = pd.read_csv(data_path, usecols=range(1, 26), header=1).dropna() testdata.index = times[1:48] assert np.allclose(testdata['DEC'], np.rad2deg(declination[1:48])) assert np.allclose(testdata['EQT'], eot[1:48], rtol=1e-4) assert np.allclose(testdata['Hour Angle'], hour_angle[1:48]) assert np.allclose(testdata['Zenith Ang'], zenith[1:48]) dawn = zenith < 88. dusk = testdata['Zenith Ang'] < 88. am = pd.Series(np.where(dawn, airmass, 0.), index=times).fillna(0.0) assert np.allclose( testdata['Air Mass'].where(dusk, 0.), am[1:48], rtol=1e-3 ) direct_beam = pd.Series(np.where(dawn, Eb, 0.), index=times).fillna(0.) assert np.allclose( testdata['Direct Beam'].where(dusk, 0.), direct_beam[1:48], rtol=1e-3 ) direct_horz = pd.Series(np.where(dawn, Ebh, 0.), index=times).fillna(0.) assert np.allclose( testdata['Direct Hz'].where(dusk, 0.), direct_horz[1:48], rtol=1e-3 ) global_horz = pd.Series(np.where(dawn, Gh, 0.), index=times).fillna(0.) assert np.allclose( testdata['Global Hz'].where(dusk, 0.), global_horz[1:48], rtol=1e-3 ) diffuse_horz = pd.Series(np.where(dawn, Dh, 0.), index=times).fillna(0.) assert np.allclose( testdata['Dif Hz'].where(dusk, 0.), diffuse_horz[1:48], rtol=1e-3 ) # test keyword parameters irrads2 = clearsky.bird( zenith, airmass, aod_380nm, aod_500nm, h2o_cm, dni_extra=etr ) Eb2, Ebh2, Gh2, Dh2 = (irrads2[_] for _ in field_names) clearsky_path = os.path.dirname(os.path.abspath(__file__)) pvlib_path = os.path.dirname(clearsky_path) data_path = os.path.join(pvlib_path, 'data', 'BIRD_08_16_2012_patm.csv') testdata2 = pd.read_csv(data_path, usecols=range(1, 26), header=1).dropna() testdata2.index = times[1:48] direct_beam2 = pd.Series(np.where(dawn, Eb2, 0.), index=times).fillna(0.) assert np.allclose( testdata2['Direct Beam'].where(dusk, 0.), direct_beam2[1:48], rtol=1e-3 ) direct_horz2 = pd.Series(np.where(dawn, Ebh2, 0.), index=times).fillna(0.) assert np.allclose( testdata2['Direct Hz'].where(dusk, 0.), direct_horz2[1:48], rtol=1e-3 ) global_horz2 = pd.Series(np.where(dawn, Gh2, 0.), index=times).fillna(0.) assert np.allclose( testdata2['Global Hz'].where(dusk, 0.), global_horz2[1:48], rtol=1e-3 ) diffuse_horz2 = pd.Series(np.where(dawn, Dh2, 0.), index=times).fillna(0.) assert np.allclose( testdata2['Dif Hz'].where(dusk, 0.), diffuse_horz2[1:48], rtol=1e-3 ) # test scalars just at noon # XXX: calculations start at 12am so noon is at index = 12 irrads3 = clearsky.bird( zenith[12], airmass[12], aod_380nm, aod_500nm, h2o_cm, dni_extra=etr[12] ) Eb3, Ebh3, Gh3, Dh3 = (irrads3[_] for _ in field_names) # XXX: testdata starts at 1am so noon is at index = 11 np.allclose( [Eb3, Ebh3, Gh3, Dh3], testdata2[['Direct Beam', 'Direct Hz', 'Global Hz', 'Dif Hz']].iloc[11], rtol=1e-3) return pd.DataFrame({'Eb': Eb, 'Ebh': Ebh, 'Gh': Gh, 'Dh': Dh}, index=times)
def test_bird(): """Test Bird/Hulstrom Clearsky Model""" times = pd.date_range(start='1/1/2015 0:00', end='12/31/2015 23:00', freq='H') tz = -7 # test timezone gmt_tz = pytz.timezone('Etc/GMT%+d' % -(tz)) times = times.tz_localize(gmt_tz) # set timezone # match test data from BIRD_08_16_2012.xls latitude = 40. longitude = -105. press_mB = 840. o3_cm = 0.3 h2o_cm = 1.5 aod_500nm = 0.1 aod_380nm = 0.15 b_a = 0.85 alb = 0.2 eot = solarposition.equation_of_time_spencer71(times.dayofyear) hour_angle = solarposition.hour_angle(times, longitude, eot) - 0.5 * 15. declination = solarposition.declination_spencer71(times.dayofyear) zenith = solarposition.solar_zenith_analytical( np.deg2rad(latitude), np.deg2rad(hour_angle), declination ) zenith = np.rad2deg(zenith) airmass = atmosphere.get_relative_airmass(zenith, model='kasten1966') etr = irradiance.get_extra_radiation(times) # test Bird with time series data field_names = ('dni', 'direct_horizontal', 'ghi', 'dhi') irrads = clearsky.bird( zenith, airmass, aod_380nm, aod_500nm, h2o_cm, o3_cm, press_mB * 100., etr, b_a, alb ) Eb, Ebh, Gh, Dh = (irrads[_] for _ in field_names) data_path = DATA_DIR / 'BIRD_08_16_2012.csv' testdata = pd.read_csv(data_path, usecols=range(1, 26), header=1).dropna() testdata.index = times[1:48] assert np.allclose(testdata['DEC'], np.rad2deg(declination[1:48])) assert np.allclose(testdata['EQT'], eot[1:48], rtol=1e-4) assert np.allclose(testdata['Hour Angle'], hour_angle[1:48]) assert np.allclose(testdata['Zenith Ang'], zenith[1:48]) dawn = zenith < 88. dusk = testdata['Zenith Ang'] < 88. am = pd.Series(np.where(dawn, airmass, 0.), index=times).fillna(0.0) assert np.allclose( testdata['Air Mass'].where(dusk, 0.), am[1:48], rtol=1e-3 ) direct_beam = pd.Series(np.where(dawn, Eb, 0.), index=times).fillna(0.) assert np.allclose( testdata['Direct Beam'].where(dusk, 0.), direct_beam[1:48], rtol=1e-3 ) direct_horz = pd.Series(np.where(dawn, Ebh, 0.), index=times).fillna(0.) assert np.allclose( testdata['Direct Hz'].where(dusk, 0.), direct_horz[1:48], rtol=1e-3 ) global_horz = pd.Series(np.where(dawn, Gh, 0.), index=times).fillna(0.) assert np.allclose( testdata['Global Hz'].where(dusk, 0.), global_horz[1:48], rtol=1e-3 ) diffuse_horz = pd.Series(np.where(dawn, Dh, 0.), index=times).fillna(0.) assert np.allclose( testdata['Dif Hz'].where(dusk, 0.), diffuse_horz[1:48], rtol=1e-3 ) # test keyword parameters irrads2 = clearsky.bird( zenith, airmass, aod_380nm, aod_500nm, h2o_cm, dni_extra=etr ) Eb2, Ebh2, Gh2, Dh2 = (irrads2[_] for _ in field_names) data_path = DATA_DIR / 'BIRD_08_16_2012_patm.csv' testdata2 = pd.read_csv(data_path, usecols=range(1, 26), header=1).dropna() testdata2.index = times[1:48] direct_beam2 = pd.Series(np.where(dawn, Eb2, 0.), index=times).fillna(0.) assert np.allclose( testdata2['Direct Beam'].where(dusk, 0.), direct_beam2[1:48], rtol=1e-3 ) direct_horz2 = pd.Series(np.where(dawn, Ebh2, 0.), index=times).fillna(0.) assert np.allclose( testdata2['Direct Hz'].where(dusk, 0.), direct_horz2[1:48], rtol=1e-3 ) global_horz2 = pd.Series(np.where(dawn, Gh2, 0.), index=times).fillna(0.) assert np.allclose( testdata2['Global Hz'].where(dusk, 0.), global_horz2[1:48], rtol=1e-3 ) diffuse_horz2 = pd.Series(np.where(dawn, Dh2, 0.), index=times).fillna(0.) assert np.allclose( testdata2['Dif Hz'].where(dusk, 0.), diffuse_horz2[1:48], rtol=1e-3 ) # test scalars just at noon # XXX: calculations start at 12am so noon is at index = 12 irrads3 = clearsky.bird( zenith[12], airmass[12], aod_380nm, aod_500nm, h2o_cm, dni_extra=etr[12] ) Eb3, Ebh3, Gh3, Dh3 = (irrads3[_] for _ in field_names) # XXX: testdata starts at 1am so noon is at index = 11 np.allclose( [Eb3, Ebh3, Gh3, Dh3], testdata2[['Direct Beam', 'Direct Hz', 'Global Hz', 'Dif Hz']].iloc[11], rtol=1e-3) return pd.DataFrame({'Eb': Eb, 'Ebh': Ebh, 'Gh': Gh, 'Dh': Dh}, index=times)
# note: .dll extension is not needed assy = clr.AddReference(str(src)) from clr import pv lat, lon = 37.81, -122.25 tz = -8.0 dates = ["19900101T12:30:00", "19900102T12:30:00", "19900103T12:30:00", "19900104T12:30:00"] print('Solar Position') sp = pv.SolarPosition(dates, lat, lon, tz) print('Day Angle, offset=1') da = sp.CalcSimpleDayAngleArray() eot = sp.EquationOfTimeSpencer71(da) print('Equation of time, Spencer (1971)') for doy in range(4): print(f'{doy+1:d} --> {eot[doy]:g}') doy = np.arange(4) + 1 eot_pvcdrom = equation_of_time_pvcdrom(doy) eot_test = equation_of_time_spencer71(doy) assert np.allclose([_ for _ in eot], eot_test) decl = declination_spencer71(doy) decl_cooper = declination_cooper69(doy) ts = pd.DatetimeIndex(dates, tz=f'Etc/GMT{int(tz):+d}') ha = hour_angle(ts, lon, eot_test) sp_test = get_solarposition(ts, latitude=lat, longitude=lon) ze = solar_zenith_analytical(37.81*np.pi/180.0, ha*np.pi/180.0, decl)*180/np.pi