def test_flexible_time_steps(self): """ - Validation to ensure that upon entering time_steps_per_hour=1 or 4, the results of the analysis are as expected (keeping pv and storage off to test wind module's performance) - the output csv files dimensions (8760, 35040 etc) must also match time_steps_per_hour given as input :return: """ # results for time_steps_per_hour = 1 d1 = json.load(open(os.path.join("reo", "tests", "outputs_test_flexible_time_steps_one_per_hour.json"), "r")) c1 = nested_to_flat(d1) # results for time_steps_per_hour = 4 response2 = self.get_response(data=fts_post_2) self.assertHttpCreated(response2) r2 = json.loads(response2.content) run_uuid2 = r2.get('run_uuid') d2 = ModelManager.make_response(run_uuid=run_uuid2) c2 = nested_to_flat(d2['outputs']) # Seems reasonable that the exact resiliency average will be different due to a great granularity of survival # information in a quarter-hourly simulation vs hourly. del c1['avoided_outage_costs_us_dollars'] del c2['avoided_outage_costs_us_dollars'] try: check_common_outputs(self, c1, c2) except: print("Run {} expected outputs may have changed.".format(run_uuid2)) print("Error message with ts=1: {}".format(d1['messages'])) print("Error message with ts=4: {}".format(d2['messages'])) raise
def test_flexible_time_steps(self): """ - Validation to ensure that upon entering time_steps_per_hour = 1 or 4, the results of the analysis are as expected (evaluating with only existing PV to keep test fast) - the output dimensions (8760, 35040 etc) must also match time_steps_per_hour given as input """ # results for time_steps_per_hour = 4 response = self.get_response(data=fts_post_2) self.assertHttpCreated(response) r2 = json.loads(response.content) run_uuid2 = r2.get('run_uuid') d2 = ModelManager.make_response(run_uuid=run_uuid2) c2 = nested_to_flat(d2['outputs']) self.assertEqual(len(c2["year_one_grid_to_load_series"]), 35040) # results for time_steps_per_hour = 1 fts_post_2["Scenario"]["time_steps_per_hour"] = 1 fts_post_2["Scenario"]["Site"]["LoadProfile"]["loads_kw"] = [50] * 8760 fts_post_2["Scenario"]["Site"]["LoadProfile"][ "outage_start_time_step"] = 100 fts_post_2["Scenario"]["Site"]["LoadProfile"][ "outage_end_time_step"] = 124 response = self.get_response(data=fts_post_2) self.assertHttpCreated(response) r = json.loads(response.content) run_uuid = r.get('run_uuid') d = ModelManager.make_response(run_uuid=run_uuid) c1 = nested_to_flat(d['outputs']) # Seems reasonable that the exact resiliency average will be different due to a great granularity of survival # information in a quarter-hourly simulation vs hourly. del c1['avoided_outage_costs_us_dollars'] del c2['avoided_outage_costs_us_dollars'] check_common_outputs(self, c1, c2)
def test_soc_incentive(self): """ Test scenario with - fixed PV of 100 kW - fixed battery of 20kW, 20kWh - no other techs Toggle on and off the SOC incentive in the objective function and compare average SOC and LCC's. """ nested_data = json.load(open(self.test_post, 'rb')) nested_data['Scenario']['add_soc_incentive'] = True resp = self.get_response(data=nested_data) self.assertHttpCreated(resp) r = json.loads(resp.content) run_uuid = r.get('run_uuid') d = ModelManager.make_response(run_uuid=run_uuid) c = nested_to_flat(d['outputs']) c['average_soc'] = (sum(d['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct']) / len(d['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct'])) print(c['lcc']) print(c['average_soc']) d_expected = dict() d_expected['lcc'] = 350416.0 d_expected['average_soc'] = 0.7271688516340313 # try: # check_common_outputs(self, c, d_expected) # except: # print("Run {} expected outputs may have changed.".format(run_uuid)) # print("Error message: {}".format(d['messages'])) # raise nested_data['Scenario']['add_soc_incentive'] = False resp = self.get_response(data=nested_data) self.assertHttpCreated(resp) r = json.loads(resp.content) run_uuid = r.get('run_uuid') d = ModelManager.make_response(run_uuid=run_uuid) c = nested_to_flat(d['outputs']) c['average_soc'] = (sum(d['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct']) / len(d['outputs']['Scenario']['Site']['Storage']['year_one_soc_series_pct'])) d_expected['lcc'] = 350416.0 d_expected['average_soc'] = 0.6069393099644554 print(c['lcc']) print(c['average_soc']) try: check_common_outputs(self, c, d_expected) except: print("Run {} expected outputs may have changed.".format(run_uuid)) print("Error message: {}".format(d['messages'])) raise
def test_generator_sizing_with_existing_pv(self): """ Test scenario with - no existing diesel generator - existing PV considered - new PV and Wind disabled - Unlimited max storage - generator doesn't sell energy to grid - generator is only allowed to operate during outage hours """ nested_data = json.load(open(self.test_post, 'rb')) nested_data['Scenario']['Site']['LoadProfile']['outage_is_major_event'] = True nested_data['Scenario']['Site']['PV']['max_kw'] = 0 nested_data['Scenario']['Site']['Generator']['existing_kw'] = 0 nested_data['Scenario']['Site']['PV']['existing_kw'] = 100 resp = self.get_response(data=nested_data) self.assertHttpCreated(resp) r = json.loads(resp.content) run_uuid = r.get('run_uuid') d = ModelManager.make_response(run_uuid=run_uuid) c = nested_to_flat(d['outputs']) d_expected = dict() d_expected['lcc'] = 244743.0 d_expected['npv'] = -3959.0 d_expected['pv_kw'] = 100.0 d_expected['batt_kw'] = 0.0 d_expected['batt_kwh'] = 0.0 d_expected['gen_kw'] = 5.85713 d_expected['fuel_used_gal'] = 0.79 d_expected['avoided_outage_costs_us_dollars'] = 2982.63 d_expected['microgrid_upgrade_cost_us_dollars'] = 1054.2 d_expected['gen_total_variable_om_cost_us_dollars'] = 1.0 d_expected['existing_pv_om_cost_us_dollars'] = 11507.0 d_expected['net_capital_costs_plus_om'] = 15443.0 try: check_common_outputs(self, c, d_expected) except: print("Run {} expected outputs may have changed.".format(run_uuid)) print("Error message: {}".format(d['messages'])) raise critical_load = d['outputs']['Scenario']['Site']['LoadProfile']['critical_load_series_kw'] generator_to_load = d['outputs']['Scenario']['Site']['Generator']['year_one_to_load_series_kw'] storage_to_load = d['outputs']['Scenario']['Site']['Storage']['year_one_to_load_series_kw'] pv_to_load = d['outputs']['Scenario']['Site']['PV']['year_one_to_load_series_kw'] outage_start = d['inputs']['Scenario']['Site']['LoadProfile']['outage_start_hour'] outage_end = d['inputs']['Scenario']['Site']['LoadProfile']['outage_end_hour'] list_to_load = [generator_to_load, storage_to_load, pv_to_load] tech_to_load = self.outage_tech_to_load(list_to_load, outage_start, outage_end) for x, y in zip(critical_load[outage_start:outage_end], tech_to_load): self.assertAlmostEquals(x, y, places=3)
def test_curtailment(self): """ Validation run for wind scenario with updated WindToolkit data Note no tax, no ITC, no MACRS. :return: """ post_path = os.path.join('reo', 'tests', 'posts', 'test_curtailment_POST.json') with open(post_path, 'r') as fp: test_post = json.load(fp) d_expected = dict() d_expected['lcc'] = 5908025 d_expected['npv'] = -4961719 d_expected['average_annual_energy_curtailed_pv'] = 1091859 d_expected['average_annual_energy_curtailed_wind'] = 2841781 d_expected['total_pv_export'] = 0 d_expected['total_wind_export'] = 0 resp = self.get_response(data=test_post) self.assertHttpCreated(resp) r = json.loads(resp.content) run_uuid = r.get('run_uuid') d = ModelManager.make_response(run_uuid=run_uuid) err_messages = d['messages'].get('error') or [] if 'Wind Dataset Timed Out' in err_messages: print("Wind Dataset Timed Out") else: c = nested_to_flat(d['outputs']) print(d['outputs']['Scenario']['Site'].keys()) c['average_annual_energy_curtailed_pv'] = sum( d['outputs']['Scenario']['Site']['PV'] ['year_one_curtailed_production_series_kw']) c['average_annual_energy_curtailed_wind'] = sum( d['outputs']['Scenario']['Site']['Wind'] ['year_one_curtailed_production_series_kw']) c['total_pv_export'] = sum(d['outputs']['Scenario']['Site']['PV'] ['year_one_to_grid_series_kw']) c['total_wind_export'] = sum( d['outputs']['Scenario']['Site']['Wind'] ['year_one_to_grid_series_kw']) try: check_common_outputs(self, c, d_expected) except: print("Run {} expected outputs may have changed.".format( run_uuid)) print("Error message: {}".format(d['messages'].get('error'))) raise
def test_complex_incentives(self): """ Tests scenario where: PV has ITC, federal, state, local rebate with maxes, MACRS, bonus, Battery has ITC, rebate, MACRS, bonus. :return: None """ data = { "Scenario": {"webtool_uuid": None, "description": "", "timeout_seconds": 295, "Site": { "roof_squarefeet": 5000.0, "longitude": -118.1164613, "address": "", "latitude": 34.5794343, "time_steps_per_hour": 1, "user_uuid": None, "PV": {"pbi_years": 1.0, "macrs_bonus_pct": 0.4, "max_kw": 1000000000.0, "pbi_max_us_dollars": 1000000000.0, "radius": 0.0, "state_ibi_pct": 0.2, "utility_rebate_max_us_dollars": 10000000000.0, "installed_cost_us_dollars_per_kw": 2000.0, "utility_ibi_max_us_dollars": 10000.0, "tilt": 34.5794343, "federal_rebate_us_dollars_per_kw": 100.0, "gcr": 0.4, "pbi_system_max_kw": 10.0, "utility_ibi_pct": 0.1, "state_ibi_max_us_dollars": 10000.0, "state_rebate_us_dollars_per_kw": 200.0, "macrs_option_years": 5, "state_rebate_max_us_dollars": 10000000000.0, "dc_ac_ratio": 1.1, "federal_itc_pct": 0.3, "pbi_us_dollars_per_kwh": 0.0, "module_type": 1, "array_type": 1, "existing_kw": 0.0, "om_cost_us_dollars_per_kw": 16.0, "utility_rebate_us_dollars_per_kw": 50.0, "min_kw": 0.0, "losses": 0.14, "macrs_itc_reduction": 0.5, "degradation_pct": 0.005, "inv_eff": 0.96, "azimuth": 180.0}, "Generator": {"pbi_years": 0.0, "macrs_bonus_pct": 0.0, "om_cost_us_dollars_per_kwh": 0.01, "max_kw": 100000000.0, "pbi_max_us_dollars": 0.0, "state_ibi_pct": 0.0, "fuel_intercept_gal_per_hr": 0.0125, "generator_only_runs_during_grid_outage": True, "state_rebate_us_dollars_per_kw": 0.0, "installed_cost_us_dollars_per_kw": 600.0, "utility_ibi_max_us_dollars": 0.0, "fuel_avail_gal": 1000000000.0, "min_turn_down_pct": 0.0, "pbi_system_max_kw": 0.0, "utility_ibi_pct": 0.0, "state_ibi_max_us_dollars": 0.0, "diesel_fuel_cost_us_dollars_per_gallon": 3.0, "fuel_slope_gal_per_kwh": 0.068, "utility_rebate_max_us_dollars": 0.0, "macrs_option_years": 0, "state_rebate_max_us_dollars": 0.0, "federal_itc_pct": 0.0, "existing_kw": 0.0, "pbi_us_dollars_per_kwh": 0.0, "om_cost_us_dollars_per_kw": 10.0, "utility_rebate_us_dollars_per_kw": 0.0, "min_kw": 0.0, "macrs_itc_reduction": 0.0, "federal_rebate_us_dollars_per_kw": 0.0, "generator_sells_energy_back_to_grid": False}, "LoadProfile": {"critical_loads_kw_is_net": False, "critical_load_pct": 0.5, "loads_kw_is_net": True, "loads_kw": [], "outage_end_hour": None, "monthly_totals_kwh": [], "year": 2017, "outage_start_hour": None, "outage_is_major_event": True, "critical_loads_kw": [], "doe_reference_name": "RetailStore", "annual_kwh": 10000000.0}, "Storage": {"max_kwh": 1000000.0, "rectifier_efficiency_pct": 0.96, "total_itc_pct": 0.0, "min_kw": 0.0, "max_kw": 1000000.0, "replace_cost_us_dollars_per_kw": 460.0, "replace_cost_us_dollars_per_kwh": 230.0, "min_kwh": 0.0, "installed_cost_us_dollars_per_kw": 1000.0, "total_rebate_us_dollars_per_kw": 100, "installed_cost_us_dollars_per_kwh": 500.0, "inverter_efficiency_pct": 0.96, "macrs_itc_reduction": 0.5, "canGridCharge": True, "macrs_bonus_pct": 0.4, "battery_replacement_year": 10, "macrs_option_years": 5, "internal_efficiency_pct": 0.975, "soc_min_pct": 0.2, "soc_init_pct": 0.5, "inverter_replacement_year": 10}, "land_acres": 1.0, "ElectricTariff": {"add_blended_rates_to_urdb_rate": False, "wholesale_rate_us_dollars_per_kwh": 0.0, "net_metering_limit_kw": 0.0, "interconnection_limit_kw": 100000000.0, "blended_monthly_demand_charges_us_dollars_per_kw": [], "urdb_utility_name": "SouthernCaliforniaEdisonCo", "urdb_label": "", "wholesale_rate_above_site_load_us_dollars_per_kwh": 0.0, "urdb_rate_name": "TimeofUse,GeneralService,DemandMetered,OptionB:GS-2TOUB,SinglePhase", "urdb_response": {"sector": "Commercial", "peakkwcapacitymax": 200, "utility": "SouthernCaliforniaEdisonCo", "peakkwcapacityhistory": 12, "energyratestructure": [[{"rate": 0.0712, "unit": "kWh"}], [{"rate": 0.09368, "unit": "kWh"}], [{"rate": 0.066, "unit": "kWh"}], [{"rate": 0.08888, "unit": "kWh"}], [{"rate": 0.1355, "unit": "kWh"}]], "energyweekendschedule": [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], "demandweekendschedule": [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], "demandrateunit": "kW", "flatdemandstructure": [[{"rate": 13.2}]], "startdate": 1433116800, "phasewiring": "SinglePhase", "eiaid": 17609, "label": "55fc81d7682bea28da64f9ae", "flatdemandunit": "kW", "source": "http://www.sce.com/NR/sc3/tm2/pdf/ce30-12.pdf", "voltagecategory": "Primary", "revisions": [1433408708, 1433409358, 1433516188, 1441198316, 1441199318, 1441199417, 1441199824, 1441199996, 1454521683], "demandweekdayschedule": [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], "voltageminimum": 2000, "description": "-Energytieredcharge=generationcharge+deliverycharge\\r\\n\\r\\n-Timeofdaydemandcharges(generation-based)aretobeaddedtothemonthlydemandcharge(Deliverybased).", "energyattrs": [{"VoltageDiscount(2KV-<50KV)": "$-0.00106/Kwh"}, {"VoltageDiscount(>50KV<220KV)": "$-0.00238/Kwh"}, {"VoltageDiscountat220KV": "$-0.0024/Kwh"}, {"CaliforniaClimatecredit": "$-0.00669/kwh"}], "energyweekdayschedule": [[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2], [2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2], [2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2], [2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0]], "flatdemandmonths": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "approved": True, "fixedmonthlycharge": 259.2, "enddate": 1451520000, "name": "TimeofUse,GeneralService,DemandMetered,OptionB:GS-2TOUB,SinglePhase", "country": "USA", "uri": "http://en.openei.org/apps/IURDB/rate/view/55fc81d7682bea28da64f9ae", "voltagemaximum": 50000, "peakkwcapacitymin": 20, "demandattrs": [{"FaciltiesVoltageDiscount(2KV-<50KV)": "$-0.18/KW"}, {"FaciltiesVoltageDiscount>50kV-<220kV": "$-5.78/KW"}, {"FaciltiesVoltageDiscount>220kV": "$-9.96/KW"}, {"TimeVoltageDiscount(2KV-<50KV)": "$-0.70/KW"}, {"TimeVoltageDiscount>50kV-<220kV": "$-1.93/KW"}, {"TimeVoltageDiscount>220kV": "$-1.95/KW"}], "demandratestructure": [[{"rate": 0}], [{"rate": 5.3}], [{"rate": 18.11}]]}, "blended_annual_demand_charges_us_dollars_per_kw": 0.0, "blended_annual_rates_us_dollars_per_kwh": 0.0, "blended_monthly_rates_us_dollars_per_kwh": []}, "Financial": {"escalation_pct": 0.026, "offtaker_discount_pct": 0.081, "value_of_lost_load_us_dollars_per_kwh": 100.0, "analysis_years": 20, "microgrid_upgrade_cost_pct": 0.3, "offtaker_tax_pct": 0.4, "om_cost_escalation_pct": 0.025}, "Wind": {"max_kw": 0.0} }}} resp = self.get_response(data=data) self.assertHttpCreated(resp) r = json.loads(resp.content) run_uuid = r.get('run_uuid') d = ModelManager.make_response(run_uuid=run_uuid) c = nested_to_flat(d['outputs']) d_expected = dict() d_expected['lcc'] = 10972574 d_expected['npv'] = 11257165 - d_expected['lcc'] d_expected['pv_kw'] = 216.667 d_expected['batt_kw'] = 29.416 d_expected['batt_kwh'] = 38.8 d_expected['year_one_utility_kwh'] = 9612970 try: check_common_outputs(self, c, d_expected) except: print("Run {} expected outputs may have changed.".format(run_uuid)) print("Error message: {}".format(d['messages'].get('error'))) raise
def test_wind(self): """ Validation run for wind scenario with updated WindToolkit data Note no tax, no ITC, no MACRS. :return: """ wind_post = {"Scenario": {"Site": { "LoadProfile": { "annual_kwh": 10000000, "doe_reference_name": "MediumOffice" }, "Storage": { "max_kwh": 0, "max_kw": 0 }, "latitude": 39.91065, "longitude": -105.2348, "PV": { "max_kw": 0 }, "Wind": { "installed_cost_us_dollars_per_kw": 1874, "om_cost_us_dollars_per_kw": 35, "macrs_bonus_pct": 0.0, "max_kw": 10000, "federal_itc_pct": 0, "macrs_option_years": 0, "size_class": "large" }, "Financial": { "om_cost_escalation_pct": 0.001, "escalation_pct": 0.006, "offtaker_discount_pct": 0.07, "analysis_years": 25, "offtaker_tax_pct": 0.0 }, "ElectricTariff": { "blended_monthly_demand_charges_us_dollars_per_kw": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "net_metering_limit_kw": 1e6, "blended_monthly_rates_us_dollars_per_kwh": [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2] } }}} d_expected = dict() d_expected['lcc'] = 8551172 d_expected['npv'] = 16159608 d_expected['wind_kw'] = 3735 d_expected['average_annual_energy_exported_wind'] = 5844282 d_expected['net_capital_costs_plus_om'] = 8537480 resp = self.get_response(data=wind_post) self.assertHttpCreated(resp) r = json.loads(resp.content) run_uuid = r.get('run_uuid') d = ModelManager.make_response(run_uuid=run_uuid) err_messages = d['messages'].get('error') or [] if 'Wind Dataset Timed Out' in err_messages: print("Wind Dataset Timed Out") else: c = nested_to_flat(d['outputs']) try: check_common_outputs(self, c, d_expected) except: print("Run {} expected outputs may have changed.".format(run_uuid)) print("Error message: {}".format(d['messages'])) raise
def test_critical_load_bau_can_sustain_outage(self): """ Test scenario with - outage_start_hour: 16 - outage_end_hour: 20 - existing diesel generator 20 kW - existing PV 3 kW - available fuel 50 gallons """ test_post = os.path.join('reo', 'tests', 'posts', 'critical_load_bau_can_sustain_outage.json') nested_data = json.load(open(test_post, 'rb')) resp = self.get_response(data=nested_data) self.assertHttpCreated(resp) r = json.loads(resp.content) run_uuid = r.get('run_uuid') d = ModelManager.make_response(run_uuid=run_uuid) c = nested_to_flat(d['outputs']) load_bau = d['outputs']['Scenario']['Site']['LoadProfile'][ 'year_one_electric_load_series_kw'] # check first 100 hours c['load_bau'] = load_bau[:100] c['status'] = d['outputs']['Scenario']['status'] c['resilience_check_flag'] = d['outputs']['Scenario']['Site'][ 'LoadProfile']['resilience_check_flag'] c['sustain_hours'] = d['outputs']['Scenario']['Site']['LoadProfile'][ 'sustain_hours'] load_bau_expected = [ 19.5635, 18.9651, 20.3557, 19.0925, 20.2735, 19.0383, 20.3317, 13.6065, 9.20435, 7.3294, 7.14286, 5.62887, 5.20491, 4.40816, 4.21774, 4.21774, 2.13005, 6.20206, 8.43682, 8.63245, 17.7916, 17.9585, 18.6981, 18.7381, 19.5483, 19.2944, 20.0656, 19.5757, 20.2466, 19.8914, 24.4053, 32.5911, 39.7653, 47.1892, 47.1892, 47.1892, 42.9714, 47.1892, 47.1892, 47.1892, 47.1892, 21.2452, 16.5046, 17.0414, 17.6651, 17.7595, 18.298, 18.2451, 18.8185, 18.7475, 19.4191, 19.1492, 19.881, 19.5412, 24.4053, 32.5911, 39.7653, 47.1892, 47.1892, 47.1892, 42.9714, 47.1892, 47.1892, 47.1892, 47.1892, 21.4645, 16.1414, 16.5509, 16.7304, 17.308, 17.3808, 17.858, 17.8368, 18.1468, 17.8958, 18.1091, 17.7883, 18.1495, 24.4053, 32.5911, 39.7653, 47.1892, 47.1892, 47.1892, 42.9714, 47.1892, 47.1892, 47.1892, 47.1892, 20.9702, 15.1757, 15.3862, 15.8559, 15.9813, 16.7046, 16.5464, 17.2186, 16.8851, 17.7358, 17.2112 ] d_expected = dict() d_expected['load_bau'] = load_bau_expected d_expected['status'] = 'optimal' d_expected['total_energy_cost_bau'] = 54201.86 d_expected['year_one_energy_cost_bau'] = 7472.12 d_expected['resilience_check_flag'] = True d_expected['sustain_hours'] = 4 try: check_common_outputs(self, c, d_expected) except: print("Run {} expected outputs may have changed.".format(run_uuid)) print("Error message: {}".format(d['messages'])) raise