Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ SPDX-FileCopyrightText: ASSUME Developers
SPDX-License-Identifier: AGPL-3.0-or-later
-->

<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
## Related Issue
Closes #<issue‑number>
*If no issue exists, delete this line.*
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repos:

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.7.2
rev: v0.14.6
hooks:
# Run the linter.
- id: ruff
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def clear(
if order_type is not None:
tt = (order["start_time"] - start) / duration
# block_id, hour, name
name = f'{order["agent_addr"]} {order.get("unit_id", "")}'
name = f"{order['agent_addr']} {order.get('unit_id', '')}"
if "exclusive" in order_type:
idx = (order["exclusive_id"], tt, name)
elif "linked" in order_type:
Expand Down
6 changes: 3 additions & 3 deletions assume/markets/clearing_algorithms/contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ async def execute_contract(self, contract: Order):
begin = max(contract["start_time"], begin)
end -= timedelta(hours=1)

reply_with = f'{buyer}_{contract["start_time"]}'
reply_with = f"{buyer}_{contract['start_time']}"
self.futures[reply_with] = asyncio.Future()
self.context.schedule_instant_message(
create_acl(
Expand All @@ -318,7 +318,7 @@ async def execute_contract(self, contract: Order):
)

if contract["contract"] in contract_needs_market:
reply_with_market = f'market_eom_{contract["start_time"]}'
reply_with_market = f"market_eom_{contract['start_time']}"
self.futures[reply_with_market] = asyncio.Future()
self.context.schedule_instant_message(
create_acl(
Expand Down Expand Up @@ -351,7 +351,7 @@ async def execute_contract(self, contract: Order):
contract, market_series, client_series, begin, end
)

in_reply_to = f'{contract["contract"]}_{contract["start_time"]}'
in_reply_to = f"{contract['contract']}_{contract['start_time']}"
await self.send_contract_result(buyer_agent, o_buyer, in_reply_to)
await self.send_contract_result(seller_agent, o_seller, in_reply_to)

Expand Down
2 changes: 1 addition & 1 deletion assume/reinforcement_learning/learning_role.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ def compare_and_save_policies(self, metrics: dict) -> bool:

if avg_change < self.learning_config.early_stopping_threshold:
logger.info(
f"Stopping training as no improvement above {self.learning_config.early_stopping_threshold*100}% in last {self.learning_config.early_stopping_steps} evaluations for {metric}"
f"Stopping training as no improvement above {self.learning_config.early_stopping_threshold * 100}% in last {self.learning_config.early_stopping_steps} evaluations for {metric}"
)
if (
self.learning_config.learning_rate_schedule
Expand Down
2 changes: 1 addition & 1 deletion assume/strategies/portfolio_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def calculate_bids(
if market_config.price_tick:
order["price"] = round(order["price"] / market_config.price_tick)
if "bid_id" not in order.keys() or order["bid_id"] is None:
order["bid_id"] = f"{unit_id}_{i+1}"
order["bid_id"] = f"{unit_id}_{i + 1}"
order["unit_id"] = unit_id
bids.append(order)

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ oeds = [
"windpowerlib >=0.2.1",
]
test = [
"ruff >=0.4.9",
"ruff >=0.14.6",
"mypy >=1.1.1",
"matplotlib >=3.7.2",
"pytest >=9",
Expand Down
138 changes: 69 additions & 69 deletions tests/test_boiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,9 @@ def test_total_heat_production_electric(electric_boiler_model):
"""
model, _ = electric_boiler_model
total_heat = sum(pyo.value(model.boiler.heat_out[t]) for t in model.time_steps)
assert total_heat == pytest.approx(
400, rel=1e-2
), f"Total heat production for electric boiler is {total_heat}, expected 500."
assert total_heat == pytest.approx(400, rel=1e-2), (
f"Total heat production for electric boiler is {total_heat}, expected 500."
)


def test_total_heat_production_gas(gas_boiler_model):
Expand All @@ -211,9 +211,9 @@ def test_total_heat_production_gas(gas_boiler_model):
"""
model, _ = gas_boiler_model
total_heat = sum(pyo.value(model.boiler.heat_out[t]) for t in model.time_steps)
assert total_heat == pytest.approx(
400, rel=1e-2
), f"Total heat production for natural gas boiler is {total_heat}, expected 500."
assert total_heat == pytest.approx(400, rel=1e-2), (
f"Total heat production for natural gas boiler is {total_heat}, expected 500."
)


def test_electric_boiler_ramping_constraints(
Expand All @@ -233,12 +233,12 @@ def test_electric_boiler_ramping_constraints(
ramp_up = power_current - power_prev
ramp_down = power_prev - power_current

assert (
ramp_up <= ramp_up_limit + 1e-5
), f"Electric Boiler: Ramp-up at time {t} is {ramp_up}, exceeds limit of {ramp_up_limit}."
assert (
ramp_down <= ramp_down_limit + 1e-5
), f"Electric Boiler: Ramp-down at time {t} is {ramp_down}, exceeds limit of {ramp_down_limit}."
assert ramp_up <= ramp_up_limit + 1e-5, (
f"Electric Boiler: Ramp-up at time {t} is {ramp_up}, exceeds limit of {ramp_up_limit}."
)
assert ramp_down <= ramp_down_limit + 1e-5, (
f"Electric Boiler: Ramp-down at time {t} is {ramp_down}, exceeds limit of {ramp_down_limit}."
)


def test_gas_boiler_ramping_constraints(gas_boiler_model, gas_boiler_config):
Expand All @@ -256,12 +256,12 @@ def test_gas_boiler_ramping_constraints(gas_boiler_model, gas_boiler_config):
ramp_up = natural_gas_current - natural_gas_prev
ramp_down = natural_gas_prev - natural_gas_current

assert (
ramp_up <= ramp_up_limit + 1e-5
), f"Natural Gas Boiler: Ramp-up at time {t} is {ramp_up}, exceeds limit of {ramp_up_limit}."
assert (
ramp_down <= ramp_down_limit + 1e-5
), f"Natural Gas Boiler: Ramp-down at time {t} is {ramp_down}, exceeds limit of {ramp_down_limit}."
assert ramp_up <= ramp_up_limit + 1e-5, (
f"Natural Gas Boiler: Ramp-up at time {t} is {ramp_up}, exceeds limit of {ramp_up_limit}."
)
assert ramp_down <= ramp_down_limit + 1e-5, (
f"Natural Gas Boiler: Ramp-down at time {t} is {ramp_down}, exceeds limit of {ramp_down_limit}."
)


def test_electric_boiler_power_bounds(electric_boiler_model, electric_boiler_config):
Expand Down Expand Up @@ -296,9 +296,9 @@ def test_gas_boiler_power_bounds(gas_boiler_model, gas_boiler_config):
for t in model.time_steps:
natural_gas_in = pyo.value(model.boiler.natural_gas_in[t])
# For natural_gas, power_in is zero
assert (
natural_gas_in >= min_power - 1e-5
), f"Natural Gas Boiler: Natural gas input at time {t} is {natural_gas_in}, which is below the minimum power {min_power}."
assert natural_gas_in >= min_power - 1e-5, (
f"Natural Gas Boiler: Natural gas input at time {t} is {natural_gas_in}, which is below the minimum power {min_power}."
)
# Assuming there is an upper limit if applicable; adjust if necessary
# Since power_in is not applicable, we skip max_power for natural_gas
# If max_power applies to natural_gas_in, uncomment the following:
Expand All @@ -320,9 +320,9 @@ def test_electric_boiler_efficiency_constraint(
heat_out = pyo.value(model.boiler.heat_out[t])
power_in = pyo.value(model.boiler.power_in[t])
expected_heat_out = power_in * efficiency
assert (
heat_out == pytest.approx(expected_heat_out, rel=1e-2)
), f"Electric Boiler: Heat output at time {t} is {heat_out}, expected {expected_heat_out} based on efficiency."
assert heat_out == pytest.approx(expected_heat_out, rel=1e-2), (
f"Electric Boiler: Heat output at time {t} is {heat_out}, expected {expected_heat_out} based on efficiency."
)


def test_gas_boiler_efficiency_constraint(gas_boiler_model, gas_boiler_config):
Expand All @@ -336,9 +336,9 @@ def test_gas_boiler_efficiency_constraint(gas_boiler_model, gas_boiler_config):
heat_out = pyo.value(model.boiler.heat_out[t])
natural_gas_in = pyo.value(model.boiler.natural_gas_in[t])
expected_heat_out = natural_gas_in * efficiency
assert (
heat_out == pytest.approx(expected_heat_out, rel=1e-2)
), f"Natural Gas Boiler: Heat output at time {t} is {heat_out}, expected {expected_heat_out} based on efficiency."
assert heat_out == pytest.approx(expected_heat_out, rel=1e-2), (
f"Natural Gas Boiler: Heat output at time {t} is {heat_out}, expected {expected_heat_out} based on efficiency."
)


def test_electric_boiler_operational_status_constraints(
Expand Down Expand Up @@ -366,19 +366,19 @@ def test_electric_boiler_operational_status_constraints(
future_t = t + step
if future_t in model.time_steps:
status = pyo.value(operational_status[future_t])
assert (
status == 1
), f"Electric Boiler: Operational status at time {future_t} should be 1 after startup at {t}, but is {status}."
assert status == 1, (
f"Electric Boiler: Operational status at time {future_t} should be 1 after startup at {t}, but is {status}."
)

# Check minimum downtime steps after each shutdown
for t in shut_down_times:
for step in range(min_down_steps):
future_t = t + step
if future_t in model.time_steps:
status = pyo.value(operational_status[future_t])
assert (
status == 0
), f"Electric Boiler: Operational status at time {future_t} should be 0 after shutdown at {t}, but is {status}."
assert status == 0, (
f"Electric Boiler: Operational status at time {future_t} should be 0 after shutdown at {t}, but is {status}."
)


def test_electric_boiler_initial_operational_status(
Expand All @@ -391,9 +391,9 @@ def test_electric_boiler_initial_operational_status(
initial_status = electric_boiler_config["initial_operational_status"]
first_time_step = model.time_steps.first()
actual_status = pyo.value(model.boiler.operational_status[first_time_step])
assert (
actual_status == initial_status
), f"Electric Boiler: Initial operational status is {actual_status}, expected {initial_status}."
assert actual_status == initial_status, (
f"Electric Boiler: Initial operational status is {actual_status}, expected {initial_status}."
)


def test_gas_boiler_initial_operational_status(gas_boiler_model, gas_boiler_config):
Expand All @@ -410,13 +410,13 @@ def test_gas_boiler_initial_operational_status(gas_boiler_model, gas_boiler_conf
natural_gas_in = pyo.value(model.boiler.natural_gas_in[first_time_step])

if initial_status == 1:
assert (
natural_gas_in >= gas_boiler_config["min_power"] - 1e-5
), f"Natural Gas Boiler: Natural gas input at initial time step {first_time_step} is {natural_gas_in}, which is below the minimum power {gas_boiler_config['min_power']}."
assert natural_gas_in >= gas_boiler_config["min_power"] - 1e-5, (
f"Natural Gas Boiler: Natural gas input at initial time step {first_time_step} is {natural_gas_in}, which is below the minimum power {gas_boiler_config['min_power']}."
)
else:
assert (
natural_gas_in == 0
), f"Natural Gas Boiler: Natural gas input at initial time step {first_time_step} is {natural_gas_in}, but boiler is off."
assert natural_gas_in == 0, (
f"Natural Gas Boiler: Natural gas input at initial time step {first_time_step} is {natural_gas_in}, but boiler is off."
)


def test_electric_boiler_operating_cost(electric_boiler_model, price_profile):
Expand All @@ -428,9 +428,9 @@ def test_electric_boiler_operating_cost(electric_boiler_model, price_profile):
pyo.value(model.boiler.power_in[t]) * price_profile[t] for t in model.time_steps
)
total_model_cost = pyo.value(model.total_cost)
assert (
abs(total_calculated_cost - total_model_cost) < 1e-5
), f"Electric Boiler: Calculated total operating cost {total_calculated_cost} does not match model's total cost {total_model_cost}."
assert abs(total_calculated_cost - total_model_cost) < 1e-5, (
f"Electric Boiler: Calculated total operating cost {total_calculated_cost} does not match model's total cost {total_model_cost}."
)

# Additionally, verify individual operating costs if available
# If the model has variables or expressions for individual operating costs
Expand All @@ -447,9 +447,9 @@ def test_gas_boiler_operating_cost(gas_boiler_model, price_profile):
for t in model.time_steps
)
total_model_cost = pyo.value(model.total_cost)
assert (
abs(total_calculated_cost - total_model_cost) < 1e-5
), f"Natural Gas Boiler: Calculated total operating cost {total_calculated_cost} does not match model's total cost {total_model_cost}."
assert abs(total_calculated_cost - total_model_cost) < 1e-5, (
f"Natural Gas Boiler: Calculated total operating cost {total_calculated_cost} does not match model's total cost {total_model_cost}."
)


def test_electric_boiler_off_during_high_prices(electric_boiler_model, price_profile):
Expand All @@ -462,9 +462,9 @@ def test_electric_boiler_off_during_high_prices(electric_boiler_model, price_pro
price = price_profile[t]
power_in = pyo.value(model.boiler.power_in[t])
if price == 1000:
assert (
power_in == 0
), f"Electric Boiler: Boiler is on at time {t} despite high price {price}."
assert power_in == 0, (
f"Electric Boiler: Boiler is on at time {t} despite high price {price}."
)


def test_gas_boiler_min_power_enforcement(gas_boiler_model, gas_boiler_config):
Expand All @@ -477,13 +477,13 @@ def test_gas_boiler_min_power_enforcement(gas_boiler_model, gas_boiler_config):
for t in model.time_steps:
natural_gas_in = pyo.value(model.boiler.natural_gas_in[t])
if natural_gas_in > 0:
assert (
natural_gas_in >= min_power - 1e-5
), f"Natural Gas Boiler: Natural gas input at time {t} is {natural_gas_in}, which is below the minimum power {min_power}."
assert natural_gas_in >= min_power - 1e-5, (
f"Natural Gas Boiler: Natural gas input at time {t} is {natural_gas_in}, which is below the minimum power {min_power}."
)
else:
assert (
natural_gas_in == 0
), f"Natural Gas Boiler: Natural gas input at time {t} is {natural_gas_in}, but boiler is off."
assert natural_gas_in == 0, (
f"Natural Gas Boiler: Natural gas input at time {t} is {natural_gas_in}, but boiler is off."
)


# Hydrogen gas boiler tests
Expand All @@ -500,9 +500,9 @@ def test_hydrogen_boiler_model_solves_successfully(hydrogen_boiler_model):
def test_total_heat_production_hydrogen(hydrogen_boiler_model):
model, _ = hydrogen_boiler_model
total_heat = sum(pyo.value(model.boiler.heat_out[t]) for t in model.time_steps)
assert total_heat == pytest.approx(
400, rel=1e-2
), f"Total heat production for hydrogen gas boiler is {total_heat}, expected 400."
assert total_heat == pytest.approx(400, rel=1e-2), (
f"Total heat production for hydrogen gas boiler is {total_heat}, expected 400."
)


def test_hydrogen_boiler_ramping_constraints(
Expand All @@ -519,22 +519,22 @@ def test_hydrogen_boiler_ramping_constraints(
ramp_up = hydrogen_current - hydrogen_prev
ramp_down = hydrogen_prev - hydrogen_current

assert (
ramp_up <= ramp_up_limit + 1e-5
), f"Hydrogen Boiler: Ramp-up at time {t} is {ramp_up}, exceeds limit of {ramp_up_limit}."
assert (
ramp_down <= ramp_down_limit + 1e-5
), f"Hydrogen Boiler: Ramp-down at time {t} is {ramp_down}, exceeds limit of {ramp_down_limit}."
assert ramp_up <= ramp_up_limit + 1e-5, (
f"Hydrogen Boiler: Ramp-up at time {t} is {ramp_up}, exceeds limit of {ramp_up_limit}."
)
assert ramp_down <= ramp_down_limit + 1e-5, (
f"Hydrogen Boiler: Ramp-down at time {t} is {ramp_down}, exceeds limit of {ramp_down_limit}."
)


def test_hydrogen_boiler_max_power(hydrogen_boiler_model, hydrogen_boiler_config):
model, _ = hydrogen_boiler_model
max_power = hydrogen_boiler_config["max_power"]
for t in model.time_steps:
hydrogen_val = pyo.value(model.boiler.hydrogen_gas_in[t])
assert (
hydrogen_val <= max_power + 1e-5
), f"Hydrogen input at {t} exceeds max_power {max_power}"
assert hydrogen_val <= max_power + 1e-5, (
f"Hydrogen input at {t} exceeds max_power {max_power}"
)


if __name__ == "__main__":
Expand Down
Loading