Skip to content

Commit

Permalink
add assume interface
Browse files Browse the repository at this point in the history
  • Loading branch information
maurerle committed Nov 5, 2024
1 parent bf9e3b8 commit 0993134
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 25 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ __pycache__
*.pyc
*.orig
*.egg-info
*.log
176 changes: 176 additions & 0 deletions emarketpy/assume.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# SPDX-FileCopyrightText: Florian Maurer
#
# SPDX-License-Identifier: AGPL-3.0-or-later

from assume.markets.base_market import MarketRole

from .clearing_algorithms.all_or_nothing import PayAsBidAonRole, PayAsClearAonRole
from .clearing_algorithms.contracts import PayAsBidContractRole
from .clearing_algorithms.simple import (
AverageMechanismRole,
McAfeeRole,
PayAsBidRole,
PayAsClearRole,
VCGAuctionRole,
)


class PayAsBidContractMarketRole(MarketRole, PayAsBidContractRole):
pass


class PayAsBidAonMarketRole(MarketRole, PayAsBidAonRole):
pass


class PayAsClearAonMarketRole(MarketRole, PayAsClearAonRole):
pass


class VCGMarketRole(MarketRole, VCGAuctionRole):
pass


class AverageMechanismMarketRole(MarketRole, AverageMechanismRole):
pass


class PayAsBidMarketRole(MarketRole, PayAsBidRole):
pass


class PayAsClearMarketRole(MarketRole, PayAsClearRole):
pass


class McAffeeMarketRole(MarketRole, McAfeeRole):
pass


clearing_mechanisms: dict[str, MarketRole] = {
"pay_as_clear": PayAsClearMarketRole,
"pay_as_bid": PayAsBidMarketRole,
"pay_as_bid_aon": PayAsBidAonRole,
"pay_as_clear_aon": PayAsClearAonMarketRole,
"pay_as_bid_contract": PayAsBidContractMarketRole,
"mc_affee": McAffeeMarketRole,
"average_mech": AverageMechanismMarketRole,
"vcg": VCGMarketRole,
}

# try importing pypsa if it is installed
try:
from .clearing_algorithms.nodal_pricing import NodalRole
from .clearing_algorithms.redispatch import RedispatchRole

class NodalMarketRole(MarketRole, NodalRole):
pass

class RedispatchMarketRole(MarketRole, RedispatchRole):
pass

clearing_mechanisms["redispatch"] = RedispatchMarketRole
clearing_mechanisms["nodal"] = NodalMarketRole

except ImportError:
pass

# try importing pyomo if it is installed
try:
from .clearing_algorithms.complex_clearing import ComplexClearingRole
from .clearing_algorithms.complex_clearing_dmas import ComplexDmasClearingRole

class ComplexDmasClearingMarketRole(MarketRole, ComplexDmasClearingRole):
pass

class ComplexClearingMarketRole(MarketRole, ComplexClearingRole):
pass

clearing_mechanisms["pay_as_clear_complex"] = ComplexClearingMarketRole
clearing_mechanisms["pay_as_clear_complex_dmas"] = ComplexDmasClearingMarketRole
except ImportError:
pass


if __name__ == "__main__":
from datetime import datetime, timedelta

from dateutil import rrule as rr
from dateutil.relativedelta import relativedelta as rd

from ..utils import MarketProduct, get_available_products
from .market_objects import MarketConfig, Orderbook

simple_dayahead_auction_config = MarketConfig(
"simple_dayahead_auction",
market_products=[MarketProduct(rd(hours=+1), 1, rd(hours=1))],
opening_hours=rr.rrule(
rr.HOURLY,
dtstart=datetime(2005, 6, 1),
cache=True,
),
opening_duration=timedelta(hours=1),
amount_unit="MW",
amount_tick=0.1,
price_unit="€/MW",
market_mechanism="pay_as_clear",
)

mr = MarketRole(simple_dayahead_auction_config)
next_opening = simple_dayahead_auction_config.opening_hours.after(datetime.now())
products = get_available_products(
simple_dayahead_auction_config.market_products, next_opening
)
assert len(products) == 1

print(products)
start = products[0][0]
end = products[0][1]
only_hours = products[0][2]

orderbook: Orderbook = [
{
"start_time": start,
"end_time": end,
"volume": 120,
"price": 120,
"agent_id": "gen1",
"only_hours": None,
},
{
"start_time": start,
"end_time": end,
"volume": 80,
"price": 58,
"agent_id": "gen1",
"only_hours": None,
},
{
"start_time": start,
"end_time": end,
"volume": 100,
"price": 53,
"agent_id": "gen1",
"only_hours": None,
},
{
"start_time": start,
"end_time": end,
"volume": -180,
"price": 70,
"agent_id": "dem1",
"only_hours": None,
},
]
simple_dayahead_auction_config.market_mechanism = clearing_mechanisms[
simple_dayahead_auction_config.market_mechanism
]
mr.all_orders = orderbook
clearing_result, meta = simple_dayahead_auction_config.market_mechanism(
mr, products
)
import pandas as pd

print(pd.DataFrame.from_dict(mr.all_orders))
print(pd.DataFrame.from_dict(clearing_result))
print(meta)
3 changes: 1 addition & 2 deletions emarketpy/base_market.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class MarketMechanism:
"""

def __init__(self, marketconfig: MarketConfig):
super().__init__(marketconfig)
super().__init__()
self.marketconfig = marketconfig

def clear(
Expand Down Expand Up @@ -275,7 +275,6 @@ async def opening(self):
else:
logger.debug("market %s - does not reopen", self.marketconfig.market_id)


def validate_registration(
self, content: RegistrationMessage, meta: MetaDict
) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions emarketpy/clearing_algorithms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
# SPDX-License-Identifier: AGPL-3.0-or-later

from ..market_objects import Orderbook
from ..base_market import MarketRole
from ..base_market import MarketMechanism

from .all_or_nothing import PayAsBidAonRole, PayAsClearAonRole
from .contracts import PayAsBidContractRole
from .simple import PayAsBidRole, PayAsClearRole

clearing_mechanisms: dict[str, MarketRole] = {
clearing_mechanisms: dict[str, MarketMechanism] = {
"pay_as_clear": PayAsClearRole,
"pay_as_bid": PayAsBidRole,
"pay_as_bid_aon": PayAsBidAonRole,
Expand Down
6 changes: 3 additions & 3 deletions emarketpy/clearing_algorithms/all_or_nothing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from itertools import groupby
from operator import itemgetter

from ..base_market import MarketRole
from ..base_market import MarketMechanism
from ..market_objects import MarketConfig, MarketProduct, Orderbook
from .simple import calculate_meta

Expand All @@ -32,7 +32,7 @@ def cumsum(orderbook: Orderbook):

# does not allow to have partially accepted bids
# all or nothing
class PayAsClearAonRole(MarketRole):
class PayAsClearAonRole(MarketMechanism):
def __init__(self, marketconfig: MarketConfig):
super().__init__(marketconfig)

Expand Down Expand Up @@ -117,7 +117,7 @@ def clear(


# does not allow to have partial accepted bids
class PayAsBidAonRole(MarketRole):
class PayAsBidAonRole(MarketMechanism):
def __init__(self, marketconfig: MarketConfig):
super().__init__(marketconfig)

Expand Down
6 changes: 3 additions & 3 deletions emarketpy/clearing_algorithms/auctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
from itertools import groupby
from operator import itemgetter

from ..base_market import MarketRole
from ..base_market import MarketMechanism
from ..market_objects import MarketConfig, MarketProduct, Orderbook
from .simple import calculate_meta

log = logging.getLogger(__name__)


class McAfeeRole(MarketRole):
class McAfeeRole(MarketMechanism):
def __init__(self, marketconfig: MarketConfig):
super().__init__(marketconfig)

Expand Down Expand Up @@ -151,7 +151,7 @@ def clear(
return accepted_orders, rejected_orders, meta, {}


class PayAsBidRole(MarketRole):
class PayAsBidRole(MarketMechanism):
def __init__(self, marketconfig: MarketConfig):
super().__init__(marketconfig)

Expand Down
4 changes: 2 additions & 2 deletions emarketpy/clearing_algorithms/complex_clearing.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import pyomo.environ as pyo
from pyomo.opt import SolverFactory, TerminationCondition, check_available_solvers

from ..base_market import MarketRole
from ..base_market import MarketMechanism
from ..market_objects import MarketConfig, MarketProduct, Orderbook
from ..utils import (
create_nodal_incidence_matrix,
Expand Down Expand Up @@ -275,7 +275,7 @@ def energy_balance_rule(model, node, t):
return instance, results


class ComplexClearingRole(MarketRole):
class ComplexClearingRole(MarketMechanism):
"""
Defines the clearing algorithm for the complex market.
Expand Down
4 changes: 2 additions & 2 deletions emarketpy/clearing_algorithms/complex_clearing_dmas.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from pyomo.environ import value as get_real_number
from pyomo.opt import SolverFactory, check_available_solvers

from ..base_market import MarketRole
from ..base_market import MarketMechanism
from ..market_objects import MarketConfig, MarketProduct, Order, Orderbook

log = logging.getLogger(__name__)
Expand All @@ -32,7 +32,7 @@
order_types = ["single_ask", "single_bid", "linked_ask", "exclusive_ask"]


class ComplexDmasClearingRole(MarketRole):
class ComplexDmasClearingRole(MarketMechanism):
required_fields = ["link", "block_id", "exclusive_id"]

def __init__(self, marketconfig: MarketConfig, verbose: bool = False):
Expand Down
4 changes: 2 additions & 2 deletions emarketpy/clearing_algorithms/nodal_pricing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pandas as pd
import pypsa

from ..base_market import MarketRole
from ..base_market import MarketMechanism
from ..grid_utils import (
add_backup_generators,
add_generators,
Expand All @@ -25,7 +25,7 @@
logging.getLogger("pypsa").setLevel(logging.WARNING)


class NodalMarketRole(MarketRole):
class NodalRole(MarketMechanism):
"""
A market role that performs market clearing at each node (bus) in an electricity network.
Expand Down
4 changes: 2 additions & 2 deletions emarketpy/clearing_algorithms/redispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pandas as pd
import pypsa

from ..base_market import MarketRole
from ..base_market import MarketMechanism
from ..grid_utils import (
add_redispatch_generators,
add_redispatch_loads,
Expand All @@ -24,7 +24,7 @@
logging.getLogger("pypsa").setLevel(logging.WARNING)


class RedispatchMarketRole(MarketRole):
class RedispatchRole(MarketMechanism):
"""
A market role that performs redispatch to resolve congestion in the electricity market.
It uses PyPSA to model the electricity network and perform the redispatch.
Expand Down
6 changes: 3 additions & 3 deletions emarketpy/clearing_algorithms/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from itertools import groupby
from operator import itemgetter

from ..base_market import MarketRole
from ..base_market import MarketMechanism
from ..market_objects import MarketConfig, MarketProduct, Orderbook

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -55,7 +55,7 @@ def calculate_meta(accepted_supply_orders, accepted_demand_orders, product):
}


class QuasiUniformPricingRole(MarketRole):
class QuasiUniformPricingRole(MarketMechanism):
def __init__(self, marketconfig: MarketConfig):
super().__init__(marketconfig)

Expand Down Expand Up @@ -388,7 +388,7 @@ def set_pricing(
return accepted_demand_orders + accepted_supply_orders


class PayAsBidRole(MarketRole):
class PayAsBidRole(MarketMechanism):
def __init__(self, marketconfig: MarketConfig):
super().__init__(marketconfig)

Expand Down
Loading

0 comments on commit 0993134

Please sign in to comment.