Пример #1
0
def recalc_financial_objective(df, scenarios, obj_col):
    f_cols = [col for col in df.columns if col.endswith('_financial_model')]

    data = dict()
    for idx, row in df.iterrows():
        for i, scenario in enumerate(scenarios):

            for j, col in enumerate(f_cols):
                new_col = col.split('_')[0] + '_' + scenario['name']
                if new_col not in data:
                    data[new_col] = []

                d = expand_financial_model(row[col])
                model = Singleowner.new()  #.default(defaults[tech_prefix[j]])
                model.assign(d)

                for key, val in scenario['values'].items():
                    if key == 'cp_capacity_credit_percent':
                        model.value(key, calc_capacity_credit_perc(d, val))
                    else:
                        model.value(key, val)

                model.execute()
                data[new_col].append(model.value(obj_col))

    for key, val in data.items():
        df[key] = val

    return df
Пример #2
0
    def __init__(self,
                 site: SiteInfo,
                 trough_config: dict):
        """
        Parabolic trough concentrating solar power class based on SSC’s Parabolic trough (physical model)

        :param site: Power source site information
        :param trough_config: CSP configuration with the following keys:

            #. ``cycle_capacity_kw``: float, Power cycle  design turbine gross output [kWe]
            #. ``solar_multiple``: float, Solar multiple [-]
            #. ``tes_hours``: float, Full load hours of thermal energy storage [hrs]
        """
        financial_model = Singleowner.default('PhysicalTroughSingleOwner')

        # set-up param file paths
        # TODO: Site should have dispatch factors consistent across all models
        self.param_files = {'tech_model_params_path': 'tech_model_defaults.json',
                            'cf_params_path': 'construction_financing_defaults.json',
                            'wlim_series_path': 'wlim_series.csv'}
        rel_path_to_param_files = os.path.join('pySSC_daotk', 'trough_data')
        self.param_file_paths(rel_path_to_param_files)

        super().__init__("TroughPlant", 'trough_physical', site, financial_model, trough_config)

        self._dispatch: TroughDispatch = None
Пример #3
0
Файл: grid.py Проект: NREL/HOPP
    def __init__(self, site: SiteInfo, interconnect_kw):
        """
        Class that houses the hybrid system performance and financials. Enforces interconnection and curtailment
        limits based on PySAM's Grid module

        :param site: Power source site information (SiteInfo object)
        :param interconnect_kw: Interconnection limit [kW]
        """
        system_model = GridModel.default("GenericSystemSingleOwner")

        financial_model: Singleowner.Singleowner = Singleowner.from_existing(system_model,
                                                                             "GenericSystemSingleOwner")
        super().__init__("Grid", site, system_model, financial_model)

        self._system_model.GridLimits.enable_interconnection_limit = 1
        self._system_model.GridLimits.grid_interconnection_limit_kwac = interconnect_kw

        # financial calculations set up
        self._financial_model.value("add_om_num_types", 1)

        self._dispatch: GridDispatch = None

        # TODO: figure out if this is the best place for these
        self.missed_load = [0.]
        self.missed_load_percentage = 0.0
        self.schedule_curtailed = [0.]
        self.schedule_curtailed_percentage = 0.0
Пример #4
0
 def default():
     """Get the default PySAM object"""
     pv = DefaultPvwattsv5.default()
     obj = PySamSingleOwner.default('PVWattsSingleOwner')
     obj.SystemOutput.gen = pv.Outputs.ac
     obj.execute()
     return obj
Пример #5
0
def test_ReOPT():

    lat = 39.7555
    lon = -105.2211

    # get resource and create model
    site = SiteInfo(flatirons_site)

    load = [1000 * (sin(x) + pi) for x in range(0, 8760)]
    urdb_label = "5ca4d1175457a39b23b3d45e"  # https://openei.org/apps/IURDB/rate/view/5ca3d45ab718b30e03405898

    solar_model = PVPlant(site, {'system_capacity_kw': 20000})
    wind_model = WindPlant(site, {
        'num_turbines': 10,
        "turbine_rating_kw": 2000
    })
    wind_model._system_model.Resource.wind_resource_filename = os.path.join(
        "data", "39.7555_-105.2211_windtoolkit_2012_60min_60m.srw")
    fin_model = so.default("GenericSystemSingleOwner")

    fileout = os.path.join(filepath, "REoptResultsNoExportAboveLoad.json")

    reopt = REopt(lat=lat,
                  lon=lon,
                  load_profile=load,
                  urdb_label=urdb_label,
                  solar_model=solar_model,
                  wind_model=wind_model,
                  fin_model=fin_model,
                  interconnection_limit_kw=20000,
                  fileout=fileout)
    reopt.set_rate_path(os.path.join(filepath, 'data'))

    reopt_site = reopt.post['Scenario']['Site']
    pv = reopt_site['PV']
    assert (pv['dc_ac_ratio'] == pytest.approx(1.3, 0.01))
    wind = reopt_site['Wind']
    assert (wind['pbi_us_dollars_per_kwh'] == pytest.approx(0.015))

    results = reopt.get_reopt_results()
    assert (isinstance(results, dict))
    print(results["outputs"]["Scenario"]["Site"]["Wind"]
          ['year_one_to_grid_series_kw'])
    if 'error' in results['outputs']['Scenario']["status"]:
        if 'error' in results["messages"].keys():
            if 'Optimization exceeded timeout' in results["messages"]['error']:
                assert True
            else:
                print(results["messages"]['error'])
        elif 'warning' in results["messages"].keys():
            print(results["messages"]['warnings'])
            assert True
    else:
        assert (results["outputs"]["Scenario"]["Site"]["Wind"]["size_kw"] >= 0)

    os.remove(fileout)
Пример #6
0
    def __init__(self,
                 site: SiteInfo,
                 battery_config: dict,
                 chemistry: str = 'lfpgraphite',
                 system_voltage_volts: float = 500):
        """
        Battery Storage class based on PySAM's BatteryStateful Model

        :param site: Power source site information (SiteInfo object)
        :param battery_config: Battery configuration with the following keys:

            #. ``system_capacity_kwh``: float, Battery energy capacity [kWh]
            #. ``system_capacity_kw``: float, Battery rated power capacity [kW]

        :param chemistry: Battery storage chemistry, options include:

            #. ``LFPGraphite``: Lithium Iron Phosphate (Lithium Ion)
            #. ``LMOLTO``: LMO/Lithium Titanate (Lithium Ion)
            #. ``LeadAcid``: Lead Acid
            #. ``NMCGraphite``: Nickel Manganese Cobalt Oxide (Lithium Ion)

        :param system_voltage_volts: Battery system voltage [VDC]
        """
        for key in ('system_capacity_kwh', 'system_capacity_kw'):
            if key not in battery_config.keys():
                raise ValueError

        system_model = BatteryModel.default(chemistry)
        financial_model = Singleowner.from_existing(system_model, "StandaloneBatterySingleOwner")
        super().__init__("Battery", site, system_model, financial_model)

        self.Outputs = BatteryOutputs(n_timesteps=site.n_timesteps)
        self.system_capacity_kw: float = battery_config['system_capacity_kw']
        self.chemistry = chemistry
        BatteryTools.battery_model_sizing(self._system_model,
                                          battery_config['system_capacity_kw'],
                                          battery_config['system_capacity_kwh'],
                                          system_voltage_volts,
                                          module_specs=Battery.module_specs)
        self._system_model.ParamsPack.h = 20
        self._system_model.ParamsPack.Cp = 900
        self._system_model.ParamsCell.resistance = 0.001
        self._system_model.ParamsCell.C_rate = battery_config['system_capacity_kw'] / battery_config['system_capacity_kwh']

        # Minimum set of parameters to set to get statefulBattery to work
        self._system_model.value("control_mode", 0.0)
        self._system_model.value("input_current", 0.0)
        self._system_model.value("dt_hr", 1.0)
        self._system_model.value("minimum_SOC", 10.0)
        self._system_model.value("maximum_SOC", 90.0)
        self._system_model.value("initial_SOC", 10.0)

        self._dispatch = None

        logger.info("Initialized battery with parameters and state {}".format(self._system_model.export()))
Пример #7
0
    def __init__(self,
                 site: SiteInfo,
                 pv_config: dict,
                 detailed_not_simple: bool = False):
        """

        :param pv_config: dict, with keys ('system_capacity_kw', 'layout_params')
            where 'layout_params' is of the SolarGridParameters type
        :param detailed_not_simple:
            Detailed model uses Pvsamv1, simple uses PVWatts
        """
        if 'system_capacity_kw' not in pv_config.keys():
            raise ValueError

        self._detailed_not_simple: bool = detailed_not_simple

        if not detailed_not_simple:
            system_model = Pvwatts.default("PVWattsSingleOwner")
            financial_model = Singleowner.from_existing(system_model, "PVWattsSingleOwner")
        else:
            system_model = Pvsam.default("FlatPlatePVSingleOwner")
            financial_model = Singleowner.from_existing(system_model, "FlatPlatePVSingleOwner")

        super().__init__("SolarPlant", site, system_model, financial_model)

        self._system_model.SolarResource.solar_resource_data = self.site.solar_resource.data

        self.dc_degradation = [0]

        params: Optional[PVGridParameters] = None
        if 'layout_params' in pv_config.keys():
            params: PVGridParameters = pv_config['layout_params']
        self._layout = PVLayout(site, system_model, params)

        self._dispatch: PvDispatch = None

        self.system_capacity_kw: float = pv_config['system_capacity_kw']
Пример #8
0
    def __init__(self, site: SiteInfo, tower_config: dict):
        """
        Tower concentrating solar power class based on SSC’s MSPT (molten salt power tower) model

        :param site: Power source site information
        :param tower_config: CSP configuration with the following keys:

            #. ``cycle_capacity_kw``: float, Power cycle  design turbine gross output [kWe]
            #. ``solar_multiple``: float, Solar multiple [-]
            #. ``tes_hours``: float, Full load hours of thermal energy storage [hrs]
            #. ``optimize_field_before_sim``: (optional, default = True) bool, If True, SolarPilot's field and tower
               height optimization will before system simulation, o.w., SolarPilot will just generate field based on
               inputs.
            #. ``scale_input_params``: (optional, default = True) bool, If True, HOPP will run
               :py:func:`hybrid.tower_source.scale_params` before system simulation.
        """
        financial_model = Singleowner.default('MSPTSingleOwner')

        # set-up param file paths
        self.param_files = {
            'tech_model_params_path': 'tech_model_defaults.json',
            'cf_params_path': 'construction_financing_defaults.json',
            'wlim_series_path': 'wlim_series.csv',
            'helio_positions_path': 'helio_positions.csv'
        }
        rel_path_to_param_files = os.path.join('pySSC_daotk', 'tower_data')
        self.param_file_paths(rel_path_to_param_files)

        super().__init__("TowerPlant", 'tcsmolten_salt', site, financial_model,
                         tower_config)

        self.optimize_field_before_sim = True
        if 'optimize_field_before_sim' in tower_config:
            self.optimize_field_before_sim = tower_config[
                'optimize_field_before_sim']

        # (optionally) adjust ssc input parameters based on tower capacity
        self.is_scale_params = False
        if 'scale_input_params' in tower_config and tower_config[
                'scale_input_params']:
            self.is_scale_params = True
            # Parameters to be scaled before receiver size optimization
            self.scale_params(params_names=[
                'helio_size', 'helio_parasitics', 'tank_heaters', 'tank_height'
            ])

        self._dispatch: TowerDispatch = None
Пример #9
0
def recalc_financials(result, assumptions):
    cols = [col for col in result.keys() if col.endswith('_financial_model')]
    
    models = []
    for col in cols:
        model_dict = expand_financial_model(result[col])
        model = Singleowner.new() #.default(defaults[tech_prefix[j]])
        model.assign(model_dict)
        
        for key, val in assumptions.items():
            if key == 'cp_capacity_credit_percent':
                val = calc_capacity_credit_percent(model_dict, N=val)
            model.value(key, val)
        model.execute()
                
        models.append(model)
        
    return models
Пример #10
0
def test_ReOPT():

    lat = 39.7555
    lon = -105.2211

    # get resource and create model
    site = SiteInfo(flatirons_site)

    load = [1000*(sin(x) + pi)for x in range(0, 8760)]
    urdb_label = "5ca4d1175457a39b23b3d45e" # https://openei.org/apps/IURDB/rate/view/5ca3d45ab718b30e03405898


    solar_model = SolarPlant(site, 20000)
    wind_model = WindPlant(site, 20000)
    wind_model.system_model.Resource.wind_resource_filename = os.path.join(
        "data", "39.7555_-105.2211_windtoolkit_2012_60min_60m.srw")
    fin_model = so.default("GenericSystemSingleOwner")

    reopt = REopt(lat=lat,
                  lon=lon,
                  load_profile=load,
                  urdb_label=urdb_label,
                  solar_model=solar_model,
                  wind_model=wind_model,
                  fin_model=fin_model,
                  interconnection_limit_kw=20000,
                  fileout=os.path.join(filepath, "data", "REoptResultsNoExportAboveLoad.json"))
    reopt.set_rate_path(os.path.join(filepath, 'data'))

    reopt_site = reopt.post['Scenario']['Site']
    pv = reopt_site['PV']
    assert(pv['dc_ac_ratio'] == pytest.approx(1.2, 0.01))
    wind = reopt_site['Wind']
    assert(wind['pbi_us_dollars_per_kwh'] == pytest.approx(0.022))

    results = reopt.get_reopt_results(force_download=True)
    assert(isinstance(results, dict))
    print(results["outputs"]["Scenario"]["Site"]["Wind"]['year_one_to_grid_series_kw'])
    assert (results["outputs"]["Scenario"]["Site"]["Wind"]["size_kw"] == pytest.approx(20000, 1))
    assert(results["outputs"]["Scenario"]["Site"]["Financial"]["lcc_us_dollars"] == pytest.approx(17008573.0, 1))
    assert(results["outputs"]["Scenario"]["Site"]["Financial"]["lcc_bau_us_dollars"] == pytest.approx(15511546.0, 1))
    assert(results["outputs"]["Scenario"]["Site"]["ElectricTariff"]["year_one_export_benefit_us_dollars"] == pytest.approx(-15158711.0, 1))
Пример #11
0
def gcr_func(x, y):
    # set up base
    a = Pvsamv1.default("FlatPlatePVSingleowner")
    a.SolarResource.solar_resource_file = "../sam/deploy/solar_resource/tucson_az_32.116521_-110.933042_psmv3_60_tmy.csv"

    b = Singleowner.default("FlatPlatePVSingleowner")

    # set up shading
    a.Shading.subarray1_shade_mode = 1
    a.Layout.subarray1_nmodx = 12
    a.Layout.subarray1_nmody = 2

    a.SystemDesign.subarray1_gcr = float(x)
    land_area = a.CECPerformanceModelWithModuleDatabase.cec_area * (
        a.SystemDesign.subarray1_nstrings *
        a.SystemDesign.subarray1_modules_per_string) / x * 0.0002471

    a.execute()
    # total_installed_cost = total_direct_cost + permitting_total + engr_total + grid_total + landprep_total + sales_tax_total + land_total
    b.SystemCosts.total_installed_cost += y * land_area * 1000
    b.SystemOutput.gen = a.Outputs.gen
    b.execute()
    return b.Outputs.analysis_period_irr
Пример #12
0
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()
grid.execute()
so.execute()
print('Made it past execute.')
print(gs.Outputs.export())  # as dictionary
Пример #13
0
import PySAM.ResourceTools as tools
import PySAM.Windpower as wp
import PySAM.Singleowner as so
    
# --- Initialize Wind Fetcher ---
wtkfetcher = tools.FetchResourceFiles(
                tech='wind',
                workers=1, #thread workers if fetching multiple files
                nrel_api_key=<NREL_API_KEY>,
                nrel_api_email=<NREL_API_EMAIL>)

# --- Pass a list of (lon, lat) tuples or Shapely points to fetch the nearest resource data ---
lon_lats = [(-105.1800775, 39.7383155)]  # golden CO
wtkfetcher.fetch(lon_lats)
    
# --- Get resource data file path ---
wtk_path_dict = wtkfetcher.resource_file_paths_dict
wtk_fp = wtk_path_dict[lon_lats[0]]

# --- Initialize Generator ---
generator = wp.default('WindPowerSingleOwner')
generator.Resource.assign({'wind_resource_model_choice': 0})
generator.Resource.assign({'wind_resource_filename': wtk_fp}) #pass path to resource file

# --- Initialize Financial Model ---
financial = so.from_existing(generator, "WindPowerSingleOwner")

# --- Execute Models ---
generator.execute()
financial.execute()
Пример #14
0
    def __init__(
            self,
            site: SiteInfo,
            farm_config: dict,
            rating_range_kw: tuple = (1000, 3000),
    ):
        """
        Set up a WindPlant

        :param farm_config: dict, with keys ('num_turbines', 'turbine_rating_kw', 'rotor_diameter', 'hub_height', 'layout_mode', 'layout_params')
            where layout_mode can be selected from the following:
            - 'boundarygrid': regular grid with boundary turbines, requires WindBoundaryGridParameters as 'params'
            - 'grid': regular grid with dx, dy distance, 0 angle; does not require 'params'

        :param rating_range_kw:
            allowable kw range of turbines, default is 1000 - 3000 kW
        """
        self._rating_range_kw = rating_range_kw

        if 'model_name' in farm_config.keys():
            if farm_config['model_name'] == 'floris':
                print('FLORIS is the system model...')
                system_model = Floris(farm_config,
                                      site,
                                      timestep=farm_config['timestep'])
                financial_model = Singleowner.default("WindPowerSingleOwner")
            else:
                raise NotImplementedError
        else:
            system_model = Windpower.default("WindPowerSingleOwner")
            financial_model = Singleowner.from_existing(
                system_model, "WindPowerSingleOwner")

        super().__init__("WindPlant", site, system_model, financial_model)
        self._system_model.value("wind_resource_data",
                                 self.site.wind_resource.data)

        if 'layout_mode' not in farm_config.keys():
            layout_mode = 'grid'
        else:
            layout_mode = farm_config['layout_mode']

        params: Optional[WindBoundaryGridParameters] = None
        if layout_mode == 'boundarygrid':
            if 'layout_params' not in farm_config.keys():
                raise ValueError(
                    "Parameters of WindBoundaryGridParameters required for boundarygrid layout mode"
                )
            else:
                params: WindBoundaryGridParameters = farm_config[
                    'layout_params']

        self._layout = WindLayout(site, system_model, layout_mode, params)

        self._dispatch: WindDispatch = None

        if 'turbine_rating_kw' not in farm_config.keys():
            raise ValueError("Turbine rating required for WindPlant")

        if 'num_turbines' not in farm_config.keys():
            raise ValueError("Num Turbines required for WindPlant")

        self.turb_rating = farm_config['turbine_rating_kw']
        self.num_turbines = farm_config['num_turbines']
        if 'hub_height' in farm_config.keys():
            self._system_model.Turbine.wind_turbine_hub_ht = farm_config[
                'hub_height']
        if 'rotor_diameter' in farm_config.keys():
            self.rotor_diameter = farm_config['rotor_diameter']
Пример #15
0
def run_reopt(site, scenario, load, interconnection_limit_kw, critical_load_factor, useful_life,
              battery_can_grid_charge,
              storage_used, run_reopt_flag):

    # kw_continuous = forced_system_size  # 5 MW continuous load - equivalent to 909kg H2 per hr at 55 kWh/kg electrical intensity

    urdb_label = "5ca4d1175457a39b23b3d45e"  # https://openei.org/apps/IURDB/rate/view/5ca3d45ab718b30e03405898
    pv_config = {'system_capacity_kw': 20000}
    solar_model = PVPlant(site, pv_config)
    # ('num_turbines', 'turbine_rating_kw', 'rotor_diameter', 'hub_height', 'layout_mode', 'layout_params')
    wind_config = {'num_turbines': np.floor(scenario['Wind Size MW'] / scenario['Turbine Rating']),
                       'rotor_dimeter': scenario['Rotor Diameter'], 'hub_height': scenario['Tower Height'],
                   'turbine_rating_kw': scenario['Turbine Rating']}

    wind_model = WindPlant(site, wind_config)
    fin_model = so.default("GenericSystemSingleOwner")
    filepath = os.path.dirname(os.path.abspath(__file__))
    fileout = 'reopt_result_test_intergration.json'
    # site = SiteInfo(sample_site, hub_height=tower_height)
    count = 1
    reopt = REopt(lat=scenario['Lat'],
                  lon=scenario['Long'],
                  load_profile=load,
                  urdb_label=urdb_label,
                  solar_model=solar_model,
                  wind_model=wind_model,
                  fin_model=fin_model,
                  interconnection_limit_kw=interconnection_limit_kw,
                  off_grid=True,
                  fileout=fileout)

    reopt.set_rate_path(os.path.join(filepath, '../data'))

    reopt.post['Scenario']['Site']['Wind']['installed_cost_us_dollars_per_kw'] = scenario['Wind Cost KW']  # ATB
    reopt.post['Scenario']['Site']['PV']['installed_cost_us_dollars_per_kw'] = scenario['Solar Cost KW']
    reopt.post['Scenario']['Site']['Storage'] = {'min_kw': 0.0, 'max_kw': 0.99e9, 'min_kwh': 0.0,
                                                 'max_kwh': 0.99e9,
                                                 'internal_efficiency_pct': 0.975, 'inverter_efficiency_pct': 0.96,
                                                 'rectifier_efficiency_pct': 0.96, 'soc_min_pct': 0.2,
                                                 'soc_init_pct': 0.5,
                                                 'canGridCharge': battery_can_grid_charge,
                                                 'installed_cost_us_dollars_per_kw': scenario['Storage Cost KW'],
                                                 'installed_cost_us_dollars_per_kwh': scenario['Storage Cost KWh'],
                                                 'replace_cost_us_dollars_per_kw': scenario['Storage Cost KW'],
                                                 'replace_cost_us_dollars_per_kwh': scenario['Storage Cost KWh'],
                                                 'inverter_replacement_year': 10,
                                                 'battery_replacement_year': 10, 'macrs_option_years': 7,
                                                 'macrs_bonus_pct': 1.0, 'macrs_itc_reduction': 0.5,
                                                 'total_itc_pct': 0.0,
                                                 'total_rebate_us_dollars_per_kw': 0,
                                                 'total_rebate_us_dollars_per_kwh': 0}

    reopt.post['Scenario']['Site']['Financial']['analysis_years'] = useful_life
    if not storage_used:
        reopt.post['Scenario']['Site']['Storage']['max_kw'] = 0
    if scenario['PTC Available']:
        reopt.post['Scenario']['Site']['Wind']['pbi_us_dollars_per_kwh'] = 0.022
    else:
        reopt.post['Scenario']['Site']['Wind']['pbi_us_dollars_per_kwh'] = 0.0
    if scenario['ITC Available']:
        reopt.post['Scenario']['Site']['PV']['federal_itc_pct'] = 0.26
    else:
        reopt.post['Scenario']['Site']['PV']['federal_itc_pct'] = 0.0

    # reopt.post['Scenario']['Site']['LoadProfile']['doe_reference_name'] = "FlatLoad"
    # reopt.post['Scenario']['Site']['LoadProfile']['annual_kwh'] = load #8760 * kw_continuous
    reopt.post['Scenario']['Site']['LoadProfile']['loads_kw'] = load
    reopt.post['Scenario']['Site']['LoadProfile']['critical_load_pct'] = critical_load_factor

    off_grid = False
    reopt.post['Scenario']['optimality_tolerance_techs'] = 0.05

    if off_grid == True:
        # reopt.post['Scenario']['Site'].pop('Wind')
        # reopt.post['Scenario']['Site']['Wind']['min_kw'] = 10000
        dictforstuff = {"off_grid_flag": True}
        reopt.post['Scenario'].update(dictforstuff)
        reopt.post['Scenario']['optimality_tolerance_techs'] = 0.05
        reopt.post['Scenario']["timeout_seconds"] = 3600
        # reopt.post['Scenario']['Site']['LoadProfile'].pop('annual kwh')
        reopt.post['Scenario']['Site'].pop('ElectricTariff')
        reopt.post['Scenario']['Site']['LoadProfile']['critical_load_pct'] = 1.0
        f = open('massproducer_offgrid (1).json')
        data_for_post = json.load(f)
        reopt.post['Scenario']['Site']['Financial'] = data_for_post['Scenario']['Site']['Financial']
    else:
        reopt.post['Scenario']['Site']['ElectricTariff']['wholesale_rate_us_dollars_per_kwh'] = 0.01
        reopt.post['Scenario']['Site']['ElectricTariff']['wholesale_rate_above_site_load_us_dollars_per_kwh'] = 0.01
        reopt.post['Scenario']['Site']['LoadProfile']['outage_start_hour'] = 10
        reopt.post['Scenario']['Site']['LoadProfile']['outage_end_hour'] = 11

    from pathlib import Path
    post_path = 'results/reopt_precomputes/reopt_post'
    post_path_abs = Path(__file__).parent / post_path
    if not os.path.exists(post_path_abs.parent):
        os.mkdir(post_path_abs.parent)
    with open(post_path_abs, 'w') as outfile:
        json.dump(reopt.post, outfile)
    # mass_producer_dict = {
    #     "mass_units": "kg",
    #     "time_units": "hr",
    #     "min_mass_per_time": 10.0,
    #     "max_mass_per_time": 10.0,
    #     "electric_consumed_to_mass_produced_ratio_kwh_per_mass": 71.7,
    #     "thermal_consumed_to_mass_produced_ratio_kwh_per_mass": 0.0,
    #     "feedstock_consumed_to_mass_produced_ratio": 0.0,
    #     "installed_cost_us_dollars_per_mass_per_time": 10.0,
    #     "om_cost_us_dollars_per_mass_per_time": 1.5,
    #     "om_cost_us_dollars_per_mass": 0.0,
    #     "mass_value_us_dollars_per_mass": 5.0,
    #     "feedstock_cost_us_dollars_per_mass": 0.0,
    #     "macrs_option_years": 0,
    #     "macrs_bonus_pct": 0
    # }
    # reopt.post['Scenario']['Site']['MassProducer'] = mass_producer_dict

    if run_reopt_flag:
        #NEW METHOD
        load_dotenv()
        result = reopt.get_reopt_results()

        #BASIC INITIAL TEST FOR NEW METHOD
        # result = post_and_poll.get_api_results(data_for_post, NREL_API_KEY, 'https://offgrid-electrolyzer-reopt-dev-api.its.nrel.gov/v1',
        #                       'reopt_result_test_intergration.json')

        # f = open('massproducer_offgrid (1).json')
        # data_for_post = json.load(f)

        #OLD METHOD
        # result = reopt.get_reopt_results(force_download=True)


        pickle.dump(result, open("results/reopt_precomputes/results_{}_{}_{}.p".format(
            scenario['Site Name'], scenario['Scenario Name'], critical_load_factor), "wb"))

    else:
        print("Not running reopt. Loading Dummy data")
        precompute_path = 'results/reopt_precomputes/'
        precompute_path_abs = Path(__file__).parent / precompute_path
        result = pickle.load(
            open(os.path.join(precompute_path_abs, "results_ATB_moderate_2020_IOWA_0.9.p"), "rb"))

    if result['outputs']['Scenario']['Site']['PV']['size_kw']:
        solar_size_mw = result['outputs']['Scenario']['Site']['PV']['size_kw'] / 1000

    if result['outputs']['Scenario']['Site']['Wind']['size_kw']:
        wind_size_mw = result['outputs']['Scenario']['Site']['Wind']['size_kw'] / 1000

    if result['outputs']['Scenario']['Site']['Storage']['size_kw']:
        storage_size_mw = result['outputs']['Scenario']['Site']['Storage']['size_kw'] / 1000
        storage_size_mwh = result['outputs']['Scenario']['Site']['Storage']['size_kwh'] / 1000
        storage_hours = storage_size_mwh / storage_size_mw

    reopt_site_result = result['outputs']['Scenario']['Site']
    generated_date = pd.date_range(start='1/1/2018 00:00:00', end='12/31/2018 23:00:00', periods=8760)
    if reopt_site_result['Wind']['size_kw'] == 0:

        reopt_site_result['Wind']['year_one_power_production_series_kw'] = np.zeros(8760)
        reopt_site_result['Wind']['year_one_to_grid_series_kw'] = np.zeros(8760)
        reopt_site_result['Wind']['year_one_to_load_series_kw'] = np.zeros(8760)
        reopt_site_result['Wind']['year_one_to_battery_series_kw'] = np.zeros(8760)
        reopt_site_result['Wind']['year_one_curtailed_production_series_kw'] = np.zeros(8760)
        wind_size_mw = 0

    if reopt_site_result['PV']['size_kw'] == 0:
        reopt_site_result['PV']['year_one_power_production_series_kw'] = np.zeros(8760)
        reopt_site_result['PV']['year_one_to_grid_series_kw'] = np.zeros(8760)
        reopt_site_result['PV']['year_one_to_load_series_kw'] = np.zeros(8760)
        reopt_site_result['PV']['year_one_to_battery_series_kw'] = np.zeros(8760)
        reopt_site_result['PV']['year_one_curtailed_production_series_kw'] = np.zeros(8760)
        solar_size_mw = 0

    if reopt_site_result['Storage']['size_kw'] == 0:
        reopt_site_result['Storage']['year_one_soc_series_pct'] = np.zeros(8760)
        reopt_site_result['Storage']['year_one_to_massproducer_series_kw'] = np.zeros(8760)
        storage_size_mw = 0
        storage_size_mwh = 0
        storage_hours = 0

    combined_pv_wind_power_production = [x + y for x, y in
                                         zip(reopt_site_result['PV']['year_one_power_production_series_kw']
                                             , reopt_site_result['Wind']['year_one_power_production_series_kw'])]
    combined_pv_wind_storage_power_production = [x + y for x, y in zip(combined_pv_wind_power_production,
                                                                       reopt_site_result['Storage'][
                                                                           'year_one_to_load_series_kw'])]
    energy_shortfall = [y - x for x, y in zip(combined_pv_wind_storage_power_production, load)]
    energy_shortfall = [x if x > 0 else 0 for x in energy_shortfall]

    combined_pv_wind_curtailment = [x + y for x, y in
                                    zip(reopt_site_result['PV']['year_one_curtailed_production_series_kw']
                                        , reopt_site_result['Wind']['year_one_curtailed_production_series_kw'])]


    reopt_result_dict = {'Date':
                             generated_date,
                         'pv_power_production':
                             reopt_site_result['PV']
                             ['year_one_power_production_series_kw'],
                         'pv_power_to_grid':
                             reopt_site_result['PV']
                             ['year_one_to_grid_series_kw'],
                         'pv_power_to_load':
                             reopt_site_result['PV']['year_one_to_load_series_kw'],
                         'pv_power_to_battery':
                             reopt_site_result['PV']['year_one_to_battery_series_kw'],
                         'pv_power_curtailed':
                             reopt_site_result['PV']['year_one_curtailed_production_series_kw'],
                         'wind_power_production':
                             reopt_site_result['Wind']
                             ['year_one_power_production_series_kw'],
                         'wind_power_to_grid':
                             reopt_site_result['Wind']
                             ['year_one_to_grid_series_kw'],
                         'wind_power_to_load':
                             reopt_site_result['Wind']['year_one_to_load_series_kw'],
                         'wind_power_to_battery':
                             reopt_site_result['Wind']['year_one_to_battery_series_kw'],
                         'wind_power_curtailed':
                             reopt_site_result['Wind']['year_one_curtailed_production_series_kw'],
                         'combined_pv_wind_power_production':
                             combined_pv_wind_power_production,
                         'combined_pv_wind_storage_power_production':
                             combined_pv_wind_storage_power_production,
                         'storage_power_to_load':
                             reopt_site_result['Storage']['year_one_to_load_series_kw'],
                         'storage_power_to_grid':
                             reopt_site_result['Storage']['year_one_to_grid_series_kw'],
                         'battery_soc_pct':
                             reopt_site_result['Storage']['year_one_soc_series_pct'],
                         'energy_shortfall':
                             energy_shortfall,
                         'combined_pv_wind_curtailment':
                             combined_pv_wind_curtailment
                         }

    REoptResultsDF = pd.DataFrame(reopt_result_dict)

    return wind_size_mw, solar_size_mw, storage_size_mw, storage_size_mwh, storage_hours, result, REoptResultsDF
Пример #16
0
# --- List of (lon, lat) tuples or Shapely points ---
lon_lats = [(lon, lat)]
wtkfetcher.fetch(lon_lats)

# --- Get resource data file path ---
wtk_path_dict = wtkfetcher.resource_file_paths_dict
wtk_fp = wtk_path_dict[lon_lats[0]]

# --- Initialize generator ---
if wtk_fp is not None:
    generator = wp.default('WindPowerSingleOwner')
    generator.Resource.assign({'wind_resource_model_choice': 0})
    generator.Resource.assign({'wind_resource_filename': wtk_fp})

    # --- Initialize financial model ---
    financial = so.from_existing(generator, 'WindPowerSingleOwner')

    print('Wind Power - Single Owner Results')
    generator.execute()
    print('capacity factor = {:.3f}'.format(generator.Outputs.capacity_factor))
    financial.execute()
    print('npv = ${:,.2f}'.format(
        financial.Outputs.project_return_aftertax_npv))

else:
    print('Wind resource file does not exist. Skipping wind model simulation.')

# --- Solar Example ---

# --- Initialize Solar Resource Fetcher with minimum parameters ---
# See function documentation for full parameter list