Skip to content

Commit b88a5e1

Browse files
authored
Apply ruff formatting to codebase (#207)
## Summary - Apply ruff code formatting across entire Python codebase for consistent style - Update CI workflow configuration - All 237 tests pass (236 passed, 1 skipped) ### **Linting vs. Formatting with Ruff** We have migrated to **Ruff**, which replaces several older tools with a single, faster engine. * **Formatting (Replaces [Black](https://github.com/psf/black)):** Standardizes the visual style of the code, such as indentation, line lengths, and quoting. * **How to run:** `ruff format .` * **Linting (Replaces [Flake8](https://github.com/PyCQA/flake8) and [isort](https://github.com/PyCQA/isort)):** Analyzes code for logical errors, unused imports, or non-standard practices. * **How to run:** `ruff check .` (use `ruff check --fix .` to automatically resolve simple issues) ### **Current Policy** * **Formatting is Enforced:** The CI pipeline will fail if the code is not formatted. Please run `ruff format .` before every commit. * **Linting is Recommended:** While we aren't enforcing strict linting yet (due to the high volume of existing errors in the codebase), we strongly encourage you to run check your changes to ensure new edits are as clean as possible. For example, run `ruff check ochre/Models/StateSpaceModel.py` check for lints in the StateSpaceModel.py file. ### **Setting up Ruff** To ensure your environment is set up correctly to use the new tooling, please follow these steps: 1. **Update your branch** Merge the latest `dev` branch into your current feature branch to get the new configuration files. 2. **Install `uv`** if you don't already have it. We use `uv` for fast Python package management. You can install it from pip with: ```bash pip install uv ``` * **macOS / Linux:** ```bash curl -LsSf [https://astral.sh/uv/install.sh](https://astral.sh/uv/install.sh) | sh ``` * **Windows:** ```powershell powershell -ExecutionPolicy ByPass -c "irm [https://astral.sh/uv/install.ps1](https://astral.sh/uv/install.ps1) | iex" ``` 3. **Sync Dependencies** If you already have a `.venv` folder in your project directory, please delete it first to ensure a clean install. Then run: ```bash uv sync ``` 4. **Run Formatting** You can run Ruff directly using `uv` (recommended) or by activating your environment. * **Option A (Recommended):** Run via `uv` ```bash uv run ruff format . ``` * **Option B:** Activate environment first * **macOS / Linux:** ```bash source .venv/bin/activate ruff format . ``` * **Windows:** ```powershell .venv\Scripts\activate ruff format . ``` ```
2 parents 5afcd2b + 505f88c commit b88a5e1

Some content is hidden

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

66 files changed

+4425
-4214
lines changed

.github/workflows/tests.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ on:
44
push:
55
branches: [main, dev]
66
pull_request:
7-
branches: [main, dev]
7+
# Run on all pull requests
8+
types: [opened, synchronize, reopened]
89

910
jobs:
1011
test:
@@ -61,9 +62,8 @@ jobs:
6162
pip install ruff
6263
6364
- name: Run ruff linter
64-
run: ruff check ochre/ --output-format=github
65+
run: ruff check . --output-format=github
6566
continue-on-error: true
6667

6768
- name: Run ruff formatter check
68-
run: ruff format ochre/ --check --diff
69-
continue-on-error: true
69+
run: ruff format . --check --diff

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ docs/_build
1414
*.code-workspace
1515

1616
ochre/defaults/Input Files/OCHRE*
17+
.history

bin/compare_energyplus.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,39 @@
11
import os
22

3-
from ochre import Analysis, CreateFigures, Dwelling
3+
from ochre import Analysis, CreateFigures
44

55
# Script to compare OCHRE and E+ outputs for generic model. Assumes both models have been run in the same folder
66

77
# File locations
8-
main_path = os.path.join('path', 'to', 'ochre_folder')
9-
eplus_file = os.path.join(main_path, 'results_timeseries.csv')
10-
simulation_name = 'ochre' # name for OCHRE files
8+
main_path = os.path.join("path", "to", "ochre_folder")
9+
eplus_file = os.path.join(main_path, "results_timeseries.csv")
10+
simulation_name = "ochre" # name for OCHRE files
1111

1212

13-
if __name__ == '__main__':
13+
if __name__ == "__main__":
1414
# Load OCHRE files
15-
ochre_exact, ochre_metrics, ochre = Analysis.load_ochre(main_path, simulation_name, load_main=False,
16-
combine_schedule=True)
15+
ochre_exact, ochre_metrics, ochre = Analysis.load_ochre(
16+
main_path, simulation_name, load_main=False, combine_schedule=True
17+
)
1718

1819
# Load E+ files
1920
eplus = Analysis.load_eplus_file(eplus_file, year=ochre.index[0].year)
2021

2122
# keep days from OCHRE simulation
22-
eplus = eplus.loc[ochre.index[0]: ochre.index[-1]]
23+
eplus = eplus.loc[ochre.index[0] : ochre.index[-1]]
2324
eplus_metrics = Analysis.calculate_metrics(eplus, metrics_verbosity=6)
2425

2526
# Compare metrics and save to file
2627
compare_metrics = Analysis.create_comparison_metrics(ochre, eplus, ochre_metrics, eplus_metrics)
27-
metrics_file = os.path.join(main_path, simulation_name + '_comparison.csv')
28+
metrics_file = os.path.join(main_path, simulation_name + "_comparison.csv")
2829
compare_metrics.to_csv(metrics_file)
2930

30-
print(f'Comparison Metrics for {simulation_name}:')
31+
print(f"Comparison Metrics for {simulation_name}:")
3132
print(compare_metrics)
3233

3334
# show plots
3435
# data = {'OCHRE (exact)': ochre_exact, 'OCHRE': ochre, 'E+': eplus}
35-
data = {'OCHRE': ochre, 'E+': eplus}
36+
data = {"OCHRE": ochre, "E+": eplus}
3637
# CreateFigures.plot_external(data)
3738
CreateFigures.plot_envelope(data)
3839
# CreateFigures.plot_hvac(data)

bin/run_cosimulation.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import os
22
import json
33
import datetime as dt
4-
import shutil
54
import sys
65
import click
76
import helics
@@ -53,9 +52,7 @@
5352

5453
# Note: see documentation for where to download other weather files
5554
# https://ochre-nrel.readthedocs.io/en/latest/InputsAndArguments.html#weather-file
56-
default_weather_file = os.path.join(
57-
default_input_path, "Weather", "USA_CO_Denver.Intl.AP.725650_TMY3.epw"
58-
)
55+
default_weather_file = os.path.join(default_input_path, "Weather", "USA_CO_Denver.Intl.AP.725650_TMY3.epw")
5956

6057
# control parameters - keep net load within +/- 1 kW per house
6158
min_net_load = -1 * n
@@ -97,7 +94,7 @@ def step_to(time, fed, offset=0):
9794
if t_new >= t_requested:
9895
return
9996
time.sleep(0.01)
100-
97+
10198

10299
@click.group()
103100
def cli():
@@ -209,9 +206,7 @@ def aggregator():
209206
results.append(total_powers)
210207

211208
# determine battery setpoints to maintain net load limits
212-
nonbattery_power = (
213-
total_powers["Total Electric Power (kW)"] - total_powers["Battery Electric Power (kW)"]
214-
)
209+
nonbattery_power = total_powers["Total Electric Power (kW)"] - total_powers["Battery Electric Power (kW)"]
215210
if nonbattery_power > max_net_load:
216211
battery_power = max_net_load - nonbattery_power
217212
elif nonbattery_power < min_net_load:

bin/run_dwelling.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import datetime as dt
33

44
from ochre import Dwelling, CreateFigures
5+
56
# from ochre import Analysis
67
from ochre.utils import default_input_path
78

@@ -12,27 +13,23 @@
1213
#
1314
# Timing parameters
1415
"start_time": dt.datetime(2018, 1, 1, 0, 0), # year, month, day, hour, minute
15-
"time_res": dt.timedelta(minutes=60), # time resolution of the simulation
16-
"duration": dt.timedelta(days=1), # duration of the simulation
16+
"time_res": dt.timedelta(minutes=60), # time resolution of the simulation
17+
"duration": dt.timedelta(days=1), # duration of the simulation
1718
"initialization_time": dt.timedelta(days=1), # used to create realistic starting temperature
1819
# "time_zone": None, # option to specify daylight savings, in development
1920
#
2021
# Input files
2122
"hpxml_file": os.path.join(default_input_path, "Input Files", "bldg0112631-up11.xml"),
22-
"hpxml_schedule_file": os.path.join(
23-
default_input_path, "Input Files", "bldg0112631_schedule.csv"
24-
),
25-
"weather_file": os.path.join(
26-
default_input_path, "Weather", "USA_CO_Denver.Intl.AP.725650_TMY3.epw"
27-
),
23+
"hpxml_schedule_file": os.path.join(default_input_path, "Input Files", "bldg0112631_schedule.csv"),
24+
"weather_file": os.path.join(default_input_path, "Weather", "USA_CO_Denver.Intl.AP.725650_TMY3.epw"),
2825
# note: weather_path can be used when Weather Station is specified in HPXML file
2926
# "weather_path": weather_path,
3027
#
3128
# Output parameters
3229
# "verbosity": 3, # verbosity of time series files (0-9)
3330
# "metrics_verbosity": 3, # verbosity of metrics file (0-9)
3431
# "save_results": False, # saves results to files. Defaults to True if verbosity > 0
35-
"output_path": os.getcwd(), # defaults to hpxml_file path
32+
"output_path": os.getcwd(), # defaults to hpxml_file path
3633
# "save_args_to_json": True, # includes data from this dictionary in the json file
3734
# "output_to_parquet": True, # saves time series files as parquet files (False saves as csv files)
3835
# "save_schedule_columns": [], # list of time series inputs to save to schedule file

bin/run_equipment.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
ElectricResistanceWaterHeater,
1212
AirConditioner,
1313
ScheduledLoad,
14-
EventBasedLoad,
1514
EventDataLoad,
1615
)
1716
from ochre import CreateFigures
@@ -45,7 +44,7 @@ def run_equipment_from_house_model(end_use):
4544

4645
# Extract equipment by its name or end use
4746
equipment = dwelling.get_equipment_by_end_use(end_use)
48-
47+
4948
# Update simulation properties to save results
5049
equipment.main_simulator = True
5150
equipment.save_results = True
@@ -130,8 +129,7 @@ def run_battery_from_schedule():
130129
# Note: can also be done at each time step, see run_external_control.py
131130
# for examples
132131
schedule = np.random.randint(-5, 5, len(battery.sim_times))
133-
battery.schedule = pd.DataFrame({"Battery Electric Power (kW)": schedule},
134-
index=battery.sim_times)
132+
battery.schedule = pd.DataFrame({"Battery Electric Power (kW)": schedule}, index=battery.sim_times)
135133
battery.reset_time() # initializes the new schedule
136134

137135
# Simulate equipment
@@ -264,20 +262,24 @@ def run_hvac():
264262

265263
# create example HVAC schedule
266264
# TODO: add solar radiation to schedule (in H_LIV)
267-
times = pd.date_range(timing["start_time"], timing["start_time"] + timing["duration"], freq=timing["time_res"],
268-
inclusive="left")
265+
times = pd.date_range(
266+
timing["start_time"], timing["start_time"] + timing["duration"], freq=timing["time_res"], inclusive="left"
267+
)
269268
deadband = (2 + 1 * np.random.randn(len(times))).clip(min=1)
270269
ambient_temp = 27 - np.abs(times.hour.values - 14) / 2 + 0.5 * np.random.randn(len(times))
271270
internal_gains = 100 + 30 * np.random.randn(len(times))
272-
schedule = pd.DataFrame({
273-
"HVAC Cooling Setpoint (C)": 22,
274-
"HVAC Cooling Deadband (C)": deadband,
275-
"Ambient Dry Bulb (C)": ambient_temp,
276-
"Ambient Humidity Ratio (-)": 0.001,
277-
# "Ambient Pressure (kPa)": 101,
278-
# "T_EXT": ambient_temp,
279-
"Internal Gains (W)": internal_gains,
280-
}, index=times)
271+
schedule = pd.DataFrame(
272+
{
273+
"HVAC Cooling Setpoint (C)": 22,
274+
"HVAC Cooling Deadband (C)": deadband,
275+
"Ambient Dry Bulb (C)": ambient_temp,
276+
"Ambient Humidity Ratio (-)": 0.001,
277+
# "Ambient Pressure (kPa)": 101,
278+
# "T_EXT": ambient_temp,
279+
"Internal Gains (W)": internal_gains,
280+
},
281+
index=times,
282+
)
281283

282284
envelope_args = {
283285
"capacitances": {
@@ -319,8 +321,7 @@ def run_hvac():
319321

320322
print()
321323
# print(df.head())
322-
CreateFigures.plot_daily_profile(df, "HVAC Cooling Electric Power (kW)",
323-
plot_max=False, plot_min=False)
324+
CreateFigures.plot_daily_profile(df, "HVAC Cooling Electric Power (kW)", plot_max=False, plot_min=False)
324325
CreateFigures.plot_hvac({"": df})
325326
# CreateFigures.plot_envelope({"": df})
326327
CreateFigures.plt.show()

bin/run_fleet.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def run_ev_fleet(n=4, n_parallel=2):
6464
df.plot()
6565
CreateFigures.plt.show()
6666

67+
6768
def setup_wh(i):
6869
start_time = dt.datetime(2018, 1, 1, 0, 0) # year, month, day, hour, minute
6970
time_res = dt.timedelta(minutes=1)
@@ -102,6 +103,7 @@ def setup_wh(i):
102103
# Initialize equipment
103104
return ElectricResistanceWaterHeater(**equipment_args)
104105

106+
105107
def run_water_heater_fleet(n=5):
106108
# Initialize equipment
107109
fleet = [setup_wh(i + 1) for i in range(n)]
@@ -113,7 +115,7 @@ def run_water_heater_fleet(n=5):
113115
all_data[wh.name] = df
114116

115117
cols_to_plot = [
116-
"Water Heating Electric Power (kW)",
118+
"Water Heating Electric Power (kW)",
117119
"Hot Water Outlet Temperature (C)",
118120
"Hot Water Delivered (L/min)",
119121
]
@@ -142,11 +144,9 @@ def setup_battery(i):
142144
# Note: can also be done at each time step, see run_external_control.py
143145
# for examples
144146
schedule = np.random.randint(-capacity, capacity, len(battery.sim_times))
145-
battery.schedule = pd.DataFrame(
146-
{"Battery Electric Power (kW)": schedule}, index=battery.sim_times
147-
)
147+
battery.schedule = pd.DataFrame({"Battery Electric Power (kW)": schedule}, index=battery.sim_times)
148148
battery.reset_time() # initializes the new schedule
149-
149+
150150
return battery
151151

152152

@@ -170,7 +170,7 @@ def run_battery_fleet(n=4):
170170
CreateFigures.plt.show()
171171

172172

173-
if __name__ == '__main__':
173+
if __name__ == "__main__":
174174
run_ev_fleet()
175175
# run_water_heater_fleet()
176176
# run_battery_fleet()

bin/run_multiple.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import shutil
33

44
from ochre import Analysis
5-
from ochre.cli import create_dwelling, limit_input_paths, run_multiple_local, run_multiple_hpc
5+
from ochre.cli import create_dwelling
66
from ochre.utils import default_input_path
77

88
# Examples to download and run multiple Dwellings. Uses OCHRE's command line
@@ -48,9 +48,7 @@ def compile_results(main_path, n_max=None):
4848
df.to_csv(os.path.join(output_path, "all_ochre_inputs.csv"))
4949

5050
# combine metrics files
51-
metrics_files = {
52-
name: os.path.join(path, "ochre_metrics.csv") for name, path in run_names.items()
53-
}
51+
metrics_files = {name: os.path.join(path, "ochre_metrics.csv") for name, path in run_names.items()}
5452
df = Analysis.combine_metrics_files(metrics_files)
5553
df.to_csv(os.path.join(output_path, "all_ochre_metrics.csv"))
5654

bin/run_panel_controls.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010
# Example code for running an building with smart panel controls.
1111

1212
main_output_path = dwelling_args.pop("output_path", os.getcwd())
13-
dwelling_args.update({
14-
"name": "ochre",
15-
"time_res": dt.timedelta(minutes=2), # time resolution of the simulation
16-
"duration": dt.timedelta(days=10), # duration of the simulation
17-
"verbosity": 6, # verbosity of time series files (0-9)
18-
'seed': 1,
19-
})
13+
dwelling_args.update(
14+
{
15+
"name": "ochre",
16+
"time_res": dt.timedelta(minutes=2), # time resolution of the simulation
17+
"duration": dt.timedelta(days=10), # duration of the simulation
18+
"verbosity": 6, # verbosity of time series files (0-9)
19+
"seed": 1,
20+
}
21+
)
2022

2123

2224
def circuit_sharing_control(dwelling, tech1, tech2):
@@ -209,7 +211,7 @@ def my_print(*args):
209211

210212
# case 1, circuit sharing with cooking range (primary) and WH (secondary)
211213
run_simulation(
212-
"circuit_sharing",
214+
"circuit_sharing",
213215
tech1="Cooking Range",
214216
tech2="Water Heating",
215217
)

changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
### OCHRE v0.9.3
44
- Allow 120V (aka low power) heat pump water heaters
5+
- Applied ruff code formatting to entire codebase
6+
- Fixed ruff lint errors across codebase
7+
- Updated CI to run tests on all pull requests
58

69
### OCHRE v0.9.2
710
- Restrict pint version to avoid colab issues [#196](https://github.com/NREL/OCHRE/issues/196)

0 commit comments

Comments
 (0)