Skip to content

Commit 581f565

Browse files
authored
merge for v0.8.5 (#125)
Merging dev into main for v0.8.5 - [ ] Reference the issue your PR is fixing - [x] Assign at least 1 reviewer for your PR - [ ] Test with run_dwelling.py or other script - [ ] Update documentation as appropriate - [ ] Update changelog as appropriate
2 parents 79fd6ad + 2d1072b commit 581f565

File tree

101 files changed

+3855
-36694
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+3855
-36694
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44

55
.idea/
66
.vscode/
7-
.env
7+
.venv
88
__pycache__/
99
src/
1010
build/
1111
dist/
12+
docs/_build
1213
*.egg-info/
1314
*.code-workspace
1415
environment.yml
16+
requirements.txt
1517

1618
defaults/Input Files/OCHRE*
1719
outputs/

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1+
![OCHRE](docs\source\images\OCHRE-Logo-Horiz-2Color.png)
2+
13
# OCHRE: The Object-oriented Controllable High-resolution Residential Energy Model
24

3-
A high-fidelity, high-resolution residential building model with behind-the-meter DERs and flexible load models
4-
that integrates with controllers and distribution models in building-to-grid co-simulation platforms.
5+
OCHRE™ is a Python-based building energy modeling (BEM) tool designed to model flexible loads in residential buildings. OCHRE includes detailed models and controls for flexible devices including HVAC equipment, water heaters, electric vehicles, solar PV, and batteries. It is designed to run in co-simulation with custom controllers, aggregators, and grid models.
56

67
The full documentation for OCHRE can be found at https://ochre-docs-final.readthedocs.io/en/latest/
78

89
910

1011
## Installation
1112

12-
Note that OCHRE requires Python version 3.9 or higher
13+
Note that OCHRE requires Python version >=3.9 and <3.12
1314

1415
### Stand-alone Installation
1516

bin/run_equipment.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def run_water_heater():
8181
water_draw_magnitude = 12 # L/min
8282
withdraw_rate = np.random.choice([0, water_draw_magnitude], p=[0.99, 0.01], size=len(times))
8383
schedule = pd.DataFrame({
84-
'Fixtures (L/min)': withdraw_rate,
84+
'Water Heating (L/min)': withdraw_rate,
8585
'Zone Temperature (C)': 20,
8686
'Mains Temperature (C)': 7,
8787
}, index=times)

bin/run_external_control.py

+80-26
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,100 @@
11
import datetime as dt
22
import pandas as pd
33

4-
from ochre import Dwelling
4+
from ochre import Dwelling, CreateFigures
55
from bin.run_dwelling import dwelling_args
66

77
# Test script to run single Dwelling with constant external control signal
88

9-
dwelling_args.update({
10-
'ext_time_res': dt.timedelta(minutes=60),
11-
})
9+
dwelling_args.update(
10+
{
11+
"time_res": dt.timedelta(minutes=10),
12+
"ext_time_res": dt.timedelta(minutes=60), # for duty cycle control only
13+
"Equipment": {
14+
"EV": {
15+
'vehicle_type': 'BEV',
16+
'charging_level': 'Level 2',
17+
'mileage': 150,
18+
},
19+
},
20+
}
21+
)
1222

1323
example_control_signal = {
14-
'HVAC Heating': {'Setpoint': 19}, # in C
15-
'HVAC Cooling': {'Setpoint': 22}, # in C
16-
'Water Heating': {'Setpoint': 50}, # in C
17-
'PV': {'P Setpoint': -1.1, 'Q Setpoint': 0.5}, # in kW, kVAR
18-
'Battery': {'P Setpoint': -1.0}, # in kW
24+
"HVAC Heating": {
25+
"Setpoint": 19,
26+
# 'Max Capacity Fraction': 0.8,
27+
"Max ER Capacity Fraction": 0.5,
28+
}, # in C
29+
"HVAC Cooling": {"Setpoint": 22}, # in C
30+
"Water Heating": {"Setpoint": 50}, # in C
31+
"PV": {"P Setpoint": -1.1, "Q Setpoint": 0.5}, # in kW, kVAR
32+
"Battery": {
33+
# 'P Setpoint': -1.0, # in kW
34+
# "SOC": 0.8,
35+
"Self Consumption Mode": True,
36+
"Max Import Limit": 1, # in kW
37+
"Max Export Limit": 1, # in kW
38+
# 'Min SOC': 0.2,
39+
# 'Max SOC': 0.8,
40+
},
41+
"EV": {
42+
# "Delay": True,
43+
"Max Power": 6,
44+
"Max SOC": 0.7,
45+
# "P Setpoint": 5,
46+
# "SOC": 0.6,
47+
# "SOC Rate": 0.02,
48+
},
1949
}
2050

2151

22-
def run_constant_control_signal(control_signal):
52+
def run_with_schedule_control():
53+
# Create Dwelling model (same as above)
54+
dwelling = Dwelling(name="Test House with Controller", **dwelling_args)
55+
56+
# Get HVAC heater setpoints
57+
heater = dwelling.get_equipment_by_end_use('HVAC Heating')
58+
setpoints = heater.schedule['HVAC Heating Setpoint (C)']
59+
60+
# Reduce heating setpoint by 1C from 5-9PM
61+
peak_times = setpoints.between_time(dt.time(17, 0, 0), dt.time(21, 0, 0), inclusive='left').index
62+
setpoints.loc[peak_times] -= 1
63+
heater.reset_time() # resets the schedule
64+
65+
# Run simulation
66+
dwelling.simulate()
67+
68+
69+
def run_constant_control_signal(control_signal=None):
2370
# Initialization
24-
dwelling = Dwelling(name='Test House with Controller', **dwelling_args)
71+
dwelling = Dwelling(name='OCHRE with Controller', **dwelling_args)
2572

2673
# Simulation
2774
for t in dwelling.sim_times:
28-
assert dwelling.current_time == t
75+
# assert dwelling.current_time == t
2976
house_status = dwelling.update(control_signal=control_signal)
3077

31-
return dwelling.finalize()
78+
df, _, _ = dwelling.finalize()
79+
80+
df["EV Electric Power (kW)"].plot()
81+
df["EV SOC (-)"].plot()
82+
CreateFigures.plt.show()
3283

3384

3485
def get_hvac_controls(hour_of_day, occupancy, heating_setpoint, **unused_inputs):
3586
# Use some of the controller_inputs to determine setpoints (or other control signals)
3687
if 14 <= hour_of_day < 20: # 2PM-8PM
37-
if occupancy > 0:
38-
heating_setpoint -= 1 # reduce setpoint by 1 degree C
39-
else:
40-
heating_setpoint -= 2 # reduce setpoint by 2 degrees C
88+
heating_setpoint -= 1 # reduce setpoint by 1 degree C
89+
# if occupancy > 0:
90+
# heating_setpoint -= 1 # reduce setpoint by 1 degree C
91+
# else:
92+
# heating_setpoint -= 2 # reduce setpoint by 2 degrees C
4193

4294
return {
43-
# 'HVAC Heating': {'Duty Cycle': 1 if heating_on else 0},
4495
'HVAC Heating': {
45-
'Setpoint': heating_setpoint,
96+
'Capacity': 1000,
97+
# 'Setpoint': heating_setpoint,
4698
# 'Deadband': 2,
4799
# 'Load Fraction': 0, # Set to 0 for force heater off
48100
# 'Duty Cycle': 0.5, # Sets fraction of on-time explicitly
@@ -53,7 +105,7 @@ def get_hvac_controls(hour_of_day, occupancy, heating_setpoint, **unused_inputs)
53105

54106
def run_with_hvac_controller():
55107
# Initialization
56-
dwelling = Dwelling(name='Test House with Controller', **dwelling_args)
108+
dwelling = Dwelling(name="OCHRE with Controller", **dwelling_args)
57109
heater = dwelling.get_equipment_by_end_use('HVAC Heating')
58110
cooler = dwelling.get_equipment_by_end_use('HVAC Cooling')
59111

@@ -73,8 +125,9 @@ def run_with_hvac_controller():
73125
'hour_of_day': t.hour,
74126
'outdoor_temp': dwelling.envelope.schedule.loc[t, 'Ambient Dry Bulb (C)'],
75127
'occupancy': dwelling.envelope.schedule.loc[t, 'Occupancy (Persons)'],
76-
'heating_setpoint': heater.schedule.loc[t, 'HVAC Heating Setpoint (C)'], # Original setpoint for current time
77-
'cooling_setpoint': cooler.schedule.loc[t, 'HVAC Cooling Setpoint (C)'], # Original setpoint for current time
128+
# Original setpoints for current time
129+
'heating_setpoint': heater.schedule.loc[t, 'HVAC Heating Setpoint (C)'],
130+
'cooling_setpoint': cooler.schedule.loc[t, 'HVAC Cooling Setpoint (C)'],
78131
})
79132

80133
control_signal = get_hvac_controls(**controller_inputs)
@@ -95,7 +148,7 @@ def run_controls_from_file(control_file):
95148
df_ext = pd.read_csv(control_file, index_col='Time', parse_dates=True)
96149

97150
# Initialization
98-
dwelling = Dwelling(name='Test House with Controller', **dwelling_args)
151+
dwelling = Dwelling(name="OCHRE with Controller", **dwelling_args)
99152

100153
# Simulation
101154
control_signal = None
@@ -110,6 +163,7 @@ def run_controls_from_file(control_file):
110163

111164

112165
if __name__ == '__main__':
113-
# run_constant_control_signal(example_control_signal)
114-
# run_controls_from_file(external_control_file='path/to/control_file.csv')
115-
run_with_hvac_controller()
166+
# run_with_schedule_control()
167+
run_constant_control_signal(example_control_signal)
168+
# run_with_hvac_controller()
169+
# run_controls_from_file(external_control_file='path/to/control_file.csv')

bin/run_fleet.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def run_water_heater_fleet(num_water_heaters=5):
4141
'Tank Height (m)': 1.22,
4242
'UA (W/K)': 2.17,
4343
'schedule': pd.DataFrame({
44-
'Fixtures (L/min)': withdraw_rate[wh_name],
44+
'Water Heating (L/min)': withdraw_rate[wh_name],
4545
'Zone Temperature (C)': np.random.uniform(15, 18),
4646
'Mains Temperature (C)': np.random.uniform(5.6, 8.3),
4747
}, index=times),

bin/run_multiple.py

-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ def run_single_building(input_path, simulation_name='ochre', output_path=None):
138138
def compile_results(main_folder):
139139
# Sample script to compile results from multiple OCHRE runs
140140
# assumes each run is in a different folder, and all simulation names are 'ochre'
141-
dirs_to_include = int(dirs_to_include)
142141

143142
# set up
144143
main_folder = os.path.abspath(main_folder)

changelog.md

+28
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,33 @@
11
## OCHRE Changelog
22

3+
### Changes from PRs
4+
5+
- Updated PV model to integrate with PVWatts using PySAM v5.0 (not backwards compatible)
6+
- PV model accepts tilt and azimuth angles from roof boundary in envelope
7+
- Removed and renamed PV input arguments related to PySAM
8+
- Changed the units for some outputs related to heat gains/capacity
9+
- Added controls and optional schedule columns for HVAC, WH, EV, Battery
10+
- Added HVAC capacity and max capacity controls, ideal mode only
11+
- Require HVAC duty cycle control for thermostatic mode only
12+
- Added water heater max power control
13+
- Added EV max power and max SOC controls
14+
- Added `equipment_event_file` input for EVs
15+
- Added OCHREException class to handle errors
16+
- Added warnings for HVAC and WH heat pumps with low COP
17+
- Moved default input file path for package installation
18+
- Replaced setup.py with pyproject.toml
19+
- Fixed bug with schedule file import using Pandas v2.2
20+
- Fixed bug with accounting for HVAC delivered heat for standalone HVAC runs
21+
- Fixed bug with ASHP backup heater units
22+
- Fixed bug with named HVAC/Water Heating equipment arguments
23+
- Fixed bug in ASHP duty cycle control
24+
- Fixed bug with accounting for HVAC delivered heat for standalone HVAC runs
25+
- Fixed bug with ASHP backup heater units
26+
- Fixed bug with battery/generator self-consumption controls
27+
- Fixed bug with WH and battery islanding time metrics
28+
- Fixed bug with state space model reduction algorithm
29+
- Fixed syntax warning for Python 3.12
30+
331
### OCHRE v0.8.4-beta
432

533
- Fixed bug with air infiltration inputs (works with ResStock 3.0 and 3.1, and OS-HPXML 1.6.0)

defaults/PV/sam_weather_header.csv

-2
This file was deleted.

0 commit comments

Comments
 (0)