diff --git a/__pycache__/constants.cpython-311.pyc b/__pycache__/constants.cpython-311.pyc new file mode 100644 index 0000000..8bccd78 Binary files /dev/null and b/__pycache__/constants.cpython-311.pyc differ diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..a69fb64 --- /dev/null +++ b/constants.py @@ -0,0 +1,123 @@ +import os +import pandas as pd +from datetime import datetime, timedelta +from calendar import month_abbr + + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__))) + +def str_to_bool(val, default=False): + if isinstance(val, str) and (val in os.environ): + return True if os.environ[val] == 'True' else False + else: + return default + +# Scenario setup +location = 'NY' +multi_home_sim = False # whether doing cosim on more than 1 home +if not multi_home_sim: + house_number = 1 + house_number_list = None + scenario_name = location + '_house_' + str(house_number) +else: + house_number = None + house_number_list = [1] + scenario_name = location + '_multi_home_sim' + + +# COsim date range, and timestep +year = 2007 +month = "Aug" # enumeration Jan, May, or Aug +month_num = list(month_abbr).index(month) +start_date = 25 +start_time = datetime(year, month_num, start_date, 0, 0) # (Year, Month, Day, Hour, Min) +duration = timedelta(days=7) +time_step = timedelta(minutes = 1) +end_time = start_time + duration +sim_times = pd.date_range(start=start_time, end=end_time, freq=time_step)[:-1] # timestamps of cosim + + +# What Agents are included? Agents for ochre house model and hems +include_house = True +include_hems = True + +# Frequency of Updates +freq_house = timedelta(minutes=1) +freq_hems = timedelta(minutes=15) #HEMS model aggregates data to this timestep. Should be greater than house frequency +freq_save_results = timedelta(minutes=5) + +# Time offsets for communication order +offset_house_run = timedelta(seconds=0) +offset_hems_to_house = timedelta(seconds=60) +offset_house_to_hems = timedelta(seconds=60) +offset_save_results = timedelta(0) + +# House Variables +house_battery_schedule = 'TOU' + +# HEMS Variables +hems_scenario = 'foresee' +hems_horizon = timedelta(hours=12) # 12 hours / 15 min frequency = 180 time steps + +# Input/Output file paths +input_path = os.path.join(base_path, "inputs") +output_path = os.path.join(base_path, "outputs") +baseline_output_path = os.path.join(base_path, "outputs", location) + +ochre_input_path = os.path.join(input_path, "ochre") +foresee_input_path = os.path.join(input_path, "foresee") + + +house_args_file_name = location + '_houses.xlsx' +house_args_file = os.path.join(input_path, 'house_args', house_args_file_name) + +# Output file locations +house_results_path = os.path.join(output_path, location, 'ochre') +house_results_file = os.path.join(house_results_path, '{}_out.csv') +hems_results_path = os.path.join(output_path, location, 'foresee') + +# Load house args spread sheed +df_house_args = pd.read_excel(house_args_file, skiprows= 1, index_col='Bldg_ID') +if not multi_home_sim: + house_id = 'house_' + str(house_number) +in_real_time = str_to_bool(['REAL_TIME']) +debug = False + +#store all sim parameters in dictionary +dict_sim_params = { + 'base_path': base_path, + 'in_real_time': in_real_time, + 'debug': debug, + 'location': location, + 'multi_home_sim': multi_home_sim, + 'house_number': house_number, + 'house_number_list': house_number_list, + 'scenario_name': scenario_name, + 'month': month, + 'start_time': start_time, + 'end_time': end_time, + 'duration': duration, + 'time_step': time_step, + 'sim_times': sim_times, + 'include_house': include_house, + 'include_hems': include_hems, + 'freq_house': freq_house, + 'freq_hems': freq_hems, + 'freq_save_results': freq_save_results, + 'offset_house_run': offset_house_run, + 'offset_hems_to_house': offset_hems_to_house, + 'offset_house_to_hems': offset_house_to_hems, + 'offset_save_results': offset_save_results, + 'house_battery_schedule': house_battery_schedule, + 'hems_scenario': hems_scenario, + 'hems_horizon': hems_horizon, + 'input_path': input_path, + 'output_path': output_path, + 'baseline_output_path': baseline_output_path, + 'ochre_input_path': ochre_input_path, + 'foresee_input_path': foresee_input_path, + 'house_results_path': house_results_path, + 'house_results_file': house_results_file, + 'hems_results_path': hems_results_path, + 'df_house_args': df_house_args, +} \ No newline at end of file diff --git a/inputs/house_args/NY_houses.xlsx b/inputs/house_args/NY_houses.xlsx new file mode 100644 index 0000000..70d109c Binary files /dev/null and b/inputs/house_args/NY_houses.xlsx differ diff --git a/inputs/house_args/~$NY_houses.xlsx b/inputs/house_args/~$NY_houses.xlsx new file mode 100644 index 0000000..df038b4 Binary files /dev/null and b/inputs/house_args/~$NY_houses.xlsx differ diff --git a/inputs/ochre/bldg0000072-up00.xml b/inputs/ochre/bldg0000072-up00.xml new file mode 100644 index 0000000..811fde8 --- /dev/null +++ b/inputs/ochre/bldg0000072-up00.xml @@ -0,0 +1,1258 @@ + + + + HPXML + BuildResidentialHPXML + 2024-08-11T08:38:34-06:00 + create + + + ResStock + 3.2.0 + + + 15 + 1 + 1 + 12 + 31 + 2018 + 1.0 + + + + LRMER_LowRECost_15 + CO2e + + electricity + kg/MWh + /lib/resources/data/cambium/2022/LRMER_LowRECost_15/RFCEc.csv + 0 + 1 + + + natural gas + lb/MBtu + 147.3 + + + + LRMER_MidCase_15 + CO2e + + electricity + kg/MWh + /lib/resources/data/cambium/2022/LRMER_MidCase_15/RFCEc.csv + 0 + 1 + + + natural gas + lb/MBtu + 147.3 + + + + LRMER_HighRECost_15 + CO2e + + electricity + kg/MWh + /lib/resources/data/cambium/2022/LRMER_HighRECost_15/RFCEc.csv + 0 + 1 + + + natural gas + lb/MBtu + 147.3 + + + + LRMER_MidCase_25 + CO2e + + electricity + kg/MWh + /lib/resources/data/cambium/2022/LRMER_MidCase_25/RFCEc.csv + 0 + 1 + + + natural gas + lb/MBtu + 147.3 + + + + + + Utility Rates - Fixed + Variable + + electricity + 12.0 + 0.15102236286919832 + + + natural gas + 11.25 + 0.827375004 + + + propane + 0.0 + 3.440384615 + + + fuel oil + 0.0 + 3.247884615 + + + + + + + + + +
+ NJ + 07960 +
+ + -5.0 + true + + 3 + 12 + 11 + 5 + + +
+ + proposed workscope + + + + + suburban + stand-alone + no units above or below + normal + 225 + + 1.1 + + 0.02288 + + + + + + northwest + 315 + 15.0 + + + southeast + 135 + 15.0 + + + + + + 2.0 + + 0.061, 0.061, 0.061, 0.061, 0.061, 0.061, 0.061, 0.053, 0.025, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.018, 0.033, 0.054, 0.054, 0.054, 0.061, 0.061, 0.061 + 0.061, 0.061, 0.061, 0.061, 0.061, 0.061, 0.061, 0.053, 0.025, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.018, 0.033, 0.054, 0.054, 0.054, 0.061, 0.061, 0.061 + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 + + + + 1940 + single-family detached + 1 + 1.0 + 1.0 + 8.0 + 4 + 2 + 1228.0 + 9824.0 + + + + ACCA + false + + 14.54 + 89.78 + 70.0 + 75.0 + 0.5 + 2400.0 + 0.0 + 5 + + + 3 + + 5 + 1 + 9 + 30 + + + 38 + + /var/simdata/openstudio/run/schedules.csv + + + + + 2006 + 5A + + + + G3400270 + + ../../../weather/G3400270.epw + + + + + + + + 50.0 + + ACH + 30.0 + + 9824.0 + 8.0 + + + false + + + + + + + + true + + + + SLA + 0.003333 + + + + + + + + + + + + + + true + + + + SLA + 0.006667 + + + + + + + + + + + + + + + + + attic - vented + 686.5 + northeast + 45 + asphalt or fiberglass shingles + medium + 0.85 + 0.9 + + none + + 6.0 + false + + + 2.3 + + + + + attic - vented + 686.5 + southwest + 225 + asphalt or fiberglass shingles + medium + 0.85 + 0.9 + + none + + 6.0 + false + + + 2.3 + + + + + + + outside + crawlspace - vented + 36.2 + northeast + 45 + vinyl siding + light + 0.5 + 0.9 + + + 3.1 + + + + + outside + crawlspace - vented + 20.1 + southeast + 135 + vinyl siding + light + 0.5 + 0.9 + + + 3.1 + + + + + outside + crawlspace - vented + 36.2 + southwest + 225 + vinyl siding + light + 0.5 + 0.9 + + + 3.1 + + + + + outside + crawlspace - vented + 20.1 + northwest + 315 + vinyl siding + light + 0.5 + 0.9 + + + 3.1 + + + + + + + outside + conditioned space + + + + 376.1 + northeast + 45 + vinyl siding + light + 0.5 + 0.9 + + gypsum board + 0.5 + + false + + + 4.0 + + + + + outside + conditioned space + + + + 209.0 + southeast + 135 + vinyl siding + light + 0.5 + 0.9 + + gypsum board + 0.5 + + false + + + 4.0 + + + + + outside + conditioned space + + + + 376.1 + southwest + 225 + vinyl siding + light + 0.5 + 0.9 + + gypsum board + 0.5 + + false + + + 4.0 + + + + + outside + conditioned space + + + + 209.0 + northwest + 315 + vinyl siding + light + 0.5 + 0.9 + + gypsum board + 0.5 + + false + + + 4.0 + + + + + outside + attic - vented + gable + + + + 85.3 + southeast + 135 + vinyl siding + light + 0.5 + 0.9 + + none + + false + + + 4.0 + + + + + outside + attic - vented + gable + + + + 85.3 + northwest + 315 + vinyl siding + light + 0.5 + 0.9 + + none + + false + + + 4.0 + + + + + + + ground + crawlspace - vented + solid concrete + 4.0 + 188.1 + northeast + 45 + 8.0 + 3.0 + + none + + + + + continuous - exterior + 0.0 + 0.0 + 4.0 + + + continuous - interior + 0.0 + 0.0 + 4.0 + + + + + + ground + crawlspace - vented + solid concrete + 4.0 + 104.5 + southeast + 135 + 8.0 + 3.0 + + none + + + + + continuous - exterior + 0.0 + 0.0 + 4.0 + + + continuous - interior + 0.0 + 0.0 + 4.0 + + + + + + ground + crawlspace - vented + solid concrete + 4.0 + 188.1 + southwest + 225 + 8.0 + 3.0 + + none + + + + + continuous - exterior + 0.0 + 0.0 + 4.0 + + + continuous - interior + 0.0 + 0.0 + 4.0 + + + + + + ground + crawlspace - vented + solid concrete + 4.0 + 104.5 + northwest + 315 + 8.0 + 3.0 + + none + + + + + continuous - exterior + 0.0 + 0.0 + 4.0 + + + continuous - interior + 0.0 + 0.0 + 4.0 + + + + + + + + crawlspace - vented + conditioned space + floor + + + + 1228.0 + + none + + false + + + 5.3 + + + + + attic - vented + conditioned space + ceiling + + + + 1228.0 + + gypsum board + 0.5 + + false + + + 39.6 + + + + + + + crawlspace - vented + 1228.0 + 0.0 + 146.3 + + + + 0.0 + 0.0 + + + + + + 0.0 + 0.0 + + + + 0.0 + 0.0 + + + + + + + 112.8 + 45 + northeast + 0.38 + 0.44 + + + 1.0 + 1.0 + + + + 0.7 + 0.85 + + + 2.0 + 1.0000000000000009 + 4.9 + + 0.67 + + + + + 62.7 + 135 + southeast + 0.38 + 0.44 + + + 1.0 + 1.0 + + + + 0.7 + 0.85 + + + 2.0 + 1.0000000000000009 + 4.7 + + 0.67 + + + + + 112.8 + 225 + southwest + 0.38 + 0.44 + + + 1.0 + 1.0 + + + + 0.7 + 0.85 + + + 2.0 + 1.0000000000000009 + 4.9 + + 0.67 + + + + + 62.7 + 315 + northwest + 0.38 + 0.44 + + + 1.0 + 1.0 + + + + 0.7 + 0.85 + + + 2.0 + 1.0000000000000009 + 4.7 + + 0.67 + + + + + + + + 20.0 + 225 + southwest + 5.0 + + + + + 1.0 + + gypsum board + 0.5 + + + + 0.4 + light-weight + + + + + + + + + + + + + crawlspace - vented + + + + false + + + natural gas + 66458.0 + + AFUE + 0.8 + + 1.0 + + 0.5 + 0.0 + 1209.0 + + + + + crawlspace - vented + + central air conditioner + electricity + 34552.0 + single stage + 1.0 + + SEER + 13.0 + + 0.73 + + 0.0 + 0.0 + 0.5 + 1167.0 + 50.0 + + + + + + 66458.0 + 17699.0 + 7397.0 + 0.0 + 222.0 + 11081.0 + 0.0 + 6780.0 + 0.0 + 1720.0 + 21559.0 + + + 26949.0 + 4953.0 + 8492.0 + 0.0 + 103.0 + 3892.0 + 0.0 + 1807.0 + 0.0 + 1234.0 + 2918.0 + 3550.0 + + + 6215.0 + 937.0 + 4277.0 + 1000.0 + + + + + + + + 1 + 1 + 12 + 31 + + + 1 + 1 + 12 + 31 + + + 0.0 + 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0 + 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0 + 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0 + 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0, 68.0 + + + + + + + regular velocity + + supply + + Percent + 0.067 + to outside + + + + return + + Percent + 0.033 + to outside + + + + + supply + 0.0 + not buried + 1.7 + crawlspace - vented + 1.0 + 331.56 + + 1.0 + + + + + return + 0.0 + not buried + 1.7 + crawlspace - vented + 1.0 + 61.400000000000006 + + 1.0 + + + 1 + + + 1228.0 + + + + + + + 1 + 100.0 + 1.0 + kitchen + true + 30.0 + + 16 + + + + + 2 + 50.0 + 1.0 + bath + true + 15.0 + + 17 + + + + + + + + natural gas + instantaneous water heater + conditioned space + false + 0.92 + 1.0 + 0.82 + 125.0 + + + + + + 80.08566187174092 + + + + 0.0 + + + + + shower head + false + + + + faucet + false + + + 0.5 + 0.012, 0.006, 0.004, 0.005, 0.010, 0.034, 0.078, 0.087, 0.080, 0.067, 0.056, 0.047, 0.040, 0.035, 0.033, 0.031, 0.039, 0.051, 0.060, 0.060, 0.055, 0.048, 0.038, 0.026 + 0.012, 0.006, 0.004, 0.005, 0.010, 0.034, 0.078, 0.087, 0.080, 0.067, 0.056, 0.047, 0.040, 0.035, 0.033, 0.031, 0.039, 0.051, 0.060, 0.060, 0.055, 0.048, 0.038, 0.026 + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 + + + + + + + false + conditioned space + 2.07 + 123.0 + 0.1065 + 1.218 + 9.0 + 7.538462 + 3.68 + + 0.8 + 0.009, 0.007, 0.004, 0.004, 0.007, 0.011, 0.022, 0.049, 0.073, 0.086, 0.084, 0.075, 0.067, 0.060, 0.049, 0.052, 0.050, 0.049, 0.049, 0.049, 0.049, 0.047, 0.032, 0.017 + 0.009, 0.007, 0.004, 0.004, 0.007, 0.011, 0.022, 0.049, 0.073, 0.086, 0.084, 0.075, 0.067, 0.060, 0.049, 0.052, 0.050, 0.049, 0.049, 0.049, 0.049, 0.047, 0.032, 0.017 + 1.011, 1.002, 1.022, 1.020, 1.022, 0.996, 0.999, 0.999, 0.996, 0.964, 0.959, 1.011 + + + + + false + conditioned space + natural gas + 2.39 + true + 100.0 + + 0.8 + 0.010, 0.006, 0.004, 0.002, 0.004, 0.006, 0.016, 0.032, 0.048, 0.068, 0.078, 0.081, 0.074, 0.067, 0.057, 0.061, 0.055, 0.054, 0.051, 0.051, 0.052, 0.054, 0.044, 0.024 + 0.010, 0.006, 0.004, 0.002, 0.004, 0.006, 0.016, 0.032, 0.048, 0.068, 0.078, 0.081, 0.074, 0.067, 0.057, 0.061, 0.055, 0.054, 0.051, 0.051, 0.052, 0.054, 0.044, 0.024 + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 + + + + + false + conditioned space + 290.0 + 12 + 0.12 + 1.09 + 23.0 + 4.0 + + 0.8 + 0.015, 0.007, 0.005, 0.003, 0.003, 0.010, 0.020, 0.031, 0.058, 0.065, 0.056, 0.048, 0.041, 0.046, 0.036, 0.038, 0.038, 0.049, 0.087, 0.111, 0.090, 0.067, 0.044, 0.031 + 0.015, 0.007, 0.005, 0.003, 0.003, 0.010, 0.020, 0.031, 0.058, 0.065, 0.056, 0.048, 0.041, 0.046, 0.036, 0.038, 0.038, 0.049, 0.087, 0.111, 0.090, 0.067, 0.044, 0.031 + 1.097, 1.097, 0.991, 0.987, 0.991, 0.890, 0.896, 0.896, 0.890, 1.085, 1.085, 1.097 + + + + + conditioned space + 433.0 + true + + 0.95 + 0.040, 0.039, 0.038, 0.037, 0.036, 0.036, 0.038, 0.040, 0.041, 0.041, 0.040, 0.040, 0.042, 0.042, 0.042, 0.041, 0.044, 0.048, 0.050, 0.048, 0.047, 0.046, 0.044, 0.041 + 0.040, 0.039, 0.038, 0.037, 0.036, 0.036, 0.038, 0.040, 0.041, 0.041, 0.040, 0.040, 0.042, 0.042, 0.042, 0.041, 0.044, 0.048, 0.050, 0.048, 0.047, 0.046, 0.044, 0.041 + 0.837, 0.835, 1.084, 1.084, 1.084, 1.096, 1.096, 1.096, 1.096, 0.931, 0.925, 0.837 + + + + + conditioned space + natural gas + false + + 0.8 + 0.007, 0.007, 0.004, 0.004, 0.007, 0.011, 0.025, 0.042, 0.046, 0.048, 0.042, 0.050, 0.057, 0.046, 0.057, 0.044, 0.092, 0.150, 0.117, 0.060, 0.035, 0.025, 0.016, 0.011 + 0.007, 0.007, 0.004, 0.004, 0.007, 0.011, 0.025, 0.042, 0.046, 0.048, 0.042, 0.050, 0.057, 0.046, 0.057, 0.044, 0.092, 0.150, 0.117, 0.060, 0.035, 0.025, 0.016, 0.011 + 1.097, 1.097, 0.991, 0.987, 0.991, 0.890, 0.896, 0.896, 0.890, 1.085, 1.085, 1.097 + + + + + false + + + + + + interior + 0.0 + + + + + + + interior + 0.0 + + + + + + + interior + 1.0 + + + + + + + exterior + 0.0 + + + + + + + exterior + 0.0 + + + + + + + exterior + 1.0 + + + + + + + + medium + 70.4 + + 1 + + 0.057, 0.057, 0.057, 0.057, 0.057, 0.057, 0.057, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.057, 0.057, 0.057, 0.057, 0.057, 0.057 + 0.057, 0.057, 0.057, 0.057, 0.057, 0.057, 0.057, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.057, 0.057, 0.057, 0.057, 0.057, 0.057 + 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0 + + + + 1.0 + 1.0 + 1.0 + 0.046, 0.046, 0.046, 0.046, 0.046, 0.037, 0.035, 0.034, 0.033, 0.028, 0.022, 0.015, 0.012, 0.011, 0.011, 0.012, 0.019, 0.037, 0.049, 0.065, 0.091, 0.105, 0.091, 0.063 + 0.046, 0.046, 0.045, 0.045, 0.046, 0.045, 0.044, 0.041, 0.036, 0.03, 0.024, 0.016, 0.012, 0.011, 0.011, 0.012, 0.019, 0.038, 0.048, 0.06, 0.083, 0.098, 0.085, 0.059 + 1.248, 1.257, 0.993, 0.989, 0.993, 0.827, 0.821, 0.821, 0.827, 0.99, 0.987, 1.248 + + + + + + other + + kWh/year + 2109.23 + + + 0.93 + 0.021 + 0.505 + 0.035, 0.033, 0.032, 0.031, 0.032, 0.033, 0.037, 0.042, 0.043, 0.043, 0.043, 0.044, 0.045, 0.045, 0.044, 0.046, 0.048, 0.052, 0.053, 0.05, 0.047, 0.045, 0.04, 0.036 + 0.035, 0.033, 0.032, 0.031, 0.032, 0.033, 0.037, 0.042, 0.043, 0.043, 0.043, 0.044, 0.045, 0.045, 0.044, 0.046, 0.048, 0.052, 0.053, 0.05, 0.047, 0.045, 0.04, 0.036 + 1.248, 1.257, 0.993, 0.989, 0.993, 0.827, 0.821, 0.821, 0.827, 0.99, 0.987, 1.248 + + + + +
+
\ No newline at end of file diff --git a/outputs/NY/bldg0000072-up00_complete b/outputs/NY/bldg0000072-up00_complete new file mode 100644 index 0000000..e69de29 diff --git a/src/run_baseline.py b/src/run_baseline.py new file mode 100644 index 0000000..b7d361e --- /dev/null +++ b/src/run_baseline.py @@ -0,0 +1,117 @@ +import os +import sys +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +import xmltodict +import click +import pandas as pd +from datetime import datetime, timedelta +import shutil +from ochre import Dwelling +from constants import dict_sim_params + +""" +Code for running simulations on OCHRE. + +Author: Alex Lee (alexlee5124@gmail.com) +Date: 4/19/2025 + +""" + + +# Set up input arguments for dwelling +HOUSE_DEFAULT_ARGS = { +# Timing parameters +'start_time': dict_sim_params['start_time'], +'time_res': dict_sim_params['time_step'], +'duration': dict_sim_params['duration'], +'initialization_time': timedelta(days=7), +'ext_time_res': dict_sim_params['freq_hems'], #HEMS model aggregates data to this timestep. Should be greater than house frequency + +# Output settings +'save_results': True, +'output_path': dict_sim_params['baseline_output_path'], +'verbosity': 9, # verbosity of results file (0-9); 8: include envelope; 9: include water heater +'metrics_verbosity': 7, +} + +# Function for extracting weather station name from an HPXML file +def extract_weather_station(file_path): + try: + with open(file_path, 'r', encoding='utf-8') as file: + buildingXML = xmltodict.parse(file.read()) + weather_station_name = buildingXML['HPXML']['Building']['BuildingDetails']['ClimateandRiskZones']['WeatherStation']['Name'] + except Exception as e: + print(f"Error parsing XML {file_path}: {e}") + + return weather_station_name + +def remove_directory(path): + if os.path.exists(path): + try: + shutil.rmtree(path) + except Exception as e: + print(f"Error deleting {path}: {e}") + else: + print(f"The filepath does not exist: {path}") + +@click.command() +@click.argument('building_id', type=int) +@click.argument('upgrade_id', type=int) +def simulate_dwelling( + building_id:int, + upgrade_id:int + ): + """ + simulate: This function runs an OCHRE simulation for a building. It filters the building by the + building id, upgrade id, state, year, and version of the building XML file. You need to have already + downloaded the building XML file prior to running this function. + + Input simulation parameters, such as duration, start date, simulation timestep size, etc. + + Author: Alex Lee (alexlee5124@gmail.com) + Date: 3/29/2025 + """ + + # Update dwelling arguments + house_id = f"bldg{building_id:07}-up{upgrade_id:02}" + house_args = HOUSE_DEFAULT_ARGS.copy() + house_row = dict_sim_params['df_house_args'].loc[house_id] + house_args.update(house_row) + house_args['name'] = f"bldg{building_id:07}-up{upgrade_id:02}" + + # Update input files + # HPXML file + house_args['hpxml_file'] = os.path.join( + dict_sim_params['ochre_input_path'], + house_args['hpxml_file'] + ) + if not os.path.exists(house_args['hpxml_file']): + print(f"HPXML file does not exist: {house_args['hpxml_file']}") + sys.exit(1) + + # Schedule file + house_args['hpxml_schedule_file'] = os.path.join( + dict_sim_params['ochre_input_path'], + house_args['hpxml_schedule_file'] + ) + if not os.path.exists(house_args['hpxml_schedule_file']): + print(f"Schedule file does not exist: {house_args['hpxml_schedule_file']}") + sys.exit(1) + # Weather File + weather_station = f"{extract_weather_station(house_args['hpxml_file'])}.epw" + house_args['weather_file'] = os.path.join( + dict_sim_params['ochre_input_path'], + weather_station + ) + if not os.path.exists(house_args['weather_file']): + print(f"Weather file does not exist: {house_args['weather_file']}") + sys.exit(1) + + try: + dwelling = Dwelling(**house_args) + dwelling.simulate() + except Exception as e: + print(f"Simulation failed for bldg{building_id:07}-up{upgrade_id:02}: {e}") + +if __name__ == '__main__': + simulate_dwelling() \ No newline at end of file diff --git a/src/swap_HP.py b/src/swap_HP.py new file mode 100644 index 0000000..3935a5a --- /dev/null +++ b/src/swap_HP.py @@ -0,0 +1,220 @@ +import os +import sys +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +import xmltodict +import click +import pandas as pd +from datetime import datetime, timedelta +import shutil +from ochre import Dwelling +from constants import dict_sim_params +import json +from ochre.utils import convert, OCHREException, nested_update, load_schedule, update_equipment_properties +from ochre.utils.hpxml import parse_hpxml_occupancy, parse_hpxml_envelope, parse_hpxml_equipment, import_hpxml, load_hpxml +from ochre.Models import Envelope +""" +Code for running simulations on OCHRE. + +Author: Alex Lee (alexlee5124@gmail.com) +Date: 4/19/2025 + +""" + + +# Set up input arguments for dwelling +HOUSE_DEFAULT_ARGS = { +# Timing parameters +'start_time': dict_sim_params['start_time'], +'time_res': dict_sim_params['time_step'], +'duration': dict_sim_params['duration'], +'initialization_time': timedelta(days=1), +'ext_time_res': dict_sim_params['freq_hems'], #HEMS model aggregates data to this timestep. Should be greater than house frequency + +# Output settings +'save_results': True, +'output_path': dict_sim_params['baseline_output_path'], +'verbosity': 9, # verbosity of results file (0-9); 8: include envelope; 9: include water heater +'metrics_verbosity': 7, +} + +# Function for extracting weather station name from an HPXML file +def extract_weather_station(file_path): + try: + with open(file_path, 'r', encoding='utf-8') as file: + buildingXML = xmltodict.parse(file.read()) + weather_station_name = buildingXML['HPXML']['Building']['BuildingDetails']['ClimateandRiskZones']['WeatherStation']['Name'] + except Exception as e: + print(f"Error parsing XML {file_path}: {e}") + + return weather_station_name + +def remove_directory(path): + if os.path.exists(path): + try: + shutil.rmtree(path) + except Exception as e: + print(f"Error deleting {path}: {e}") + else: + print(f"The filepath does not exist: {path}") + +def get_HP_info(HP_id:int): + with open('inputs/equipments/HP.json', 'r') as file: + HP_info = json.load(file) + # Find the heat pump with matching id in the ASHP array + for hp in HP_info['ASHP']: + if hp['id'] == HP_id: + return hp + raise ValueError(f"No heat pump found with id {HP_id}") + +def create_HP_equipment(HP_info:dict, hvac_type:str): + name = HP_info['heat_pump_type'] + fuel = HP_info['fuel_type'] + capacity = HP_info[f'{hvac_type.lower()}_capacity'] + space_fraction = HP_info[f'fraction_{hvac_type.lower()}_load_served'] + efficiency = HP_info[f'annual_{hvac_type.lower()}_efficiency'] + efficiency_string = (f"{HP_info[f'annual_{hvac_type.lower()}_efficiency']} " + f"{HP_info[f'annual_{hvac_type.lower()}_efficiency_units']}") + if HP_info[f'annual_{hvac_type.lower()}_efficiency_units'] in ['Percent', 'AFUE']: + eir = 1 / efficiency + if HP_info[f'annual_{hvac_type.lower()}_efficiency_units'] == 'Percent': + efficiency *= 100 + elif HP_info[f'annual_{hvac_type.lower()}_efficiency_units'] in ['EER', 'SEER', 'HSPF']: + eir = 1 / convert(efficiency, 'Btu/hour', 'W') + else: + raise OCHREException(f'Unknown inputs for HVAC {hvac_type} efficiency: {efficiency}') + + # Get number of speeds + speed_options = { + 'single stage': 1, + 'two stage': 2, + 'variable speed': 4, + } + if name == 'mini-split': + number_of_speeds = 4 # MSHP always variable speed + elif HP_info['compressor_type'] in speed_options: + number_of_speeds = speed_options[HP_info['compressor_type']] + elif convert(1 / eir, 'W', 'Btu/hour') <= 15: + number_of_speeds = 1 # Single-speed for SEER <= 15 + elif convert(1 / eir, 'W', 'Btu/hour') <= 21: + number_of_speeds = 2 # Two-speed for 15 < SEER <= 21 + else: + number_of_speeds = 4 # Variable speed for SEER > 21 + + is_heater = hvac_type == 'Heating' + if is_heater: + shr = None + else: + shr = HP_info['sensible_heat_ratio'] + + if "fan_power_Watts_per_CFM" in HP_info: + # Note: air flow rate is only used for non-dymanic HVAC models with fans, e.g., furnaces + # airflow_cfm = hvac_ext.get(f'{hvac_type}AirflowCFM', 0) + cfm_per_ton = 350 if is_heater else 312 + power_per_cfm = HP_info["fan_power_Watts_per_CFM"] + aux_power = power_per_cfm * cfm_per_ton * convert(capacity, 'W', 'refrigeration_ton') + + HP = { + 'Equipment Name': name, + 'Fuel': fuel.capitalize(), + 'Capacity (W)': capacity, + 'EIR (-)': eir, + 'Rated Efficiency': efficiency_string, + 'SHR (-)': shr, + 'Conditioned Space Fraction (-)': space_fraction, + 'Number of Speeds (-)': number_of_speeds, + 'Rated Auxiliary Power (W)': aux_power, + } + + return HP + + +@click.command() +@click.argument('building_id', type=int) +@click.argument('upgrade_id', type=int) +@click.argument('hp_id', type=int) +def swap_HP( + building_id:int, + upgrade_id:int, + hp_id:int + ): + """ + simulate: This function runs an OCHRE simulation for a building. It filters the building by the + building id, upgrade id, state, year, and version of the building XML file. You need to have already + downloaded the building XML file prior to running this function. + + Input simulation parameters, such as duration, start date, simulation timestep size, etc. + + Author: Alex Lee (alexlee5124@gmail.com) + Date: 3/29/2025 + """ + + # Update dwelling arguments + house_id = f"bldg{building_id:07}-up{upgrade_id:02}" + house_args = HOUSE_DEFAULT_ARGS.copy() + house_row = dict_sim_params['df_house_args'].loc[house_id] + house_args.update(house_row) + house_args['name'] = f"bldg{building_id:07}-up{upgrade_id:02}" + + # Update input files + # HPXML file + house_args['hpxml_file'] = os.path.join( + dict_sim_params['ochre_input_path'], + house_args['hpxml_file'] + ) + if not os.path.exists(house_args['hpxml_file']): + print(f"HPXML file does not exist: {house_args['hpxml_file']}") + sys.exit(1) + + # Schedule file + house_args['hpxml_schedule_file'] = os.path.join( + dict_sim_params['ochre_input_path'], + house_args['hpxml_schedule_file'] + ) + if not os.path.exists(house_args['hpxml_schedule_file']): + print(f"Schedule file does not exist: {house_args['hpxml_schedule_file']}") + sys.exit(1) + # Weather File + weather_station = f"{extract_weather_station(house_args['hpxml_file'])}.epw" + house_args['weather_file'] = os.path.join( + dict_sim_params['ochre_input_path'], + weather_station + ) + if not os.path.exists(house_args['weather_file']): + print(f"Weather file does not exist: {house_args['weather_file']}") + sys.exit(1) + + try: + # Baseline simulation + dwelling = Dwelling(**house_args) + + # Load properties from HPXML file + properties, weather_station = load_hpxml(**house_args) + # Load occupancy schedule and weather files + schedule, location = load_schedule( + properties, weather_station=weather_station, **house_args + ) + properties["location"] = location + # Update args for initializing Envelope and Equipment + sim_args = { + **house_args, + "start_time": dwelling.start_time, # updates time zone if necessary + "schedule": schedule, + "initial_schedule": schedule.loc[dwelling.start_time].to_dict(), + "output_path": dwelling.output_path, + } + # initial_schedule.update(self.envelope.get_main_states()) + sim_args["envelope_model"] = dwelling.envelope + HP1 = create_HP_equipment(get_HP_info(1), 'Cooling') + properties['equipment']['HVAC Cooling'].update(HP1) + + # Add detailed equipment properties, including ZIP parameters + equipment_dict = update_equipment_properties(properties, **sim_args) + #print(equipment_dict) + # continue at Dwelling line 139 + + dwelling.simulate() + except Exception as e: + print(f"Simulation failed for bldg{building_id:07}-up{upgrade_id:02}: {e}") + +if __name__ == '__main__': + swap_HP() \ No newline at end of file