def get_wind_energy_output(self): ssc = pssc.PySSC() f = open(self.sam_export_json) self.dic = json.load(f) self.dic['wind_resource_filename'] = self.fp_srw wp_dat = pssc.dict_to_ssc_table(self.dic, "windpower") grid_dat = pssc.dict_to_ssc_table(self.dic, "grid") f.close() wp = Windpower.wrap(wp_dat) grid = Grid.from_existing(wp) grid.assign(Grid.wrap(grid_dat).export()) wp.execute() grid.execute() self.json_dict = wp.Outputs.export() # print(self.json_dict.keys()) # print (self.json_dict['gen']) self.df_output = pd.DataFrame() self.df_output[self.year] = self.json_dict['gen'] for col in self.df_output.columns: self.df_output[col] = preprocessing.minmax_scale( self.df_output[col].values.reshape(1, -1), feature_range=(0, 1), axis=1, copy=True).T if self.df_all is None: self.df_all = self.df_output.copy() else: self.df_all = pd.concat([self.df_all, self.df_output], axis=1)
def get_solar_energy_output(self): ssc = pssc.PySSC() f = open(self.sam_export_json) self.dic = json.load(f) self.dic['solar_resource_file'] = self.fp_srw ### uncomment if you want to change any model input parameters # self.dic['system_capacity'] = 20000 # self.dic['module_type'] = 0 # self.dic['dc_ac_ratio'] = 1.3 # self.dic['array_type'] = 2 # self.dic['tilt'] = 35 # self.dic['azimuth'] = 180 # self.dic['gcr'] = 0.40 # self.dic['losses'] = 14 # self.dic['en_snowloss'] = 0 # self.dic['inv_eff'] = 95 pv_dat = pssc.dict_to_ssc_table(self.dic, "pvwattsv7") grid_dat = pssc.dict_to_ssc_table(self.dic, "grid") f.close() pv = PVWatts.wrap(pv_dat) grid = Grid.from_existing(pv) grid.assign(Grid.wrap(grid_dat).export()) pv.execute() grid.execute() self.json_dict = pv.Outputs.export() # print(self.json_dict.keys()) self.df_output = pd.DataFrame() self.df_output[self.year] = self.json_dict['gen'] for col in self.df_output.columns: self.df_output[col] = preprocessing.minmax_scale( self.df_output[col].values.reshape(1, -1), feature_range=(0, 1), axis=1, copy=True).T if self.df_all is None: self.df_all = self.df_output.copy() else: self.df_all = pd.concat([self.df_all, self.df_output], axis=1)
def calculate_power(solar_data, pv_dict): """Use PVWatts to translate weather data into power. :param dict solar_data: weather data as returned by :meth:`Psm3Data.to_dict`. :param dict pv_dict: solar plant attributes. :return: (*numpy.array*) hourly power output. """ pv_dat = pssc.dict_to_ssc_table(pv_dict, "pvwattsv7") pv = PVWatts.wrap(pv_dat) pv.SolarResource.assign({"solar_resource_data": solar_data}) pv.execute() return np.array(pv.Outputs.gen)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Wed Mar 4 13:47:58 2020 Most recently tested against PySAM 2.2.3 @author: frohro """ import json import PySAM.GenericSystem as GenericSystem import PySAM.Grid as Grid import PySAM.Singleowner as Singleowner import PySAM.PySSC as pssc ssc = pssc.PySSC() with open("Examples/100mW_Generic.json") as f: dic = json.load(f) gs_dat = pssc.dict_to_ssc_table(dic, "generic_system") grid_dat = pssc.dict_to_ssc_table(dic, "grid") so_dat = pssc.dict_to_ssc_table(dic, "singleowner") gs = GenericSystem.wrap(gs_dat) grid = Grid.from_existing(gs) grid.assign(Grid.wrap(grid_dat).export()) # to create GenericSystem and Singleowner combined simulation, sharing the same data so = Singleowner.from_existing(gs) so.assign(Singleowner.wrap(so_dat).export()) gs.execute()
def retrieve_data(solar_plant, email, api_key, year="2016", rate_limit=0.5): """Retrieves irradiance data from NSRDB and calculate the power output using the System Adviser Model (SAM). :param pandas.DataFrame solar_plant: plant data frame. :param str email: email used to`sign up <https://developer.nrel.gov/signup/>`_. :param str api_key: API key. :param str year: year. :param int/float rate_limit: minimum seconds to wait between requests to NREL :return: (*pandas.DataFrame*) -- data frame with *'Pout'*, *'plant_id'*, *'ts'* and *'ts_id'* as columns. Values are power output for a 1MW generator. """ # SAM only takes 365 days. try: leap_day = (pd.Timestamp("%s-02-29-00" % year).dayofyear - 1) * 24 is_leap_year = True dates = pd.date_range(start="%s-01-01-00" % 2015, freq="H", periods=365 * 24) dates = dates.map(lambda t: t.replace(year=int(year))) except ValueError: leap_day = None is_leap_year = False dates = pd.date_range(start="%s-01-01-00" % year, freq="H", periods=365 * 24) # Identify unique location coord = get_plant_id_unique_location(solar_plant) data = pd.DataFrame({"Pout": [], "plant_id": [], "ts": [], "ts_id": []}) # PV tracking ratios # By state and by interconnect when EIA data do not have any solar PV in # the state pv_info = get_pv_tracking_data() zone_id = solar_plant.zone_id.unique() frac = {} for i in zone_id: state = id2abv[i] frac[i] = get_pv_tracking_ratio_state(pv_info, [state]) if frac[i] is None: frac[i] = get_pv_tracking_ratio_state( pv_info, list(interconnect2abv[abv2interconnect[state]])) # Inverter Loading Ratio ilr = 1.25 api = NrelApi(email, api_key, rate_limit) for key in tqdm(coord.keys(), total=len(coord)): lat, lon = key[1], key[0] solar_data = api.get_psm3_at( lat, lon, attributes="dhi,dni,wind_speed,air_temperature", year=year, leap_day=False, dates=dates, ).to_dict() for i in coord[key]: data_site = pd.DataFrame({ "ts": pd.date_range(start="%s-01-01-00" % year, end="%s-12-31-23" % year, freq="H") }) data_site["ts_id"] = range(1, len(data_site) + 1) data_site["plant_id"] = i power = 0 for j, axis in enumerate([0, 2, 4]): pv_dict = { "system_capacity": ilr, "dc_ac_ratio": ilr, "tilt": 30, "azimuth": 180, "inv_eff": 94, "losses": 14, "array_type": axis, "gcr": 0.4, "adjust:constant": 0, } pv_dat = pssc.dict_to_ssc_table(pv_dict, "pvwattsv7") pv = PVWatts.wrap(pv_dat) pv.SolarResource.assign({"solar_resource_data": solar_data}) pv.execute() ratio = frac[solar_plant.loc[i].zone_id][j] power += ratio * np.array(pv.Outputs.gen) if is_leap_year is True: data_site["Pout"] = np.insert(power, leap_day, power[leap_day - 24:leap_day]) else: data_site["Pout"] = power data = data.append(data_site, ignore_index=True, sort=False) data["plant_id"] = data["plant_id"].astype(np.int32) data["ts_id"] = data["ts_id"].astype(np.int32) data.sort_values(by=["ts_id", "plant_id"], inplace=True) data.reset_index(inplace=True, drop=True) return data
Load json file with inputs from SAM GUI. Load all needed PySAM module's data structures with the json input data. Run the simulations. Print the results. @author: frohro """ import json import PySAM.Pvwattsv7 as PVWatts import PySAM.Grid as Grid import PySAM.Utilityrate5 as UtilityRate import PySAM.Cashloan as Cashloan import PySAM.PySSC as pssc ssc = pssc.PySSC() verbose = True # Make False if you don't want all the debugging info. # Get the SAM json file, make the simulations we need for the commercial # PVWatts simulation. # The json file is generated from SAM using the "Generate Code" menu item # in the added simulation case. Choose "JSON for inputs" and a .json file # with the title of your simulation case will be created where you select with # the "Open" button on the file dialog. json_file_path = 'Examples/100kW_PVWatts.json' # Change this file name to yours! with open(json_file_path) as f: dic = json.load(f) # The next seven lines are needed to load the PySAM data structures with the # inputs from the json file.
def fit_sdm_cec_sam(celltype, v_mp, i_mp, v_oc, i_sc, alpha_sc, beta_voc, gamma_pmp, cells_in_series, temp_ref=25): """ Estimates parameters for the CEC single diode model (SDM) using the SAM SDK. Parameters ---------- celltype : str Value is one of 'monoSi', 'multiSi', 'polySi', 'cis', 'cigs', 'cdte', 'amorphous' v_mp : float Voltage at maximum power point [V] i_mp : float Current at maximum power point [A] v_oc : float Open circuit voltage [V] i_sc : float Short circuit current [A] alpha_sc : float Temperature coefficient of short circuit current [A/C] beta_voc : float Temperature coefficient of open circuit voltage [V/C] gamma_pmp : float Temperature coefficient of power at maximum point point [%/C] cells_in_series : int Number of cells in series temp_ref : float, default 25 Reference temperature condition [C] Returns ------- I_L_ref : float The light-generated current (or photocurrent) at reference conditions [A] I_o_ref : float The dark or diode reverse saturation current at reference conditions [A] R_sh_ref : float The shunt resistance at reference conditions, in ohms. R_s : float The series resistance at reference conditions, in ohms. a_ref : float The product of the usual diode ideality factor ``n`` (unitless), number of cells in series ``Ns``, and cell thermal voltage at reference conditions [V] Adjust : float The adjustment to the temperature coefficient for short circuit current, in percent. Raises ------ ImportError If NREL-PySAM is not installed. RuntimeError If parameter extraction is not successful. Notes ----- Inputs ``v_mp``, ``v_oc``, ``i_mp`` and ``i_sc`` are assumed to be from a single IV curve at constant irradiance and cell temperature. Irradiance is not explicitly used by the fitting procedure. The irradiance level at which the input IV curve is determined and the specified cell temperature ``temp_ref`` are the reference conditions for the output parameters ``I_L_ref``, ``I_o_ref``, ``R_sh_ref``, ``R_s``, ``a_ref`` and ``Adjust``. References ---------- .. [1] A. Dobos, "An Improved Coefficient Calculator for the California Energy Commission 6 Parameter Photovoltaic Module Model", Journal of Solar Energy Engineering, vol 134, 2012. """ try: from PySAM import PySSC except ImportError: raise ImportError("Requires NREL's PySAM package at " "https://pypi.org/project/NREL-PySAM/.") datadict = {'tech_model': '6parsolve', 'financial_model': 'none', 'celltype': celltype, 'Vmp': v_mp, 'Imp': i_mp, 'Voc': v_oc, 'Isc': i_sc, 'alpha_isc': alpha_sc, 'beta_voc': beta_voc, 'gamma_pmp': gamma_pmp, 'Nser': cells_in_series, 'Tref': temp_ref} result = PySSC.ssc_sim_from_dict(datadict) if result['cmod_success'] == 1: return tuple([result[k] for k in ['Il', 'Io', 'Rsh', 'Rs', 'a', 'Adj']]) else: raise RuntimeError('Parameter estimation failed')
def generate_solar_power_from_nsrdb(self, clearsky, capacity, DC_AC_ratio, tilt, azimuth, inv_eff, losses, array_type, year=None, leap_year=None, interval=None, utc=None): """ Generate PV power time series. Parameters ---------- clearsky : bool True returns clearsky power, false returns "simulated" output capacity : float System capacity in MW DC_AC_ratio : float DC/AC ratio (or power ratio). See https://sam.nrel.gov/sites/default/files/content/virtual_conf_july_2013/07-sam-virtual-conference-2013-woodcock.pdf tilt : float Tilt of system in degrees azimuth : float Azimuth angle (in degrees) from north (0 degrees) inv_eff : float Inverter efficiency (in %) losses : float Total system losses (in %) array_type : int # Specify PV configuration (0=Fixed, 1=Fixed Roof, 2=1 Axis Tracker, 3=Backtracted, 4=2 Axis Tracker) year : int Year of data. May take any value in the interval [1998,2018] leap_year : bool Leap year to true or false. True will return leap day data if present, false will not. interval: string Time interval in minutes, i.e., '30' is half hour intervals. Valid intervals are 30 & 60. utc : bool Specify Coordinated Universal Time (UTC), 'true' will use UTC, 'false' will use the local time zone of the data. NOTE: In order to use the NSRDB data in SAM, you must specify UTC as 'false'. SAM requires the data to be in the local time zone. """ if not hasattr(self, "resource_data"): args = [arg == None for arg in [year, leap_year, interval, utc]] if any(args): raise NameError("Missing input: year,leap_year,interval,utc") else: self.year = year self.leap_year = leap_year self.interval = interval self.utc = utc self.get_nsrdb_data(self) if clearsky == True: clearsky_str = "Clearsky " else: clearsky_str = "" ssc = PySSC() # Resource inputs for SAM model: wfd = ssc.data_create() ssc.data_set_number(wfd, 'lat'.encode('utf-8'), self.lat) ssc.data_set_number(wfd, 'lon'.encode('utf-8'), self.lon) ssc.data_set_number(wfd, 'tz'.encode('utf-8'), self.meta_resource_data["Time Zone"]) ssc.data_set_number(wfd, 'elev'.encode('utf-8'), self.meta_resource_data["Elevation"]) ssc.data_set_array(wfd, 'year'.encode('utf-8'), self.resource_data.Year) ssc.data_set_array(wfd, 'month'.encode('utf-8'), self.resource_data.Month) ssc.data_set_array(wfd, 'day'.encode('utf-8'), self.resource_data.Day) ssc.data_set_array(wfd, 'hour'.encode('utf-8'), self.resource_data.Hour) ssc.data_set_array(wfd, 'minute'.encode('utf-8'), self.resource_data.Minute) ssc.data_set_array(wfd, 'dn'.encode('utf-8'), self.resource_data["{}DNI".format(clearsky_str)]) ssc.data_set_array(wfd, 'df'.encode('utf-8'), self.resource_data["{}DHI".format(clearsky_str)]) ssc.data_set_array(wfd, 'wspd'.encode('utf-8'), self.resource_data['Wind Speed']) ssc.data_set_array(wfd, 'tdry'.encode('utf-8'), self.resource_data.Temperature) # Create SAM compliant object dat = ssc.data_create() ssc.data_set_table(dat, 'solar_resource_data'.encode('utf-8'), wfd) ssc.data_free(wfd) # Specify the system Configuration ssc.data_set_number(dat, 'system_capacity'.encode('utf-8'), capacity) ssc.data_set_number(dat, 'dc_ac_ratio'.encode('utf-8'), DC_AC_ratio) ssc.data_set_number(dat, 'tilt'.encode('utf-8'), tilt) ssc.data_set_number(dat, 'azimuth'.encode('utf-8'), azimuth) ssc.data_set_number(dat, 'inv_eff'.encode('utf-8'), inv_eff) ssc.data_set_number(dat, 'losses'.encode('utf-8'), losses) ssc.data_set_number(dat, 'array_type'.encode('utf-8'), array_type) ssc.data_set_number(dat, 'gcr'.encode('utf-8'), 0.4) # Set ground coverage ratio ssc.data_set_number(dat, 'adjust:constant'.encode('utf-8'), 0) # Set constant loss adjustment # execute and put generation results back into dataframe mod = ssc.module_create('pvwattsv5'.encode('utf-8')) ssc.module_exec(mod, dat) df = pd.DataFrame() df['generation'] = np.array( ssc.data_get_array(dat, 'gen'.encode('utf-8'))) df.index = self.resource_data.index # free the memory ssc.data_free(dat) ssc.module_free(mod) self.cloud_type = self.resource_data['Cloud Type'] self.solar_power_from_nsrdb = df self.capacity = capacity return df
# https://nrel-pysam.readthedocs.io/en/latest/ # https://nrel-pysam.readthedocs.io/en/latest/#importing-a-sam-gui-case # https://nrel-pysam.readthedocs.io/en/latest/Models.html import json import os import PySAM.Pvwattsv5 as pvwatts import PySAM.StandAloneBattery as battery import PySAM.Utilityrate5 as utility import PySAM.CashloanModel as cashloan from PySAM.PySSC import * ssc = PySSC() # I generated json files using "Generate Code" option in example.sam in pysam-examples and exporting as json. # Battery data is captured through detailed PV model, but will be used with PVWatts here with open(os.path.join('pysam_inputs', "pvwatts.json")) as f: dic = json.load(f) pvwatts_dat = dict_to_ssc_table(dic, "pvwattsv5") pv = pvwatts.wrap(pvwatts_dat) with open(os.path.join('pysam_inputs', "pvsamv1.json")) as f: dic = json.load(f) batt_dat = dict_to_ssc_table(dic, "battery") batt = battery.wrap(batt_dat) utility_dat = dict_to_ssc_table(dic, "utilityrate5") utilityrate = utility.wrap(utility_dat) loan_dat = dict_to_ssc_table(dic, "cashloan") loan = cashloan.wrap(loan_dat) # run PV model