Skip to main content

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 UsageChargeMethods 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 TradeDirections. 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)

Example TOU Tariff

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytariff-0.0.3.tar.gz (36.2 kB view hashes)

Uploaded Source

Built Distribution

pytariff-0.0.3-py3-none-any.whl (42.1 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page