# Tariffs Annular supports simulating the effect of market interventions through various policies and tariffs. We aim to support a wide range of potential tariffs, and provide an easy interface for accessing their values in the internals of any bidding strategy. This page will explain the: - design philosophy - expected data format and schema - provided runtime interface ## Design philosophy Tariffs can be defined for many different scenarios, and are commonly separated according to both some categorical values and some temporal aspect. Each tariff should be recorded in a separate file to avoid having to specify unnecessary values for all possible index combinations. This means that each file only specifies the required indexing levels relevant for that particular tariff. As an added benefit, this makes the system very modular, as replacing a single tariff means exactly replacing a single file, without being bound by indexing levels of those other tariffs. In use, we see the main distinction between 'categorial' and 'temporal' index levels, with the categorical index assumed to be fixed during the runtime of a simulation. This leaves the temporal index to be selected at runtime through a simple interface. We acknowledge that some of these categories may depend on the maximum used capacity, with jumps in tariff value between them. In such cases, we assume that the final category in which you end up is known to you beforehand with a high degree of certainty. ## Data format and schema All tariffs should be defined in [tidy][tidy-verse] CSV files. A single CSV file `.csv` should contain the full specification of a _single_ tariff. The name of the file will be used as the identifier for that tariff when loaded. This name is not case-sensitive. The collection of tariff files should be contained in a single folder. This should include any other tariff-related variables such as weighting factors. Each CSV file should be formatted as follows: | grid level | consumer type | ... | year | ... | hour | value | |------------|---------------|-----|------|-----|------|-------| | ... | ... | ... | ... | ... | ... | ... | In order, the file should contain the following columns, preferably in this order: - Categorical index levels (grid level, consumer type, ...) - Temporal index levels if relevant (year, ..., hour) - Value The names of these columns are case-insensitive. They will all be cast to lowercase upon being loaded. Each file should only contain those columns that are necessary to specify the tariff. E.g., if there is no monthly variance in a tariff, a `month` column should not be specified. ## Runtime interface A folder of tariffs can be loaded using the [`TariffManager.from_folder()`] method. This takes an argument of type `Path` pointing to the folder containing the collection of CSV files defining the tariffs. Additionally, a dictionary of categorical index keys must be passed in with the `preselect` argument to select values that remain fixed for the runtime of the simulation. Once the [`TariffManager`] has been instantiated, tariff values can be retrieved by name using the various fetching methods. ### Fetch types We distinguish between the following 'tariff fetching scenarios': 1. A tariff is not temporally indexed (temporally least granular) 2. A tariff is indexed by each hour (temporally most granular) 3. A tariff is temporally indexed, but not by the hour (intermediate temporal granularity) There is a separate fetching function for each of these scenarios with different corresponding behavior. While the first scenario only needs the tariff name, the fetching functions for temporally indexed tariffs both require a timeseries as input. Based on the timestamps in this timeseries, the corresponding tariff values are then returned: - Tariff values are needed for given timestamps: use [`fetch_timeseries(name, timestamps)`][`fetch_timeseries`], with `timestamps` as its index. With this call, the timestamps are parsed using the provided temporal index columns, to fetch the appropriate value for each timestamp. For example, given the following monthly and hourly indexed tariff: | month | hour | value | |-------|------|-------| | ... | ... | ... | | 1 | 0 | 10 | | 1 | 1 | 11 | | ... | ... | ... | | 2 | 0 | 20 | | 2 | 1 | 21 | | ... | ... | ... | The following result is retrieved when fetching with hourly timestamps: `2025-01-30 00:00, 2025-01-30 01:00, 2025-01-30 02:00, ..., 2025-02-02 23:00`: | timestamp | value | |------------------|-------| | 2025-01-30 00:00 | 10 | | 2025-01-30 01:00 | 11 | | ... | ... | | 2025-01-31 00:00 | 10 | | 2025-01-31 01:00 | 11 | | ... | ... | | 2025-02-01 00:00 | 20 | | 2025-02-01 01:00 | 21 | | ... | ... | | 2025-02-02 00:00 | 20 | | 2025-02-02 01:00 | 21 | | ... | ... | - Only certain tariff values are needed, based on given timestamps: use [`fetch_indexed(name, timestamps)`][`fetch_indexed`] In these cases there is no need for a value per timestamp, but only those values that are relevant for the given window. An example might be values for a monthly capacity tariff. This fetch function selects all rows that match the given timestamps, and returns them as-is with their original index columns. For example, given the following monthly indexed tariff: | month | value | |-------|-------| | 1 | 5 | | 2 | 6 | | ... | ... | The following result is retrieved when fetching with hourly timestamps: `2025-01-30 00:00, 2025-01-30 01:00, 2025-01-30 02:00, ..., 2025-02-02 23:00`: | month | value | |-------|-------| | 1 | 5 | | 2 | 6 | ### Temporal index level parsing Since all remaining index levels are temporal in nature, the `timestamps` argument of the [`fetch_timeseries`] and [`fetch_indexed`] methods is used to select the relevant values. The [`TariffManager`] will parse the given timestamps to match with the temporal index columns. The available parsing options are listed below with the associated valid values. Note that the column names are not case-sensitive. - `"year"`: integers, e.g. 2025, 2026, etc. - `"month"`: integers 1 ... 12, with optional leading zeros (e.g. 01). - `"weekday/weekend"` or `"weekend/weekday"`: litteral strings `"weekday"` or `"weekend"` (where Dutch national holidays are included in the 'weekend' category). Note that the entry values `"weekday"` and `"weekend"` must be lowercase. - `"hour"`: integers 0 ... 23, with optional leading zeros (e.g. 00). [`fetch_indexed`]: #annular.tariffs.TariffManager.fetch_indexed [`fetch_timeseries`]: #annular.tariffs.TariffManager.fetch_timeseries [`TariffManager`]: #annular.tariffs.TariffManager [`TariffManager.from_folder()`]: #annular.tariffs.TariffManager.from_folder [tidy-verse]: https://r4ds.hadley.nz/data-tidy.html