def test_disc_min_cos_zenith_max_zenith(): # map out behavior under difficult conditions with various # limiting kwargs settings columns = ['dni', 'kt', 'airmass'] times = pd.DatetimeIndex(['2016-07-19 06:11:00'], tz='America/Phoenix') out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times) expected = pd.DataFrame(np.array( [[0.00000000e+00, 1.16046346e-02, 3.63954476e+01]]), columns=columns, index=times) assert_frame_equal(out, expected) out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, min_cos_zenith=0) expected = pd.DataFrame(np.array( [[0.00000000e+00, 1.0, 3.63954476e+01]]), columns=columns, index=times) assert_frame_equal(out, expected) out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, max_zenith=100) expected = pd.DataFrame(np.array( [[6.68577449e+03, 1.16046346e-02, 3.63954476e+01]]), columns=columns, index=times) assert_frame_equal(out, expected) out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, min_cos_zenith=0, max_zenith=100) expected = pd.DataFrame(np.array( [[7.21238390e+03, 1.00000000e+00, 3.63954476e+01]]), columns=columns, index=times) assert_frame_equal(out, expected)
def test_disc_keys(): clearsky_data = clearsky.ineichen(times, tus, linke_turbidity=3) disc_data = irradiance.disc(clearsky_data['ghi'], ephem_data['zenith'], ephem_data.index) assert 'dni' in disc_data.columns assert 'kt' in disc_data.columns assert 'airmass' in disc_data.columns
def apply_decomposition_model(weather_df, model, location): """ Uses the specified decomposition model to calculate DNI and DHI. Parameters ---------- weather_df : :pandas:`DataFrame` Weather DataFrame containing all variables needed to apply the decomposition model. See model functions for more information. model : :obj:`str` Decomposition model to use. Choose from 'reindl', 'erbs' or 'disc'. location : :pvlib:`Location` Returns ------- :pandas:`DataFrame` DataFrame with DNI and DHI. """ solar_position = location.get_solarposition( weather_df.index, pressure=weather_df['pressure'].mean(), temperature=weather_df['temp_air'].mean()) if model == 'reindl': solar_position = location.get_solarposition( weather_df.index, pressure=weather_df['pressure'].mean(), temperature=weather_df['temp_air'].mean()) df = reindl(weather_df.ghi, weather_df.i0_h, solar_position.elevation) df['dni_corrected'] = irradiance.dni( weather_df['ghi'], df['dhi'], solar_position.zenith, clearsky_dni=location.get_clearsky( weather_df.index, solar_position=solar_position).dni, clearsky_tolerance=1.1, zenith_threshold_for_zero_dni=88.0, zenith_threshold_for_clearsky_limit=80.0) elif model == 'erbs': df = irradiance.erbs(weather_df.ghi, solar_position.zenith, weather_df.index) df['dni_corrected'] = irradiance.dni( weather_df['ghi'], df['dhi'], solar_position.zenith, clearsky_dni=location.get_clearsky( weather_df.index, solar_position=solar_position).dni, clearsky_tolerance=1.1, zenith_threshold_for_zero_dni=88.0, zenith_threshold_for_clearsky_limit=80.0) elif model == 'disc': df = irradiance.disc(weather_df.ghi, solar_position.zenith, weather_df.index, weather_df.pressure.mean()) df['dhi'] = weather_df.ghi - df.dni * pvlib.tools.cosd( solar_position.zenith) df['gni'] = df.dni + df.dhi return df
def test_disc_value(): times = pd.DatetimeIndex(['2014-06-24T12-0700', '2014-06-24T18-0700']) ghi = pd.Series([1038.62, 254.53], index=times) zenith = pd.Series([10.567, 72.469], index=times) pressure = 93193. disc_data = irradiance.disc(ghi, zenith, times, pressure=pressure) assert_almost_equal(disc_data['dni'].values, np.array([830.46, 676.09]), 1)
def test_disc_keys(): clearsky_data = clearsky.ineichen(times, tus, linke_turbidity=3) disc_data = irradiance.disc(clearsky_data['GHI'], ephem_data['zenith'], ephem_data.index) assert 'DNI_gen_DISC' in disc_data.columns assert 'Kt_gen_DISC' in disc_data.columns assert 'AM' in disc_data.columns
def test_disc_value(): times = pd.DatetimeIndex(['2014-06-24T12-0700','2014-06-24T18-0700']) ghi = pd.Series([1038.62, 254.53], index=times) zenith = pd.Series([10.567, 72.469], index=times) pressure = 93193. disc_data = irradiance.disc(ghi, zenith, times, pressure=pressure) assert_almost_equal(disc_data['dni'].values, np.array([830.46, 676.09]), 1)
def test_disc_min_cos_zenith_max_zenith(): # map out behavior under difficult conditions with various # limiting kwargs settings columns = ['dni', 'kt', 'airmass'] times = pd.DatetimeIndex(['2016-07-19 06:11:00'], tz='America/Phoenix') out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times) expected = pd.DataFrame(np.array( [[0.00000000e+00, 1.16046346e-02, 12.0]]), columns=columns, index=times) assert_frame_equal(out, expected) # max_zenith and/or max_airmass keep these results reasonable out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, min_cos_zenith=0) expected = pd.DataFrame(np.array( [[0.00000000e+00, 1.0, 12.0]]), columns=columns, index=times) assert_frame_equal(out, expected) # still get reasonable values because of max_airmass=12 limit out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, max_zenith=100) expected = pd.DataFrame(np.array( [[0., 1.16046346e-02, 12.0]]), columns=columns, index=times) assert_frame_equal(out, expected) # still get reasonable values because of max_airmass=12 limit out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, min_cos_zenith=0, max_zenith=100) expected = pd.DataFrame(np.array( [[277.50185968, 1.0, 12.0]]), columns=columns, index=times) assert_frame_equal(out, expected) # max_zenith keeps this result reasonable out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, min_cos_zenith=0, max_airmass=100) expected = pd.DataFrame(np.array( [[0.00000000e+00, 1.0, 36.39544757]]), columns=columns, index=times) assert_frame_equal(out, expected) # allow zenith to be close to 90 and airmass to be infinite # and we get crazy values out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, max_zenith=100, max_airmass=100) expected = pd.DataFrame(np.array( [[6.68577449e+03, 1.16046346e-02, 3.63954476e+01]]), columns=columns, index=times) assert_frame_equal(out, expected) # allow min cos zenith to be 0, zenith to be close to 90, # and airmass to be very big and we get even higher DNI values out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, min_cos_zenith=0, max_zenith=100, max_airmass=100) expected = pd.DataFrame(np.array( [[7.21238390e+03, 1., 3.63954476e+01]]), columns=columns, index=times) assert_frame_equal(out, expected)
def cloud_cover_to_irradiance_clearsky_scaling(cls, cloud_cover, location): solar_position = location.get_solarposition(cloud_cover.index) clearsky_irradiance = location.get_clearsky( cloud_cover.index, model='ineichen', solar_position=solar_position) ghi = cls.cloud_cover_to_ghi_linear(cloud_cover, clearsky_irradiance['ghi']) dni = disc(ghi, solar_position['zenith'], cloud_cover.index)['dni'] dhi = ghi - dni * np.cos(np.radians(solar_position['zenith'])) return pd.DataFrame({'ghi': ghi, 'dni': dni, 'dhi': dhi}).fillna(0)
def test_disc_overirradiance(): columns = ['dni', 'kt', 'airmass'] ghi = np.array([3000]) solar_zenith = np.full_like(ghi, 0) times = pd.DatetimeIndex(start='2016-07-19 12:00:00', freq='1s', periods=len(ghi), tz='America/Phoenix') out = irradiance.disc(ghi=ghi, solar_zenith=solar_zenith, datetime_or_doy=times) expected = pd.DataFrame(np.array( [[8.72544336e+02, 1.00000000e+00, 9.99493933e-01]]), columns=columns, index=times) assert_frame_equal(out, expected)
def test_disc_value(pressure, expected): # see GH 449 for pressure=None vs. 101325. columns = ['dni', 'kt', 'airmass'] times = pd.DatetimeIndex(['2014-06-24T1200', '2014-06-24T1800'], tz='America/Phoenix') ghi = pd.Series([1038.62, 254.53], index=times) zenith = pd.Series([10.567, 72.469], index=times) out = irradiance.disc(ghi, zenith, times, pressure=pressure) expected_values = np.array(expected) expected = pd.DataFrame(expected_values, columns=columns, index=times) # check the pandas dataframe. check_less_precise is weird assert_frame_equal(out, expected, check_less_precise=True) # use np.assert_allclose to check values more clearly assert_allclose(out.values, expected_values, atol=1e-5)
def calc_dni_disc(self, time_range, ghi, mypressure=101325): """ Compute the dni-value based on given ghi value within a time range using the DISC algortihm. Parameter: ========== time_range: pandas Series - time range. ghi: pandas Series - with global horizontal irradiance (ghi) >> taken from DWD Forecast. [W/m2] """ dni = disc(ghi=ghi, solar_zenith=self.solpos.zenith, datetime_or_doy=time_range) return dni
def dni(self, time, lat, lon, ghi, pressure): dni = [] try: ghi = self.ghi(ghi) ps = self.pressure(pressure, 'Pa') zenith = self.zenith(time, lat, lon) dni = irradiance.disc(ghi, zenith, time, ps).dni.values # irradiance.dirint(ghi, zenith, time, ps) except Exception as e: f = sys.exc_info()[2].tb_frame.f_back print("error: %s, line %s, in %s" % (f.f_code.co_filename, str(f.f_lineno), f.f_code.co_name)) print(e) return (dni)
def test_disc_value(): columns = ['dni', 'kt', 'airmass'] times = pd.DatetimeIndex(['2014-06-24T1200', '2014-06-24T1800'], tz='America/Phoenix') ghi = pd.Series([1038.62, 254.53], index=times) zenith = pd.Series([10.567, 72.469], index=times) pressure = 93193. out = irradiance.disc(ghi, zenith, times, pressure=pressure) expected_values = np.array( [[830.46567, 0.79742, 0.93505], [676.09497, 0.63776, 3.02102]]) expected = pd.DataFrame(expected_values, columns=columns, index=times) # check the pandas dataframe. check_less_precise is weird assert_frame_equal(out, expected, check_less_precise=True) # use np.assert_allclose to check values more clearly assert_allclose(out.values, expected_values, atol=1e-5)
def cloud_cover_to_irradiance_clearsky_scaling(self, cloud_cover, method='linear', **kwargs): """ Estimates irradiance from cloud cover in the following steps: 1. Determine clear sky GHI using Ineichen model and climatological turbidity. 2. Estimate cloudy sky GHI using a function of cloud_cover e.g. :py:meth:`~ForecastModel.cloud_cover_to_ghi_linear` 3. Estimate cloudy sky DNI using the DISC model. 4. Calculate DHI from DNI and GHI. Parameters ---------- cloud_cover : Series Cloud cover in %. method : str, default 'linear' Method for converting cloud cover to GHI. 'linear' is currently the only option. **kwargs Passed to the method that does the conversion Returns ------- irrads : DataFrame Estimated GHI, DNI, and DHI. """ solpos = self.location.get_solarposition(cloud_cover.index) cs = self.location.get_clearsky(cloud_cover.index, model='ineichen', solar_position=solpos) method = method.lower() if method == 'linear': ghi = self.cloud_cover_to_ghi_linear(cloud_cover, cs['ghi'], **kwargs) else: raise ValueError('invalid method argument') dni = disc(ghi, solpos['zenith'], cloud_cover.index)['dni'] dhi = ghi - dni * np.cos(np.radians(solpos['zenith'])) irrads = pd.DataFrame({'ghi': ghi, 'dni': dni, 'dhi': dhi}).fillna(0) return irrads
def _make_pv_forecast(self, forecast) -> pd.DataFrame: """Compile the forecast required for PV generation prediction Uses pvlib to generate solar irradiance predictions. Arguments: forecast {pandas.DataFrame} -- DarkSky originated forecast """ # Annoyingly, the PV & wind libraries want temperature named differently pv_forecast = forecast.rename(columns={ 'temperature': 'air_temp', 'windSpeed': 'wind_speed', }) # Use PV lib to get insolation based on the cloud cover reported here model = GFS() # Next up, we get hourly solar irradiance using interpolated cloud cover # We can get this from the clearsky GHI... if tables in sys.modules: # We can use Ineichen clear sky model (uses pytables for turbidity) clearsky = self.pv_location.get_clearsky(pv_forecast.index) else: # We can't, so use 'Simplified Solis' clearsky = self.pv_location.get_clearsky(pv_forecast.index, model='simplified_solis') # ... and by knowledge of where the sun is solpos = self.pv_location.get_solarposition(pv_forecast.index) ghi = model.cloud_cover_to_ghi_linear(pv_forecast['cloudCover'] * 100, clearsky['ghi']) dni = disc(ghi, solpos['zenith'], pv_forecast.index)['dni'] dhi = ghi - dni * np.cos(np.radians(solpos['zenith'])) # Whump it all together and we have our forecast! pv_forecast['dni'] = dni pv_forecast['dhi'] = dhi pv_forecast['ghi'] = ghi return pv_forecast
def cloud_cover_to_irradiance_clearsky_scaling(self, cloud_cover, method='linear', **kwargs): """ Estimates irradiance from cloud cover in the following steps: 1. Determine clear sky GHI using Ineichen model and climatological turbidity. 2. Estimate cloudy sky GHI using a function of cloud_cover e.g. :py:meth:`~ForecastModel.cloud_cover_to_ghi_linear` 3. Estimate cloudy sky DNI using the DISC model. 4. Calculate DHI from DNI and DHI. Parameters ---------- cloud_cover : Series Cloud cover in %. method : str Method for converting cloud cover to GHI. 'linear' is currently the only option. **kwargs Passed to the method that does the conversion Returns ------- irrads : DataFrame Estimated GHI, DNI, and DHI. """ solpos = self.location.get_solarposition(cloud_cover.index) cs = self.location.get_clearsky(cloud_cover.index, model='ineichen', solar_position=solpos) method = method.lower() if method == 'linear': ghi = self.cloud_cover_to_ghi_linear(cloud_cover, cs['ghi'], **kwargs) else: raise ValueError('invalid method argument') dni = disc(ghi, solpos['zenith'], cloud_cover.index)['dni'] dhi = ghi - dni * np.cos(np.radians(solpos['zenith'])) irrads = pd.DataFrame({'ghi': ghi, 'dni': dni, 'dhi': dhi}).fillna(0) return irrads
def test_disc_min_cos_zenith_max_zenith(): # map out behavior under difficult conditions with various # limiting kwargs settings columns = ['dni', 'kt', 'airmass'] times = pd.DatetimeIndex(['2016-07-19 06:11:00'], tz='America/Phoenix') out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times) expected = pd.DataFrame(np.array([[0.00000000e+00, 1.16046346e-02, 12.0]]), columns=columns, index=times) assert_frame_equal(out, expected) # max_zenith and/or max_airmass keep these results reasonable out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, min_cos_zenith=0) expected = pd.DataFrame(np.array([[0.00000000e+00, 1.0, 12.0]]), columns=columns, index=times) assert_frame_equal(out, expected) # still get reasonable values because of max_airmass=12 limit out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, max_zenith=100) expected = pd.DataFrame(np.array([[0., 1.16046346e-02, 12.0]]), columns=columns, index=times) assert_frame_equal(out, expected) # still get reasonable values because of max_airmass=12 limit out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, min_cos_zenith=0, max_zenith=100) expected = pd.DataFrame(np.array([[277.50185968, 1.0, 12.0]]), columns=columns, index=times) assert_frame_equal(out, expected) # max_zenith keeps this result reasonable out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, min_cos_zenith=0, max_airmass=100) expected = pd.DataFrame(np.array([[0.00000000e+00, 1.0, 36.39544757]]), columns=columns, index=times) assert_frame_equal(out, expected) # allow zenith to be close to 90 and airmass to be infinite # and we get crazy values out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, max_zenith=100, max_airmass=100) expected = pd.DataFrame(np.array( [[6.68577449e+03, 1.16046346e-02, 3.63954476e+01]]), columns=columns, index=times) assert_frame_equal(out, expected) # allow min cos zenith to be 0, zenith to be close to 90, # and airmass to be very big and we get even higher DNI values out = irradiance.disc(ghi=1.0, solar_zenith=89.99, datetime_or_doy=times, min_cos_zenith=0, max_zenith=100, max_airmass=100) expected = pd.DataFrame(np.array([[7.21238390e+03, 1., 3.63954476e+01]]), columns=columns, index=times) assert_frame_equal(out, expected)
def time_disc(self): irradiance.disc(self.clearsky_irradiance.ghi, self.solar_position.apparent_zenith, self.times)
def simulate_power_by_station(station_index, surface_tilt, surface_azimuth, pv_module, tcell_model_parameters, ghi, tamb, wspd, albedo, days, lead_times, air_mass, dni_extra, zenith, apparent_zenith, azimuth): """ This is the worker function for simulating power at a specified location. This function should be used inside of `simulate_power` and direct usage is discouraged. :param station_index: A station index :param ghi: See `simulate_power` :param tamb: See `simulate_power` :param wspd: See `simulate_power` :param albedo: See `simulate_power` :param days: See `simulate_power` :param lead_times: See `simulate_power` :param air_mass: See `simulate_power` :param dni_extra: See `simulate_power` :param zenith: See `simulate_power` :param apparent_zenith: See `simulate_power` :param azimuth: See `simulate_power` :param surface_tilt: See `simulate_power` :param surface_azimuth: See `simulate_power` :param pv_module: A PV module name :param tcell_model_parameters: A cell module name :return: A list with power, cell temperature, and the effective irradiance """ # Sanity check assert 0 <= station_index < ghi.shape[3], 'Invalid station index' # Determine the dimensions num_analogs = ghi.shape[0] num_lead_times = ghi.shape[1] num_days = ghi.shape[2] # Initialization p_mp = np.zeros((num_analogs, num_lead_times, num_days)) tcell = np.zeros((num_analogs, num_lead_times, num_days)) effective_irradiance = np.zeros((num_analogs, num_lead_times, num_days)) pv_module = pvsystem.retrieve_sam("SandiaMod")[pv_module] tcell_model_parameters = temperature.TEMPERATURE_MODEL_PARAMETERS["sapm"][ tcell_model_parameters] for day_index in range(num_days): for lead_time_index in range(num_lead_times): # Determine the current time current_posix = days[day_index] + lead_times[lead_time_index] current_time = pd.Timestamp(current_posix, tz="UTC", unit='s') for analog_index in range(num_analogs): ghi_ = ghi[analog_index, lead_time_index, day_index, station_index] if ghi_ == 0: continue albedo_ = albedo[analog_index, lead_time_index, day_index, station_index] wspd_ = wspd[analog_index, lead_time_index, day_index, station_index] tamb_ = tamb[analog_index, lead_time_index, day_index, station_index] air_mass_ = air_mass[lead_time_index, day_index, station_index] dni_extra_ = dni_extra[lead_time_index, day_index, station_index] zenith_ = zenith[lead_time_index, day_index, station_index] apparent_zenith_ = apparent_zenith[lead_time_index, day_index, station_index] azimuth_ = azimuth[lead_time_index, day_index, station_index] ########################################################################################## # # # Core procedures of simulating power at one location # # # ########################################################################################## # Decompose DNI from GHI dni_dict = irradiance.disc(ghi_, zenith_, current_time) # Calculate POA sky diffuse poa_sky_diffuse = irradiance.haydavies( surface_tilt, surface_azimuth, ghi_, dni_dict["dni"], dni_extra_, apparent_zenith_, azimuth_) # Calculate POA ground diffuse poa_ground_diffuse = irradiance.get_ground_diffuse( surface_tilt, ghi_, albedo_) # Calculate angle of incidence aoi = irradiance.aoi(surface_tilt, surface_azimuth, apparent_zenith_, azimuth_) # Calculate POA total poa_irradiance = irradiance.poa_components( aoi, dni_dict["dni"], poa_sky_diffuse, poa_ground_diffuse) # Calculate cell temperature tcell[analog_index, lead_time_index, day_index] = pvsystem.temperature.sapm_cell( poa_irradiance['poa_global'], tamb_, wspd_, tcell_model_parameters['a'], tcell_model_parameters['b'], tcell_model_parameters["deltaT"]) # Calculate effective irradiance effective_irradiance[ analog_index, lead_time_index, day_index] = pvsystem.sapm_effective_irradiance( poa_irradiance['poa_direct'], poa_irradiance['poa_diffuse'], air_mass_, aoi, pv_module) # Calculate power sapm_out = pvsystem.sapm( effective_irradiance[analog_index, lead_time_index, day_index], tcell[analog_index, lead_time_index, day_index], pv_module) # Save output to numpy p_mp[analog_index, lead_time_index, day_index] = sapm_out["p_mp"] return [p_mp, tcell, effective_irradiance]
def test_disc_keys(irrad_data, ephem_data): disc_data = irradiance.disc(irrad_data['ghi'], ephem_data['zenith'], ephem_data.index) assert 'dni' in disc_data.columns assert 'kt' in disc_data.columns assert 'airmass' in disc_data.columns