Skip to content

Commit

Permalink
fixed base-case bug, included shell run files for base case
Browse files Browse the repository at this point in the history
  • Loading branch information
ebalogun01 committed Dec 28, 2023
1 parent 99e7baa commit 15668c6
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 77 deletions.
28 changes: 18 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,27 +176,35 @@ from the simulation.

## How to run

For quick-run, it is recommended to use MacOS or Linux. All Native Windows from windows 11 come with WSL2. Older windows
users can install WSL2. See [here](https://docs.microsoft.com/en-us/windows/wsl/install-win10) for more details.

1. If you do not have conda installed and want to use conda, please follow the instructions [here](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html) to install conda.

2. Create a new environment using `conda env create --name <your env name> -f environment.yml`OR
install packages listed in the environment manually. You can also use the `requirements.txt` file to install the required packages or use [pip](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/).
install packages listed in the environment manually. You can also use the `requirements.txt` file and [pip](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/) to install the required packages.

3. Ensure gridlabd is installed by following recommended installation method if using the online (MPC) power system co-simulation functionality.

4. For offline (One-shot) optimization simulation (Does not require GridLAB-D install):
* Open the `default_user_inputs.json` file in the root folder and modify the parameters as needed. The prepopulated
fields can be modified. Once the fields are modified as desired, navigate to `app.py` which is also in the root directory. Make sure the *test* is set to *False* (see below) in the `app.py` file.

<img src="doc_images/app_run_readme.png" width="300">

Then run `app.py`. This will run the simulation and generate the results in the `results` folder under the `analysis` directory. To perform post-simulation cost
analysis, navigate to the `analysis` folder and run `load_post_opt_costs.py`. This will generate the cost analysis plots and tables in the `analysis` folder.
* **If using Unix based system or Windows Subsystem for Linux (WSL)**: Open the `default_user_inputs.json` file in the root folder and modify the parameters as needed. The prepopulated
fields can be modified. To open WSL, you can open the command line interface or terminal and type `wsl` Once the
fields are modified as desired, run `python3 evecosim.py --mode=oneshot` or `python3 evecosim.py --mode oneshot` or
`python3 evecosim.py` in the root directory. This will run the simulation and generate the results in the `results`
folder under the `analysis` directory. After which the platform will generate the cost analysis plots and tables in
the `analysis` folder.
* **If using Native Windows**: TODO

5. For online MPC battery test case (Requires GridLAB-D install):
* Navigate to `test_cases/battery/feeder_population` and run `feeder_population_collocated.py` for collocated (DEFAULT) case or `feeder_population_centralized.py`. This uses the
* **If using Unix based system or Windows Subsystem for Linux (WSL) [RECOMMENDED]**: Open the `default_user_inputs.json` file in the root folder and modify the parameters as needed. The prepopulated
fields can be modified. To open WSL, you can open the command line interface or terminal and type `wsl`. Once the
fields are modified as desired, and you are in the project root directory, in the terminal,
type: `python3 evecosim.py --mode=mpc-grid` or `python3 evecosim.py --mode mpc-grid` and let the simulation run.

* **If using Native Windows**: Navigate to `test_cases/battery/feeder_population` and run `feeder_population_collocated.py` for collocated (DEFAULT) case or `feeder_population_centralized.py`. This uses the
`test_cases/battery/feeder_population/config.txt` settings to prepare the power system and populate the secondary
distribution network with time-varying base loads, EV charging stations, Distributed Energy Resources (DERs - Solar, Storage), and required transformers.
* Once confirmed that `feeder_population_<CASE_TYPE>.py` (CASE_TYPE is either collocated or centralized) has run successfully and generates the required `IEEE123_secondary.glm` and
* Once confirmed that `feeder_population_<CASE_TYPE>.py` (CASE_TYPE is either collocated or centralized but only collocated is supported at this time) has run successfully and generates the required `IEEE123_secondary.glm` and
`IEEE123_populated.glm` files, you are done with the initial pre-simulation run preparation.
* Now navigate one level of out `/feeder_population` and run scenarios.py using `python3 scenarios.py` or `gridlabd python scenarios.py` (recommended).

Expand Down
12 changes: 10 additions & 2 deletions evecosim.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,28 @@ def run_oneshot_opt():
return


def run_grid_base_case():
subprocess.call(['sh', './shell_scripts/run-basecase-grid.sh'])
return


def main(mode):
if mode == 'oneshot':
run_oneshot_opt()
elif mode == 'mpc-grid':
run_mpc_grid_collocated()
elif mode == 'base-case-grid':
run_grid_base_case()
elif mode == 'mpc-grid-central':
raise NotImplementedError
else:
raise ValueError(f'Invalid mode: {mode}. Please choose from: oneshot, mpc-grid')
raise ValueError(f'Invalid mode: {mode}. Please choose from: oneshot, mpc-grid, base-case-grid')


if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--mode', type=str, default='oneshot',
help='This flag only included for testing deployment, do not change.')
help='Oneshot (offline) optimization mode is default. '
'Choose from: oneshot, mpc-grid, base-case-grid')
args = parser.parse_args()
main(args.mode)
37 changes: 37 additions & 0 deletions shell_scripts/run-basecase-grid.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/sh

#!/bin/sh

cd test_cases/base_case/feeder_population || exit

python_file="feeder_population.py"
text_file="config.txt"

timestamp_file="exec_timestamp.txt"

# Function to get the last run time
get_last_run_time() {
if [ -e "$timestamp_file" ]; then
cat "$timestamp_file"
else
echo 0
fi
}

# Get the modification times of the files
text_file_time=$(stat -c %Y "$text_file")
last_run_time=$(get_last_run_time)
#printf "Text file time: %s\n" "$(date -d @"$text_file_time")"
#printf "Last run time: %s\n" "$(date -d @"$last_run_time")"

# Compare the modification times
if [ "$text_file_time" -gt "$last_run_time" ]; then
echo "Feeder config text file has been modified. Running feeder population..."
date +%s > "$timestamp_file"
python3 "$python_file"
else
echo "No feeder pop config changes detected. Feeder population will not be run."
fi

cd .. || exit
gridlabd python master_sim.py
2 changes: 1 addition & 1 deletion shell_scripts/run-mpc-grid-central.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ else
fi

cd .. || exit
gridlabd python scenarios.py --scenario 1
gridlabd python scenarios.py
2 changes: 1 addition & 1 deletion shell_scripts/run-mpc-grid.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ else
fi

cd .. || exit
gridlabd python scenarios.py --scenario 1
gridlabd python scenarios.py
12 changes: 9 additions & 3 deletions test_cases/base_case/event_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@
# will later remove some import flags but leaving here for potential debugging

# get the desired path prefix
path_prefix = os.getcwd()
path_prefix = path_prefix[0:path_prefix.index('EV50_cosimulation')] + 'EV50_cosimulation'
path_prefix.replace('\\', '/')
path_prefix = str(os.getcwd())
os.chdir(path_prefix) # change directory
# Splitting the path is different for Windows and Linux/MacOS.
if '\\' in path_prefix:
path_prefix = "/".join(
path_prefix.split('\\')[:-2]) # Gets absolute path to the root of the project to get the desired files.
else:
path_prefix = "/".join(path_prefix.split('/')[:-2])

save_folder_prefix = 'June_test/'
num_charging_nodes = 0 # needs to come in as input initially & should be initialized prior from the feeder population
central_storage = False # toggle for central vs. decentralized storage
Expand Down
9 changes: 5 additions & 4 deletions test_cases/base_case/feeder_population/feeder_population.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ def main():
feeder_name = param_dict['feeder_name']
set_sd = param_dict['set_sd']
mean_scale = param_dict['mean_scale']
base_file_dir = path_prefix + param_dict['base_file_dir']
test_case_dir = path_prefix + param_dict['test_case_dir']
load_data_dir = path_prefix + param_dict['load_data_dir']
base_file_dir = f'{path_prefix}/{param_dict["base_file_dir"]}'
test_case_dir = f'{path_prefix}/{param_dict["test_case_dir"]}'
load_data_dir = f'{path_prefix}/{param_dict["load_data_dir"]}'
base_load_file = f'{param_dict["base_load_file"]}'
box_pts = param_dict['box_pts']
starttime_str = param_dict['starttime']
endtime_str = param_dict['endtime']
Expand Down Expand Up @@ -263,7 +264,7 @@ def main():
# % load residential load data

os.chdir(load_data_dir)
data_use = pandas.read_csv('data_2015_use.csv')
data_use = pandas.read_csv(base_load_file)

year = 2018

Expand Down
91 changes: 45 additions & 46 deletions test_cases/base_case/gblvar.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,53 @@
# TODO: remove this file, it is not going to be required anymore.

# import numpy as np
# import pandas as pd
# import pickle
import numpy as np
import pandas as pd
import pickle
#
# # define global python simulation variables and default initial values
#
# # iteration number
# it = 0 # what does this mean?
#
# # power flow timestep
# pf_dt = 60
#
# # uncontrollable load profiles
# p_df = pd.read_csv('real_power.csv')
# q_df = pd.read_csv('reactive_power.csv')
# print("Done reading base power files")
#
# p_array = np.asarray(p_df)
# q_array = np.asarray(q_df)
#
# # voltage objects and properties
# with open('voltage_obj.txt', 'rb') as fp:
# voltage_obj = pickle.load(fp)
# with open('voltage_prop.txt', 'rb') as fp:
# voltage_prop = pickle.load(fp)
# vm = np.zeros((1, len(voltage_obj)))
# vp = np.zeros((1, len(voltage_obj)))
# v_pred = np.zeros((1, len(voltage_obj)))
# define global python simulation variables and default initial values

# iteration number
it = 0

# power flow timestep
pf_dt = 60

# uncontrollable load profiles
p_df = pd.read_csv('real_power.csv')
q_df = pd.read_csv('reactive_power.csv')
print("Done reading base power files")

p_array = np.asarray(p_df)
q_array = np.asarray(q_df)
#
# voltage objects and properties
with open('voltage_obj.txt', 'rb') as fp:
voltage_obj = pickle.load(fp)
with open('voltage_prop.txt', 'rb') as fp:
voltage_prop = pickle.load(fp)
vm = np.zeros((1, len(voltage_obj)))
vp = np.zeros((1, len(voltage_obj)))
v_pred = np.zeros((1, len(voltage_obj)))
#
# ####################### RESOURCE PROPERTIES ################################
# # move to other file format, maybe json, generated from feeder population code
#
# # transformer properties
# trans_dt = 10.0 # integration timestep [seconds]?
# trans_Ta = 20.0 # ambient temperature[C]
#
# # TODO: find where all these transformer values were obtained from
# trans_R = 5.0 # ratio of copper loss to iron loss at rated load
# trans_tau_o = 2 * 60 * 60.0 # top oil time constant in seconds
# trans_tau_h = 6 * 60.0 # hotspot time constant in seconds
# trans_n = 0.9 # how did we get these numbers ?
# trans_m = 0.8 # how did we get these numbers ?
# trans_delta_theta_hs_rated = 28.0
# trans_delta_theta_oil_rated = 36.0
#
# trans_To0 = 30.0 # initial oil temperature [C]
# trans_Th0 = 60.0 # initial hot spot temperature [C] # How is this set?
# trans_int_method = 'euler' # integration method ['euler' or 'RK4']
#
# move to other file format, maybe json, generated from feeder population code

# transformer properties
trans_dt = 10.0 # integration timestep [seconds]?
trans_Ta = 20.0 # ambient temperature[C]

trans_R = 5.0 # ratio of copper loss to iron loss at rated load
trans_tau_o = 2 * 60 * 60.0 # top oil time constant in seconds
trans_tau_h = 6 * 60.0 # hotspot time constant in seconds
trans_n = 0.9 # how did we get these numbers ?
trans_m = 0.8 # how did we get these numbers ?
trans_delta_theta_hs_rated = 28.0
trans_delta_theta_oil_rated = 36.0

trans_To0 = 30.0 # initial oil temperature [C]
trans_Th0 = 60.0 # initial hot spot temperature [C] # How is this set?
trans_int_method = 'euler' # integration method ['euler' or 'RK4']

# # Battery properties
#
# bat_soc0 = 0.5
Expand Down
2 changes: 1 addition & 1 deletion test_cases/base_case/master_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import gridlabd
import sys
sys.path.append('../../../EV50_cosimulation/charging_sim')
sys.path.append('../../charging_sim')

print('Starting GridLAB-D')
gridlabd.command("IEEE123_populated.glm")
Expand Down
14 changes: 7 additions & 7 deletions test_cases/battery/IEEE123_secondary.glm
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ object load {

object transformer {
name dcfc_trans_0;
phases "ABCD";
from "meter_76";
phases "ABCN";
from "meter_55";
to dcfc_load_0;
configuration dcfc_transformer;
}
Expand All @@ -69,7 +69,7 @@ object load {
object transformer {
name dcfc_trans_1;
phases "ABCN";
from "meter_79";
from "meter_80";
to dcfc_load_1;
configuration dcfc_transformer;
}
Expand All @@ -86,8 +86,8 @@ object load {

object transformer {
name dcfc_trans_2;
phases "ABC";
from "meter_62";
phases "ABCN";
from "meter_60";
to dcfc_load_2;
configuration dcfc_transformer;
}
Expand All @@ -104,8 +104,8 @@ object load {

object transformer {
name dcfc_trans_3;
phases "ABCN";
from "meter_86";
phases "ABC";
from "meter_62";
to dcfc_load_3;
configuration dcfc_transformer;
}
Expand Down
2 changes: 1 addition & 1 deletion test_cases/battery/event_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

path_prefix = str(os.getcwd())
os.chdir(path_prefix) # change directory
# Splitting the path is different for Windows and Linux/MacOS. Need condition to deal with both OS file path styles.
# Splitting the path is different for Windows and Linux/MacOS.
if '\\' in path_prefix:
path_prefix = "/".join(
path_prefix.split('\\')[:-2]) # Gets absolute path to the root of the project to get the desired files.
Expand Down
2 changes: 1 addition & 1 deletion test_cases/battery/feeder_population/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'endtime': "'2018-07-30 23:59:00'",
'python_module': 'event_handlers',
'safety_factor': 0.1,
'dcfc_charging_stall_base_rating': '75_kW',
'dcfc_charging_stall_base_rating': '75_kW_kW',
'l2_charging_stall_base_rating': '11.5_kW',
'num_dcfc_nodes': 4,
'num_l2_nodes': 0,
Expand Down

0 comments on commit 15668c6

Please sign in to comment.