# Tutorial 2: Calculations¶

In the first tutorial we decided what outputs we wanted from
our PV system power model. In the second tutorial we’ll create the calculations
that yield those desired outputs. In Carousel, a *calculation* is a combination
of formulas, data, and outputs that calculates outputs from formulas evaluated
using data and outputs as arguments. Each step in the calculation maps formula
input arguments to data and outputs and the return values to outputs. We already
explained in Tutorial 1: Outputs how Carousel defines *outputs*, and next in
Tutorial 3: Formulas and Tutorial 4: Data we’ll define what the terms *data* and
*formulas* mean.

## Calculation Class¶

Let’s keep using the `performance.py`

module we created in Tutorial 1: Outputs.
We’ll need to import the `Calc`

class to
create a new subclass for the calculations in our PV system power example. To
calculate the hourly energy and corresponding timestamps we’ll need to integrate
AC power over time and shift the timestamps to the end of each hour. Therefore
in this example, the hourly energy at the given timestamp corresponds to the
energy accumulated over the previous hour instead of the average power at that
timestamp. We can also roll up the hourly energy to output monthly and annual
values. We need to import the `CalcParameter`

class to define these calculation steps. Assuming the AC power and corresponding
timestamps are already outputs, and assuming that functions for energy
integration and roll-ups are already formulas we can specify this calculation as
follows:

```
from carousel.core.calculations import Calc, CalcParameter, Calculator
class UtilityCalcs(Calc):
"""
Calculations for PV Power demo
"""
energy = CalcParameter(
is_dynamic=False,
calculator=Calculator,
dependencies=["ac_power", "daterange"],
formula="f_energy",
args={"outputs": {"ac_power": "Pac", "times": "timestamps"}},
returns=["hourly_energy", "hourly_timeseries"]
)
monthly_rollup = CalcParameter(
is_dynamic=False,
calculator=Calculator,
dependencies=["energy"],
formula="f_rollup",
args={
"data": {"freq": "MONTHLY"},
"outputs": {"items": "hourly_energy",
"times": "hourly_timeseries"}
},
returns=["monthly_energy"]
)
yearly_rollup = CalcParameter(
is_dynamic=False,
calculator=Calculator,
dependencies=["energy"],
formula="f_rollup",
args={"data": {"freq": "YEARLY"},
"outputs": {"items": "hourly_energy",
"times": "hourly_timeseries"}},
returns=["annual_energy"]
)
```

## Calculation Attributes¶

In the snippet above, the calculation is called `UtilityCalcs`

, and it defines
three calculation parameters: `energy`

, `monthly_rollup`

, and
`yearly_rollup`

. Each calculation parameter has keyword arguments like
dependencies, `always_calc`

, and `frequency`

,
that describe attributes about the calculation parameter. All calculations
parameters and their attributes are stored in the calculation registry which the
simulation uses to run the model.

### Formulas, Arguments, and Returns¶

Calculations are sets of calculation parameters that describe the steps required
to calculate the desired outputs. Each step is a `CalcParameter`

that must at
least contain `formula`

, `args`

and `returns`

. The value of each is a
reference to the value in the corresponding registry. For example, in the
`UtilityCalc`

snippet above, the first calculation parameter, `energy`

, uses
the formula `f_energy`

which is the key for the corresponding function in the
`FormulaRegistry`

. The arguments to the formula
are given by `args`

which is a dictionary that maps the formula inputs with
either `data`

form the `DataRegistry`

or
`outputs`

from the `OutputRegistry`

. The first
key in `args`

tells you which registry and the following dictionary maps the
formula inputs to the registry keys. For example, `f_energy`

takes two inputs:
`ac_power`

and `times`

. To calculate `energy`

we use the outputs: `Pac`

and `timestamps`

. Formulas can be used with different arguments to return
different outputs by referring to different values in the data and output
registries respectively. For example, notice how `f_rollup`

is used twice,
once with the `freq`

argument set to the value of the data `MONTHLY`

and
return value set to the output `monthly_energy`

and then again with data
`YEARLY`

and output `annual_energy`

.

The following table lists the attributes that calculations can have. If given as positional arguments, then the order is the same as the table below; keyword arguments can be in any order.

Attribute | Description | Default |
---|---|---|

dependencies | list of required calculations | required |

always_calc | calculations ignore simulation thresholds | `False` |

frequency | dynamic calculations different from timestep | 1-interval |

formula | name of a function | required |

args | dictionary of data and outputs | required |

returns | name of outputs | required |

calculator | calculator class used to calculate this | `Calculator` |

is_dynamic | true if this is a periodic calculation | `False` |

### Static and Dynamic Calculations¶

The `is_dynamic`

attribute indicates whether the calculation parameter has a
time dependency or whether it is calculated once at the beginning of a
simulation. The simulation first calculates parameters with
`is_dynamic==False`

then loops over calculations with `is_dynamic==True`

for each timestep. The default value of `is_dynamic`

is `False`

.

#### Dynamic Calculations¶

Dynamic calculations depend on a previous timestep. To refer to arguments from previous timesteps use an index or to refer to a prior time use a quantity. In the example below, encapsulant browning depends on the previous timestep and the temperatures from the previous day.

```
encapsulant_browning = CalcParameter(
formula="f_encapsulant_browning",
args={
"data": {"encapsulant": "encapsulant"},
"outputs": {
"prev_encapsulant_browning": ["encapsulant_browning", -1],
"prev_day_cell_temp": ["Tcell", -1, "day"]
}
},
returns=["encapsulant_browning"]
)
```

### Calculators¶

The `calculator`

attribute sets the `Calculator`

class used to evaluate the
calculation. The default is `Calculator`

but
can be overriden to change how the calculation is performed. A `Calculator`

should implement a `calculate()`

method that takes the following arguments:

- dictionary of parameter
`formula`

,`args`

and`return`

keys - formula registry
- data registry
- outputs registry

For dynamic calculations, the `calculate`

method should take these additional
arguments:

- timestep, defaults to
`None`

for static calculations - index, defaults to
`None`

for static calculations

New in version 0.3.1.

### Meta Class Options¶

Calculation attributes can be specified for all parameters in a calculation by
declaring them in a nested `Meta`

class. If individual parameters also declare
the same attributes, then the parameter value will override the `Meta`

class
value. For example, in the `UtilityCalcs`

example, the attributes
`is_dynamic`

and `calculator`

are declared for all three parameters. Instead
these attributes could just be declared for all parameters in `UtilityCalcs`

by putting them the `Meta`

class.

```
class UtilityCalcs(Calc):
"""
Calculations for PV Power demo
"""
# same calculation parameters as above without is_dynamic and calculator
# default attributes for all parameters
class Meta:
is_dynamic = False
calculator = Calculator
```

## Parameter File¶

Calculations can also be specified in a parameter file. For example copy the
following into `PVPower/calculations/utils.json`

:

```
{
"energy": {
"is_dynamic": false,
"dependencies": ["ac_power", "daterange"],
"formula": "f_energy",
"args": {
"outputs": {"ac_power": "Pac", "times": "timestamps"}
},
"returns": ["hourly_energy", "hourly_timeseries"]
},
"monthly_rollup": {
"is_dynamic": false,
"dependencies": ["energy"],
"formula": "f_rollup",
"args": {
"data": {"freq": "MONTHLY"},
"outputs": {"items": "hourly_energy", "times": "hourly_timeseries"}
},
"returns": ["monthly_energy"]
},
"yearly_rollup": {
"is_dynamic": false,
"dependencies": ["energy"],
"formula": "f_rollup",
"args": {
"data": {"freq": "YEARLY"},
"outputs": {"items": "hourly_energy", "times": "hourly_timeseries"}
},
"returns": ["annual_energy"]
}
}
```

Just like the `Output`

class, we tell Carousel
about our calculations by specifying the parameter file in a
`Calc`

class. Create a new Python module
in the pvpower package called `performance.py`

, like we did above and add a
`Calc`

class for each calculation.

```
from carousel.core.calculations import Calc
import os
from pvpower import PROJ_PATH
class UtilityCalcs(Calc):
outputs_file = 'utils.json'
outputs_path = os.path.join(PROJ_PATH, 'calculations')
```