Controller / data_generator /rollout_runner.py
Gen-HVAC's picture
Upload 2 files
831718a verified
import gymnasium as gym
import sinergym
import pandas as pd
import numpy as np
import os
import json
import sys
from unihvac.find_files import (
detect_paths,
find_manifest,
find_building_and_weather_from_manifest,
)
from unihvac.tables import (
print_monthly_tables_extra,
print_monthly_tables_split,
)
from unihvac.rollout import run_rollout_to_df
from unihvac.data_generator import save_dt_training_data
# ============================================
# FOR TABLE
pd.set_option("display.max_columns", None)
pd.set_option("display.width", 240)
pd.set_option("display.max_colwidth", 32)
pd.set_option("display.float_format", lambda x: f"{x:,.2f}")
# ============================================
# ==============================================================================
# USER CONFIGURATION
# ==============================================================================
TARGET_LOCATION = "Fairbanks"
TARGET_THERMAL = "default"
TARGET_OCCUPANCY = "standard"
HEATING_SP = 21.0
COOLING_SP = 24.0
# ==========================================
# PATH DISCOVERY (ROBUST)
# ==========================================
paths = detect_paths(outputs_dirname="baseline_results")
# Get manifest (patched preferred)
manifest_path = find_manifest(paths, building="OfficeSmall", prefer_patched=True)
output_root = str(paths.outputs_root)
os.makedirs(output_root, exist_ok=True)
OUTPUT_DIR = "rollout_run"
TIME_STEP_HOURS = 900.0 / 3600.0 # 0.25 h
# ==========================================
# 3. COMMON ACTUATORS & VARIABLES
# ==========================================
hot_actuators = {
"Htg_Core": ("Zone Temperature Control", "Heating Setpoint", "CORE_ZN"),
"Clg_Core": ("Zone Temperature Control", "Cooling Setpoint", "CORE_ZN"),
"Htg_P1": ("Zone Temperature Control", "Heating Setpoint", "PERIMETER_ZN_1"),
"Clg_P1": ("Zone Temperature Control", "Cooling Setpoint", "PERIMETER_ZN_1"),
"Htg_P2": ("Zone Temperature Control", "Heating Setpoint", "PERIMETER_ZN_2"),
"Clg_P2": ("Zone Temperature Control", "Cooling Setpoint", "PERIMETER_ZN_2"),
"Htg_P3": ("Zone Temperature Control", "Heating Setpoint", "PERIMETER_ZN_3"),
"Clg_P3": ("Zone Temperature Control", "Cooling Setpoint", "PERIMETER_ZN_3"),
"Htg_P4": ("Zone Temperature Control", "Heating Setpoint", "PERIMETER_ZN_4"),
"Clg_P4": ("Zone Temperature Control", "Cooling Setpoint", "PERIMETER_ZN_4"),
}
hot_variables = {
"outdoor_temp": ("Site Outdoor Air DryBulb Temperature", "Environment"),
"core_temp": ("Zone Air Temperature", "Core_ZN"),
"perim1_temp": ("Zone Air Temperature", "Perimeter_ZN_1"),
"perim2_temp": ("Zone Air Temperature", "Perimeter_ZN_2"),
"perim3_temp": ("Zone Air Temperature", "Perimeter_ZN_3"),
"perim4_temp": ("Zone Air Temperature", "Perimeter_ZN_4"),
"elec_power": ("Facility Total HVAC Electricity Demand Rate", "Whole Building"),
"core_occ_count": ("Zone People Occupant Count", "CORE_ZN"),
"perim1_occ_count": ("Zone People Occupant Count", "PERIMETER_ZN_1"),
"perim2_occ_count": ("Zone People Occupant Count", "PERIMETER_ZN_2"),
"perim3_occ_count": ("Zone People Occupant Count", "PERIMETER_ZN_3"),
"perim4_occ_count": ("Zone People Occupant Count", "PERIMETER_ZN_4"),
"outdoor_dewpoint": ("Site Outdoor Air Dewpoint Temperature", "Environment"),
"outdoor_wetbulb": ("Site Outdoor Air Wetbulb Temperature", "Environment"),
"core_rh": ("Zone Air Relative Humidity", "CORE_ZN"),
"perim1_rh": ("Zone Air Relative Humidity", "PERIMETER_ZN_1"),
"perim2_rh": ("Zone Air Relative Humidity", "PERIMETER_ZN_2"),
"perim3_rh": ("Zone Air Relative Humidity", "PERIMETER_ZN_3"),
"perim4_rh": ("Zone Air Relative Humidity", "PERIMETER_ZN_4"),
}
class BaselineReward:
def __init__(self, *args, **kwargs):
pass
def __call__(self, obs_dict):
return 0.0, {}
# ==========================================
# 5. RBC CONTROLLER (CONSTANT SETPOINTS)
# ==========================================
def get_constant_rbc():
h_sp, c_sp = HEATING_SP, COOLING_SP
action = np.array([h_sp, c_sp] * 5, dtype=np.float32)
return action, h_sp, c_sp
def run_baseline_for_location(location, building_path, weather_path):
print("\n" + "=" * 80)
print(f"Running baseline for location: {location}")
print(f" Building: {building_path}")
print(f" Weather: {weather_path}")
print("=" * 80)
out_dir = os.path.join(output_root, location)
os.makedirs(out_dir, exist_ok=True)
def policy_fn(obs, info, step):
action, _, _ = get_constant_rbc()
return action
df = run_rollout_to_df(
building_path=str(building_path),
weather_path=str(weather_path),
variables=hot_variables,
actuators=hot_actuators,
policy_fn=policy_fn,
location=location,
timestep_hours=TIME_STEP_HOURS,
heating_sp=HEATING_SP,
cooling_sp=COOLING_SP,
reward=BaselineReward,
max_steps=None,
verbose=True,
)
print("setpoint_htg min/max:", df["setpoint_htg"].min(), df["setpoint_htg"].max())
print("setpoint_clg min/max:", df["setpoint_clg"].min(), df["setpoint_clg"].max())
print("comfort_violation min/mean/max:", df["comfort_violation_degCh"].min(),
df["comfort_violation_degCh"].mean(), df["comfort_violation_degCh"].max())
df["setpoint_htg"] = HEATING_SP
df["setpoint_clg"] = COOLING_SP
# 7) Print the same tables
print_monthly_tables_extra(df, location)
print_monthly_tables_split(df, location, time_step_hours=TIME_STEP_HOURS)
# Save raw timeseries for inspection
df.to_csv(os.path.join(out_dir, "baseline_timeseries.csv"), index=False)
save_dt_training_data(df, out_dir, location=location)
if "month" in df.columns:
monthly_energy = df.groupby("month")
return df, monthly_energy
return df, None
if __name__ == "__main__":
bpath, wpath = find_building_and_weather_from_manifest(
manifest_path,
location=TARGET_LOCATION,
occupancy=TARGET_OCCUPANCY,
thermal=TARGET_THERMAL,
require_patched=True,
)
run_baseline_for_location(TARGET_LOCATION, str(bpath), str(wpath))