Issue Description
There is an incorrect variable reference in citylearn/building.py that prevents the Domestic Hot Water (DHW) storage system from updating its state of charge or energy balance. DHW actions are multiplied by self.heating_storage.capacity instead of self.dhw_storage.capacity.
When heating_storage is disabled (as in the 2023 challenge dataset), heating_storage.capacity == 0, causing DHW storage to remain unused even though dhw_storage appears as an active action.
Expected Behavior
When the agent outputs non-zero dhw_storage actions, the DHW tank should charge or discharge according to its configured capacity. Its SOC and energy balance should vary over time.
Actual Behavior
dhw_storage actions have no effect.
- DHW SOC stays strictly zero for the entire episode.
- DHW energy balance remains zero.
- All DHW demand is supplied directly by the electric heater.
- Changing one line of code to reference
self.dhw_storage.capacity produces
the expected non-zero behavior.
Output with original code (incorrect)
DHW Storage SOC: [0. 0. 0. 0. ... 0.]
Output after fixing the line
DHW Storage SOC: [0.9780134 1. 1. 1. ... 0.62974083 1. 0.]
This clearly shows that DHW storage behavior is completely suppressed in the current version.
Steps to Reproduce
-
Use the citylearn_challenge_2023_phase_1 dataset where:
dhw_storage is active,
heating_storage is inactive → capacity = 0.
-
Create any agent that outputs non-zero dhw_storage actions.
-
Run a full episode and log:
env.buildings[0].dhw_storage.soc
-
Observe that SOC stays zero throughout the entire simulation.
Minimal Reproducible Example
from typing import List
from citylearn.agents.base import Agent
from citylearn.citylearn import CityLearnEnv
class CustomRBC(Agent):
def __init__(self, env: CityLearnEnv, **kwargs):
super().__init__(env, **kwargs)
def predict(self, observations: List[List[float]], deterministic=True):
actions = []
for i, o in enumerate(observations):
available_obs = self.observation_names[i]
available_act = self.action_names[i]
action = [0.0 for _ in range(len(available_act))]
hour = o[available_obs.index('hour')]
if 'dhw_storage' in available_act:
if 6 <= hour <= 9 or 18 <= hour <= 22:
action[available_act.index('dhw_storage')] = -0.2
else:
action[available_act.index('dhw_storage')] = 1.0
actions.append(action)
return actions
env = CityLearnEnv(
schema='citylearn_challenge_2023_phase_1',
central_agent=True,
)
agent = CustomRBC(env)
obs, _ = env.reset(seed=0)
while not env.terminated:
action = agent.predict(obs)
obs, reward, _, _, _ = env.step(action)
print("DHW Storage SOC:", env.buildings[0].dhw_storage.soc)
Environment
- CityLearn version: 2.4.2
- Dataset: citylearn_challenge_2023_phase_1
- Operating System: Ubuntu 24.04
- Python version: 3.10.19
- Issue present also in latest
main branch at time of reporting.
Root Cause
In building.py around line 1765:
energy = action * self.heating_storage.capacity * self.algorithm_action_based_time_step_hours_ratio
This uses the heating storage capacity even when processing DHW actions.
Possible Solution
Replace the incorrect line with:
energy = action * self.dhw_storage.capacity * self.algorithm_action_based_time_step_hours_ratio
This immediately restores correct DHW storage behavior.
Additional Notes
This bug makes DHW storage unusable in all configurations where heating storage is inactive (capacity = 0), including the official challenge dataset. Fixing it is necessary for agents to learn or implement any DHW shifting strategies.
Issue Description
There is an incorrect variable reference in
citylearn/building.pythat prevents the Domestic Hot Water (DHW) storage system from updating its state of charge or energy balance. DHW actions are multiplied byself.heating_storage.capacityinstead ofself.dhw_storage.capacity.When
heating_storageis disabled (as in the 2023 challenge dataset),heating_storage.capacity == 0, causing DHW storage to remain unused even thoughdhw_storageappears as an active action.Expected Behavior
When the agent outputs non-zero
dhw_storageactions, the DHW tank should charge or discharge according to its configured capacity. Its SOC and energy balance should vary over time.Actual Behavior
dhw_storageactions have no effect.self.dhw_storage.capacityproducesthe expected non-zero behavior.
Output with original code (incorrect)
Output after fixing the line
This clearly shows that DHW storage behavior is completely suppressed in the current version.
Steps to Reproduce
Use the
citylearn_challenge_2023_phase_1dataset where:dhw_storageis active,heating_storageis inactive → capacity = 0.Create any agent that outputs non-zero
dhw_storageactions.Run a full episode and log:
env.buildings[0].dhw_storage.socObserve that SOC stays zero throughout the entire simulation.
Minimal Reproducible Example
Environment
mainbranch at time of reporting.Root Cause
In
building.pyaround line 1765:This uses the heating storage capacity even when processing DHW actions.
Possible Solution
Replace the incorrect line with:
This immediately restores correct DHW storage behavior.
Additional Notes
This bug makes DHW storage unusable in all configurations where heating storage is inactive (capacity = 0), including the official challenge dataset. Fixing it is necessary for agents to learn or implement any DHW shifting strategies.