For representing generic electrical tariffs
Project description
PyTariff
PyTariff is a library for the generic representation of electrical tariffs in domain models.
Installation
pip install pytariff
Basic Usage: Defining a Tariff
In the below example, we create a simple time-of-use tariff consisting of a single import charge and a single export charge. The tariff is defined over the time period from the first of January 2023 until the first of January 2024 in UTC.
The import charge is applied at all times of day (because start_time=time(0)
and end_time=time(0))
), on all days within the tariff definition period without exceptions for holidays. It defines a single charge on the Consumption
of energy in kWh in the Import
TradeDirection
with a value of 20.0 units in Australian dollars over the consumption range from 0 kWh to infinite kWh imported.
The charge is reset every three months (quarterly), starting from the anchor datetime, which is not useful in this example but becomes relevant if the UsageChargeMethod
is not identity
. Other UsageChargeMethod
s allow the user to define a tariff which charges on maximum demand in a quarter, for example, reset each quarter. The export charge is similar, but defined in the oposite TradeDirection
.
Naturally, many other combinations are possible. Obvious restrictions on tariff construction is achieved by using specific subclasses of the base PyTariff GenericTariff
object, such as the TimeofUseTariff
shown below, or other classes such as the BlockTariff
or MarketTariff
, to name a few.
import pytariff as pt
from zoneinfo import ZoneInfo
from datetime import datetime, time
# Define a Time-Of-Use Tariff with import and export charges
import_charge = pt.TariffInterval(
start_time=time(0),
end_time=time(0),
days_applied=pt.DaysApplied(day_types=pt.DayType.ALL_DAYS),
tzinfo=ZoneInfo("UTC"),
charge=pt.TariffCharge(
blocks=(
pt.TariffBlock(
rate=pt.TariffRate(currency="AUD", value=20.0),
from_quantity=0.0,
to_quantity=float("inf")
),
),
unit=pt.TariffUnit(
metric=pt.Consumption.kWh,
direction=pt.TradeDirection.Import,
convention=pt.SignConvention.Passive
),
reset_data=pt.ResetData(
anchor=datetime(2023, 1, 1, tzinfo=ZoneInfo("UTC")),
period=pt.ResetPeriod.FIRST_OF_QUARTER
),
method=pt.UsageChargeMethod.identity,
),
)
# define the export charge
export_charge = pt.TariffInterval(
start_time=time(0),
end_time=time(0),
days_applied=pt.DaysApplied(day_types=pt.DayType.ALL_DAYS),
tzinfo=ZoneInfo("UTC"),
charge=pt.TariffCharge(
blocks=(
pt.TariffBlock(
rate=pt.TariffRate(currency="AUD", value=-1.0),
from_quantity=0.0,
to_quantity=float("inf")
),
),
unit=pt.TariffUnit(
metric=pt.Consumption.kWh,
direction=pt.TradeDirection.Import,
convention=pt.SignConvention.Passive
),
reset_data=pt.ResetData(
anchor=datetime(2023, 1, 1, tzinfo=ZoneInfo("UTC")),
period=pt.ResetPeriod.FIRST_OF_QUARTER
),
method=pt.UsageChargeMethod.identity,
),
)
# define the parent time-of-use tariff
tou_tariff = TimeOfUseTariff(
start=datetime(2023, 1, 1),
end=datetime(2024, 1, 1),
tzinfo=ZoneInfo("UTC"),
children=(import_charge, export_charge),
)
Basic Usage: Applying a Tariff to Metering Data
Now that we have defined a tariff, we are able to investigate how costs are levied against energy usage. Before we begin, we must define metering data for the tariff to be applied towards, and provide a MeterProfileHandler
which can be used by PyTariff:
import pandas as pd
import numpy as np
from zoneinfo import ZoneInfo
meter_profile = pd.DataFrame(
index=pd.date_range(
start="2022-12-31T00:00:00",
end="2023-01-04T00:00:00",
tz=ZoneInfo("UTC"),
freq="1h",
inclusive="left",
),
data={"profile": np.tile(np.array([0.0] * 8 + [5.0] * 8 + [-1.0] * 8), 3)},
)
handler = MeterProfileHandler(meter_profile)
cost_df = tou_tariff.apply_to(
handler,
tariff_unit=TariffUnit(
metric=Consumption.kWh,
convention=SignConvention.Passive
),
)
We can call .apply_to
with our MeterProfileHandler
and a TariffUnit
which specifies that the metering data provided has the same units are the TariffCharges to which is it applied, and ensures the SignConvention
of the metering data is respected (as either Active or Passive).
The output cost_df
contains a breakdown of the costs by TariffCharge
and TariffBlock
combinations in each of the TradeDirection
s. It also contains columns which tally the total import_cost
, export_cost
, and total_cost
. This dataframe, and all the cost components, can be easily visualised by passing the results to a TariffCostHandler
:
cost_handler = TariffCostHandler(cost_df)
cost_handler.plot(include_additional_cost_components=True)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.