Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,9 @@
],
"metadata": {
"kernelspec": {
"display_name": "py36",
"display_name": "Python 3",
"language": "python",
"name": "py36"
"name": "python3"
},
"language_info": {
"codemirror_mode": {
Expand All @@ -314,7 +314,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.8"
"version": "3.8.8"
}
},
"nbformat": 4,
Expand Down
1 change: 1 addition & 0 deletions REopt API Scripts/inputs/site_1.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions REopt API Scripts/inputs/site_2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Site": {"latitude": 39.5611, "longitude": -107.29351, "land_acres": 10, "roof_squarefeet": 0}, "ElectricLoad": {"doe_reference_name": "Hospital", "year": 2023, "critical_load_fraction": 1, "loads_kw_is_net": 1}, "Generator": {"existing_kw": 120, "om_cost_per_kw": 16, "fuel_cost_per_gallon": 4}, "ElectricUtility": {"net_metering_limit_kw": 1000}, "ElectricTariff": {"blended_annual_energy_rate": 0.2, "blended_annual_demand_rate": 10, "wholesale_rate": 0}, "Financial": {"om_cost_escalation_rate_fraction": 0.02, "elec_cost_escalation_rate_fraction": 0.01, "generator_fuel_cost_escalation_rate_fraction": 0.01}, "PV": {"existing_kw": 50, "min_kw": 0, "array_type": 0, "installed_cost_per_kw": 2000, "tilt": 20, "azimuth": 270, "federal_itc_fraction": 0.4}, "ElectricStorage": {"min_kw": 0, "min_kwh": 0, "installed_cost_per_kw": 919.1, "installed_cost_per_kwh": 459.55, "replace_cost_per_kw": 722.15, "replace_cost_per_kwh": 321.18}, "Wind": {"max_kw": 0}}
1 change: 1 addition & 0 deletions REopt API Scripts/inputs/site_3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Site": {"latitude": 40.011965, "longitude": -75.099488}, "ElectricLoad": {"doe_reference_name": "StripMall", "annual_kwh": 500000, "year": 2023, "loads_kw_is_net": false}, "Generator": {"om_cost_per_kw": false}, "ElectricUtility": {"net_metering_limit_kw": false}, "ElectricTariff": {"blended_annual_energy_rate": 0.15, "blended_annual_demand_rate": false, "wholesale_rate": false}, "PV": {"existing_kw": false, "array_type": 2, "installed_cost_per_kw": 3500}, "ElectricStorage": {"min_kw": false, "min_kwh": false, "installed_cost_per_kw": 819, "installed_cost_per_kwh": 409.5, "replace_cost_per_kw": 643.5, "replace_cost_per_kwh": 286.2}, "Wind": {"max_kw": false}}
Binary file not shown.
Binary file not shown.
337 changes: 337 additions & 0 deletions REopt API Scripts/multiple_runs.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,337 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "dced6536",
"metadata": {},
"source": [
"# TODO: \n",
"- determine a good example of inputs to use in the example Excel\n",
"- improve the instructions in the Excel\n",
"- consider moving some functions to src file\n",
"- Improve error checking\n",
"- Add resilience inputs and outage time selection\n",
"- Could add scenario description and save the site + description\n",
"- Finish the output file generation with the 3 options\n",
"\n",
"# MVP: \n",
"- Electric only\n",
"- Don't worry about Google Colab (user clones Repo, modifies Excel, downloads results to local (cloned) folder)\n",
"- Minimal error checking "
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "b43b54b7",
"metadata": {},
"outputs": [
{
"ename": "ImportError",
"evalue": "Unable to import required dependencies:\nnumpy: Error importing numpy: you should not try to import numpy from\n its source directory; please exit the numpy source tree, and relaunch\n your python interpreter from there.",
"output_type": "error",
"traceback": [
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
"\u001b[31mImportError\u001b[39m Traceback (most recent call last)",
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mpandas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mpd\u001b[39;00m\n\u001b[32m 2\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mnumpy\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mnp\u001b[39;00m\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mjson\u001b[39;00m\n",
"\u001b[36mFile \u001b[39m\u001b[32m~/Library/Python/3.13/lib/python/site-packages/pandas/__init__.py:19\u001b[39m\n\u001b[32m 16\u001b[39m _missing_dependencies.append(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m_dependency\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m_e\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 18\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m _missing_dependencies: \u001b[38;5;66;03m# pragma: no cover\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m19\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mImportError\u001b[39;00m(\n\u001b[32m 20\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mUnable to import required dependencies:\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m\"\u001b[39m + \u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m\"\u001b[39m.join(_missing_dependencies)\n\u001b[32m 21\u001b[39m )\n\u001b[32m 22\u001b[39m \u001b[38;5;28;01mdel\u001b[39;00m _hard_dependencies, _dependency, _missing_dependencies\n\u001b[32m 24\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m 25\u001b[39m \u001b[38;5;66;03m# numpy compat\u001b[39;00m\n",
"\u001b[31mImportError\u001b[39m: Unable to import required dependencies:\nnumpy: Error importing numpy: you should not try to import numpy from\n its source directory; please exit the numpy source tree, and relaunch\n your python interpreter from there."
]
}
],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import json\n",
"import requests\n",
"import copy\n",
"import os\n",
"from src.post_and_poll import get_api_results\n",
"\n",
"root_url = \"https://developer.nrel.gov/api/reopt/stable\"\n",
"\n",
"API_KEY = 'DEMO_KEY' # REPLACE WITH YOUR API KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e4269b73",
"metadata": {},
"outputs": [],
"source": [
"# following is not necessary but silences warnings:\n",
"# InsecureRequestWarning: Unverified HTTPS request is being made to host 'developer.nrel.gov'. Adding certificate verification is strongly advised.\n",
"import urllib3\n",
"urllib3.disable_warnings()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8c07f411",
"metadata": {},
"outputs": [],
"source": [
"# Specify file name: \n",
"data_file = \"multi_site_inputs.xlsx\"\n",
"\n",
"##############################################################################################################\n",
"site_data = os.path.join(\".\", 'multi_site_inputs', data_file)\n",
"posts_path = os.path.join(\".\", 'inputs') # To save posts\n",
"outputs_path = os.path.join(\".\", 'outputs')\n",
"rates_path = os.path.join(\".\", 'electric_rates')\n",
"results_summary_path = os.path.join(\".\", 'results_summary')\n",
"##############################################################################################################"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "82eb329c",
"metadata": {},
"outputs": [],
"source": [
"# Get Data\n",
"df_site = pd.read_excel(site_data, sheet_name=\"reopt_inputs\", index_col=0) \n",
"df_loads = pd.read_excel(site_data, sheet_name=\"interval_load\", index_col=0) \n",
"df_monthly_loads = pd.read_excel(site_data, sheet_name=\"monthly_loads\", index_col=0) "
]
},
{
"cell_type": "markdown",
"id": "d5093ffc",
"metadata": {},
"source": [
"## The code below is draft and needs a lot of improvement"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e619f318",
"metadata": {},
"outputs": [],
"source": [
"# Create posts Dict by site then scenario\n",
"# e.g., posts[site_name]\n",
"\n",
"posts = dict() # Dictionary for all posts by site name\n",
"for site in df_site: # iterate over sites\n",
" post = dict()\n",
" # Populate all site-specific inputs from Excel\n",
" for label in df_site[site].keys():\n",
" val = df_site[site][label]\n",
" if not pd.isna(val): # ignore empty entries\n",
" key, subkey = label.split(\" | \")\n",
" if key not in post:\n",
" post[key] = {}\n",
" # Check if custom utility rate json is provided\n",
" if subkey == \"urdb_response\":\n",
" with open(os.path.join(rates_path, val), 'r') as fp:\n",
" post[key][subkey] = json.load(fp)\n",
" else:\n",
" post[key][subkey] = val\n",
"\n",
" ## Add load and correct timesteps per hour ## \n",
" if sum(df_loads[site]) > 0:\n",
" load_profile = df_loads[site].to_list()\n",
" load_profile = [float(v) for v in load_profile] \n",
" post[\"ElectricLoad\"][\"loads_kw\"] = load_profile\n",
"\n",
"\n",
" # Add post to dict\n",
" posts[site] = copy.deepcopy(post)\n",
"\n",
" with open(os.path.join(posts_path, site + \".json\"), 'w') as fp:\n",
" json.dump(posts[site], fp)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f8da992f",
"metadata": {},
"outputs": [],
"source": [
"responses = []\n",
"\n",
"for site in df_site:\n",
" responses.append(\n",
" get_api_results(\n",
" posts[site], \n",
" results_file=os.path.join(outputs_path, site + '.json'),\n",
" api_url=root_url, \n",
" API_KEY=API_KEY\n",
" )\n",
" )"
]
},
{
"cell_type": "markdown",
"id": "f710931f",
"metadata": {},
"source": [
"### Optionally load saved responses"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b1d98850",
"metadata": {},
"outputs": [],
"source": [
"responses = []\n",
"\n",
"for site in df_site:\n",
" with open(os.path.join(outputs_path, site + \".json\"), 'r') as fp:\n",
" responses.append(json.load(fp))"
]
},
{
"cell_type": "markdown",
"id": "57f63ebb",
"metadata": {},
"source": [
"### Summarizing multiple scenario results\n",
"\n",
"There are two options for making a summary of multiple scenarios' resutls:\n",
"1. Write to a csv using a template with column headers for desired summary keys (scalar values only)\n",
"2. Write all inputs, outputs, and dispatch to an Excel spreadsheet\n",
"^^TBD\n",
"3. Use the `generation_results_table` endpoint to create a summary Excel\n"
]
},
{
"cell_type": "markdown",
"id": "e7cd3a5c",
"metadata": {},
"source": [
"#### Option 1: Use a template CSV to collect certain results"
]
},
{
"cell_type": "raw",
"id": "f78b226d",
"metadata": {},
"source": [
"from src.parse_api_responses_to_csv import parse_responses_to_csv_with_template\n",
"\n",
"parse_responses_to_csv_with_template(\n",
" csv_template=output_template, \n",
" responses=responses, \n",
" output_csv=output_file, \n",
" input_csv=path_to_inputs,\n",
" n_custom_columns=2\n",
")"
]
},
{
"cell_type": "raw",
"id": "1c77162f",
"metadata": {},
"source": [
"#### Option 2: Write all results out to an Excel file"
]
},
{
"cell_type": "raw",
"id": "3b11e792",
"metadata": {},
"source": [
"from src.parse_api_responses_to_excel import parse_api_responses_to_excel\n",
"\n",
"parse_api_responses_to_excel(responses, template=output_file_spreadsheet_template, spreadsheet=output_file_spreadsheet)"
]
},
{
"cell_type": "markdown",
"id": "c321502f",
"metadata": {},
"source": [
"#### Option 3: Use Results Spreadsheet API endpoint\n",
"/job/generate_results_table - takes a list of run_uuid's and creates a results table spreadsheet to download in response"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6c451d7a",
"metadata": {},
"outputs": [],
"source": [
"run_uuids = []\n",
"for response in responses:\n",
" run_uuids.append(response[\"run_uuid\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c6f3fa78",
"metadata": {},
"outputs": [],
"source": [
"# Construct the URL with run_uuid[] as query parameters\n",
"results_url = f\"{root_url}/job/generate_results_table/?api_key={API_KEY}&table_config_name=custom_table_webtool\"\n",
"\n",
"for i, uuid in enumerate(run_uuids):\n",
" results_url += f\"&run_uuid%5B{i}%5D={uuid}\"\n",
"\n",
"print(f\"Requesting custom comparison table from: {results_url}\")\n",
"\n",
"try:\n",
" # Make the GET request to retrieve the final comparison table\n",
" response = requests.get(results_url)\n",
" response.raise_for_status() # Raise an exception for HTTP errors\n",
"\n",
" # Check the response and save the Excel file\n",
" if response.status_code == 200:\n",
" os.makedirs(results_summary_path, exist_ok=True)\n",
" output_path = os.path.join(results_summary_path, f'{uuid}-results-table.xlsx')\n",
" \n",
" with open(output_path, \"wb\") as o:\n",
" o.write(response.content)\n",
" print(f\"File saved to {output_path}\")\n",
" else:\n",
" print(f\"Request failed with status code {response.status_code}: {response.text}\")\n",
"except requests.exceptions.RequestException as e:\n",
" print(f\"Request failed: {e}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5a6e3fc0",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"@webio": {
"lastCommId": null,
"lastKernelId": null
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
1 change: 1 addition & 0 deletions REopt API Scripts/outputs/results_template.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Financial | npv,PV|size_kw,Storage|size_kw,Storage|size_kwh
1 change: 1 addition & 0 deletions REopt API Scripts/outputs/site_1.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions REopt API Scripts/outputs/site_2.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions REopt API Scripts/outputs/site_3.json

Large diffs are not rendered by default.

Binary file not shown.