def single_axis_irr(self, include_track_angles=False): """ Calculate the irradiances incident on a surface that mounted on an ideal single-axis tracker :param include_track_angles: whether to include the tracker angles into the returned dataframe. :return: a dataframe of sun irradiances on the single-axis tracked surface. """ tracker = SingleAxisTracker(axis_tilt=0, axis_azimuth=0, max_angle=180, backtrack=False) ngo = Location(latitude=self.latitude, longitude=self.longitude, altitude=0, tz='Japan') solar_pos = ngo.get_solarposition( pd.DatetimeIndex(self.hour_df['avg_time'])) tracker_angle = tracker.singleaxis( apparent_azimuth=solar_pos['azimuth'], apparent_zenith=solar_pos['apparent_zenith']) dni_arr = self.get_DNI() irr = tracker.get_irradiance( dni=dni_arr, ghi=self.hour_df['GHI'], dhi=self.hour_df['dHI'], solar_zenith=solar_pos['apparent_zenith'], solar_azimuth=solar_pos['azimuth'], surface_tilt=tracker_angle['surface_tilt'], surface_azimuth=tracker_angle['surface_azimuth']) irr['DNI'] = dni_arr n_df = pd.concat([self.hour_df, irr], axis=1) if include_track_angles == True: n_df = pd.concat([n_df, tracker_angle], axis=1) return n_df
def test_run_model_tracker(system, location, weather, mocker): system = SingleAxisTracker(module_parameters=system.module_parameters, inverter_parameters=system.inverter_parameters) mocker.spy(system, 'singleaxis') mc = ModelChain(system, location) mc.run_model(weather.index, weather=weather) assert system.singleaxis.call_count == 1 assert (mc.tracking.columns == ['tracker_theta', 'aoi', 'surface_azimuth', 'surface_tilt']).all() assert mc.ac[0] > 0 assert np.isnan(mc.ac[1])
def download_forecasts(request): modules_per_string = request.session['modules_per_string'] strings_per_inverter = request.session['strings_per_inverter'] module = request.session['module'] inverter = request.session['inverter'] latitude = request.session['latitude'] longitude = request.session['longitude'] tz = request.session['timezone'] sandia_modules = retrieve_sam('SandiaMod') cec_inverters = retrieve_sam('SandiaInverter') # Parametros de la granja solar surface_tilt = 30 surface_azimuth = 180 # pvlib uses 0=North, 90=East, 180=South, 270=West convention albedo = 0.2 # Rango de tiempo start = pd.Timestamp(date.today(), tz=tz) # Pronostico a 3 días en adelante end = start + pd.Timedelta(days=3) module = pd.Series(sandia_modules[module]) inverter = cec_inverters[inverter] # model a big tracker for more fun system = SingleAxisTracker(module_parameters=module, inverter_parameters=inverter, modules_per_string=modules_per_string, strings_per_inverter=strings_per_inverter) # fx is a common abbreviation for forecast fx_model = GFS() fx_data = fx_model.get_processed_data(latitude, longitude, start, end) # use a ModelChain object to calculate modeling intermediates mc = ModelChain(system, fx_model.location) # extract relevant data for model chain mc.run_model(fx_data.index, weather=fx_data) AC = mc.ac.fillna(0) response = HttpResponse(content_type='text/csv') response[ 'Content-Disposition'] = 'attachment; filename=AC_5days_forecasts.csv' AC.to_csv(path_or_buf=response, sep=';', float_format='%.2f', index=True, decimal=",") return response
def test_run_model_tracker(system, location): system = SingleAxisTracker(module_parameters=system.module_parameters, inverter_parameters=system.inverter_parameters) mc = ModelChain(system, location) times = pd.date_range('20160101 1200-0700', periods=2, freq='6H') ac = mc.run_model(times).ac expected = pd.Series(np.array([119.067713606, nan]), index=times) assert_series_equal(ac, expected, check_less_precise=2) expected = pd.DataFrame( np.array([[54.82513187, 90., 11.0039221, 11.0039221], [nan, 0., 0., nan]]), columns=['aoi', 'surface_azimuth', 'surface_tilt', 'tracker_theta'], index=times) assert_frame_equal(mc.tracking, expected, check_less_precise=2)
def test_run_model_from_poa_tracking(sapm_dc_snl_ac_system, location, total_irrad): system = SingleAxisTracker( module_parameters=sapm_dc_snl_ac_system.module_parameters, temperature_model_parameters=( sapm_dc_snl_ac_system.temperature_model_parameters ), inverter_parameters=sapm_dc_snl_ac_system.inverter_parameters) mc = ModelChain(system, location, aoi_model='no_loss', spectral_model='no_loss') ac = mc.run_model_from_poa(total_irrad).ac assert (mc.tracking.columns == ['tracker_theta', 'aoi', 'surface_azimuth', 'surface_tilt']).all() expected = pd.Series(np.array([149.280238, 96.678385]), index=total_irrad.index) assert_series_equal(ac, expected)
def get_cast(start_date, end_date): from pvlib.pvsystem import PVSystem, retrieve_sam from pvlib.temperature import TEMPERATURE_MODEL_PARAMETERS from pvlib.tracking import SingleAxisTracker from pvlib.modelchain import ModelChain sandia_modules = retrieve_sam('sandiamod') cec_inverters = retrieve_sam('cecinverter') module = sandia_modules['SolarWorld_Sunmodule_250_Poly__2013_'] inverter = cec_inverters['ABB__TRIO_20_0_TL_OUTD_S1_US_480__480V_'] temperature_model_parameters = TEMPERATURE_MODEL_PARAMETERS['sapm'][ 'open_rack_glass_glass'] # model a single axis tracker system = SingleAxisTracker( module_parameters=module, inverter_parameters=inverter, temperature_model_parameters=temperature_model_parameters, modules_per_string=15, strings_per_inverter=4) # fx is a common abbreviation for forecast fx_model = GFS() forecast_mod = fx_model.get_processed_data(latitude, longitude, start_date, end_date) # use a ModelChain object to calculate modeling intermediates mchain = ModelChain(system, fx_model.location) # extract relevant data for model chain mchain.run_model(forecast_mod) acp = mchain.ac.fillna(0) return acp
def get_system(racking, axis_height, collector_width, axis_azimuth, gcr, module_parameters, temperature_model_parameters, axis_tilt=0, max_angle=0, backtrack=False, surface_tilt=0, surface_azimuth=0, albedo=0): ''' Creates a PVSystem instance from PVLib (an input to ModelChain which defines a standard set of PV system attributes and modeling functions). Parameters: racking: string. mounting structure used for PV system either (tracker, ground-mount, rooftop, or canopy) axis_height: float. meters of racking tilt axis above ground collector_width: float. meter width of PV module perpendicular to axis of tilt axis_azimuth: float. compass direction along which the axis of rotation lies measured in decimal degrees East of North gcr: float. ratio of ground covered by PV modules within array to spacing betweeen modules used as common metric to refer to module spacing module_parameters: dict. module-specific parameters used to model dc output given irradiance temperature_model_parameters: dict. parameters used to convert ambient temperature to PV cell temperature axis_tilt: float. tracker requirement. The tilt of the axis of rotation in decimal degrees(DD) max_angle: float. tracker requirement. The max tilt allowed of a single-axis tracker in DD backtrack: boolean. tracker requirement. Whether or not the tracking system uses a backtracking algorithm surface_tilt: float. non-tracker requirement. Tilt of a fixed-tilt racking system in DD surface_azimuth: float. non-tracker requirement. Azimuth angle of the module surface East of North albedo: float. non-tracker requirement. The percent of light reflected from the ground Returns: pvlib.PVSystem Note: Would have used a kwargs parameter to but doesnt work with reticulate ''' # Single-Axis Tracker if racking == 'tracker': system = SingleAxisTracker(axis_tilt=axis_tilt, axis_azimuth=axis_azimuth, max_angle=max_angle, backtrack=backtrack, gcr=gcr, module_parameters=module_parameters) # Fixed-tilt System else: system = PVSystem(surface_tilt=surface_tilt, surface_azimuth=surface_azimuth, module_parameters=module_parameters) # These attributes get declared as part of SingleAxisTracker but not in # PVSystem system.axis_azimuth = axis_azimuth system.gcr = gcr system.backtrack = False # If racking is canopy or rooftop if racking != 'ground-mount': # Override system albedo for canopy and rooftop systems since time # series albedo calculations assume typical ground coverage (grass) system.albedo = albedo if racking == 'rooftop': system.module_parameters['bifaciality'] = 0 # Adding Attributes allows ModelChain to self-contain all project inputs system.axis_height = axis_height system.collector_width = collector_width system.temperature_model_parameters = temperature_model_parameters return system
def construct_pvsystem( inverter: models.Inverter) -> Union[PVSystem, SingleAxisTracker]: """Construct a pvlib.pvsystem.PVSystem (or SingleAxisTracker) from an Inverter object""" system_kwargs = dict( inverter=inverter.make_model, inverter_parameters=inverter.inverter_parameters.dict(), name=inverter.name, ) if inverter.losses is not None: system_kwargs["losses_parameters"] = inverter.losses.dict() array_params = [] tracking_params = [] is_single_axis = False for array in inverter.arrays: array_params.append( dict( albedo=array.albedo, module=array.make_model, module_parameters=array.module_parameters.pvlib_dict(), temperature_model_parameters=array. temperature_model_parameters.dict(), modules_per_string=array.modules_per_string, strings=array.strings, name=array.name, )) if isinstance(array.tracking, models.SingleAxisTracking): tracking_params.append( dict( axis_tilt=array.tracking.axis_tilt, axis_azimuth=array.tracking.axis_azimuth, gcr=array.tracking.gcr, backtrack=array.tracking.backtracking, )) is_single_axis = True # later might also need to keep track of the array class to use else: tracking_params.append( dict( surface_tilt=array.tracking.tilt, surface_azimuth=array.tracking.azimuth, )) if is_single_axis: if len(tracking_params) > 1: # pragma: no cover # until pvlib/pvlib-python#1109 is resolved raise ValueError( "Single axis tracking with multiple arrays not supported") else: return SingleAxisTracker(arrays=[ Array(**array_params[0], surface_tilt=None, surface_azimuth=None) ], **tracking_params[0], **system_kwargs) else: system_kwargs["arrays"] = [ Array(**atp[0], **atp[1]) for atp in zip(array_params, tracking_params) ] return PVSystem(**system_kwargs)
def pvlib_location(request): if request.method == 'POST': formulario = location_pv(request.POST) if formulario.is_valid(): params = formulario.cleaned_data #Creación del diccionario para las caracteristicas del modulo PV utilizado en Cutonalá #Canadian_Solar_CS6X_320P___2016_ = {"Vintage": 2016, "Area":1.91 , "Material": "Poly-crystalline", "Cells_in_Series": 72, "Parallel_Strings": 1, # "Isco":9.26, "Voco":45.3, "Impo":8.69, "Vmpo":36.8, "Aisc":0.000397, "Aimp":0.000181, "C0":1.01284, "C1":-0.0128398, "Bvoco":-0.21696, # "Mbvoc":0, "Bvmpo":-0.235488, "Mbvmp":0, "N":1.4032, "C2":0.279317, "C3":-7.24463, "A0":0.928385, "A1":0.068093, "A2":-0.0157738, "A3":0.0016605999999999997, # "A4":-6.929999999999999e-05, "B0":1, "B1":-0.002438, "B2":0.0003103, "B3":-1.246e-05, "B4":2.1100000000000002e-07, "B5":-1.36e-09, "DTC":3.0, "FD":1, "A":-3.4064099999999997, "B":-0.0842075, "C4":0.9964459999999999, # "C5":0.003554, "IXO":4.97599, "IXXO":3.18803, "C6":1.15535, "C7":-0.155353, "Notes":"caracteristicas del modulo instalado en CUT"} #module = pd.Series(Canadian_Solar_CS6X_320P___2016_, name="Canadian_Solar_CS6X_320P___2016_") #Modulo desde la librería de Sandia labs #cec_inverters = retrieve_sam('cecinverter') #inverter = cec_inverters['SMA_America__SC630CP_US_315V__CEC_2012_'] modules_per_string = params['modules_per_string'] strings_per_inverter = params['strings_per_inverter'] module = params['module'] inverter = params['inverter'] request.session['modules_per_string'] = modules_per_string request.session['strings_per_inverter'] = strings_per_inverter request.session['module'] = module request.session['inverter'] = inverter #Calcular la potencia CD, aqui debemos tener el diccionario para el tipo de Modulo en CUTonalá sandia_modules = retrieve_sam('SandiaMod') #### Modulo desde la librería de Sandia labs cec_inverters = retrieve_sam('cecinverter') # Lugar Tonalá latitude, longitude = params['latitude'], params['longitude'] request.session['latitude'] = latitude request.session['longitude'] = longitude tz = tzwhere.tzwhere().tzNameAt(latitude, longitude) request.session['timezone'] = tz # Parametros de la granja solar surface_tilt = 30 surface_azimuth = 180 # pvlib uses 0=North, 90=East, 180=South, 270=West convention albedo = 0.2 # Rango de tiempo start = pd.Timestamp(date.today(), tz=tz) # Pronostico a 3 días en adelante end = start + pd.Timedelta(days=5) module = pd.Series(sandia_modules[module]) inverter = cec_inverters[inverter] # model a big tracker for more fun system = SingleAxisTracker( module_parameters=module, inverter_parameters=inverter, modules_per_string=modules_per_string, strings_per_inverter=strings_per_inverter) # fx is a common abbreviation for forecast fx_model = GFS() fx_data = fx_model.get_processed_data(latitude, longitude, start, end) # use a ModelChain object to calculate modeling intermediates mc = ModelChain(system, fx_model.location) # extract relevant data for model chain mc.run_model(fx_data.index, weather=fx_data) #mc.run_model(fx_data) AC = mc.ac.fillna(0) #AC = pd.DataFrame(AC) #labeles = AC.keys() #valores = AC.values() #data = { # "Dates": labeles, # "Power (W)": valores, #} #here we print the data the correct thing would be to use them to graph them #print(AC.head()) #return render(request, 'chart.html', {'forma': formulario}) template = 'chart.html' #columns = [{'field': 'date', 'title': 'Date'}, {'field': 'value', 'title': 'Value'}] #Write the DataFrame to JSON (as easy as can be) #json = AC.to_json(orient='records') # output just the records (no fieldnames) as a collection of tuples #Proceed to create your context object containing the columns and the data #context = { # 'data': json, # 'columns': columns # } #And render it! #return render(request, template, context) AC = AC.reset_index() AC.rename(columns={ 'index': 'Time', 0: 'AC Power (W)' }, inplace=True) figure = px.line(AC, x='Time', y='AC Power (W)') #figure.update_layout(title="Your 5 days AC power output forecast (W)", font=dict(size=20, color='black')) #figure.update_xaxes(title_font=dict(size=16, color='black')) #figure.update_yaxes(title_font=dict(size=16, color='black')) figure.update_xaxes(dtick=10800000) plot_div = plot(figure, image_height='100%', output_type='div', include_plotlyjs=False) context = {'linechart': plot_div} return render(request, template, context) else: formulario = location_pv() return render(request, 'forecast_data.html', {'form': formulario})
def PVlibwrapper(PV_instance, tmy, return_model_object=False): PV = PV_instance tmy.site = Location(tmy.lat, tmy.lon) cec_inverters = pvlib.pvsystem.retrieve_sam("cecinverter") cec_modules = pvlib.pvsystem.retrieve_sam("CECMod") # default: Jinko Solar Co Ltd JKM350M 72 V module = cec_modules[PV.module] # default: Huawei Technologies Co Ltd SUN2000 100KTL USH0 800V cec_inverter = cec_inverters[PV.inverter] temperature_model_parameters = TEMPERATURE_MODEL_PARAMETERS["sapm"][ "open_rack_glass_glass"] if PV.tracking: system = SingleAxisTracker( axis_tilt=0, axis_azimuth=PV.azimuth, module_parameters=module, inverter_parameters=cec_inverter, temperature_model_parameters=temperature_model_parameters, strings_per_inverter=PV.strings_per_inverter, modules_per_string=PV.modules_per_string, ) losses_model = "no_loss" else: system = PVSystem( surface_tilt=PV.tilt, surface_azimuth=PV.azimuth, module_parameters=module, inverter_parameters=cec_inverter, temperature_model_parameters=temperature_model_parameters, strings_per_inverter=PV.strings_per_inverter, modules_per_string=PV.modules_per_string, ) losses_model = "pvwatts" total_module_power = PV.strings_per_inverter * PV.modules_per_string * module[ "STC"] mc = ModelChain( system, tmy.site, aoi_model="ashrae", spectral_model="no_loss", losses_model=losses_model, transposition_model="perez", ) if hasattr(PV, "bifacial_irradiance"): mc.run_model_from_effective_irradiance(PV.bifacial_irradiance) print() print() print(f"{PV.name} triggered run_from") print() print() else: mc.run_model(PVlibweather(tmy)) print() print() print(f"{PV.name} triggered run_model") print() print() normalized_power = mc.ac / total_module_power scaled_power = normalized_power * PV.installed # reset index scaled_power.index = PV.state.index if return_model_object: return mc, scaled_power else: return scaled_power