Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ with no data and no solver.**
A math-spec file declares four things: the axes the model runs over, such as
`snapshot` and `generator`; the data it expects, such as `load` and `cost`; the
decisions the solver makes, such as `dispatch`; and the rules those decisions
obey, such as `sum(dispatch, over=generator) == load`. The file
obey, such as `sum(dispatch, consume=generator) == load`. The file
[below](#example) is a complete model.

math-spec reads that file, checks everything that can be checked without data,
Expand Down Expand Up @@ -93,7 +93,7 @@ variables:
constraints:
power_balance:
dims: [snapshot]
expression: sum(dispatch, over=generator) == load
expression: sum(dispatch, consume=generator) == load

objective:
sense: minimize
Expand Down Expand Up @@ -381,7 +381,7 @@ through are a dependency rather than one engine's internals. The keys themselves
which are YAML math, a block per component, `dims:` and a `where:` string,
come from [Calliope](https://github.com/calliope-project/calliope).
[linopy](https://github.com/PyPSA/linopy) supplies the vocabulary that
`sum(over=)` and the dimension rules are named against. Issue numbers in these
`sum(consume=)` and the dimension rules are named against. Issue numbers in these
pages point at lpspec, where the arguments happened.

## Status
Expand Down
8 changes: 4 additions & 4 deletions docs/about/limits.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ instead.
### What a new primitive has to satisfy

**A macro must be able to call it.** Everything a modeller might pass in goes in
the value of a keyword argument, such as `over=snapshot`, never in the key. A
macro can write `over=d` and let the caller supply `d`. It could not do that if
the value of a keyword argument, such as `consume=snapshot`, never in the key. A
macro can write `consume=d` and let the caller supply `d`. It could not do that if
the dimension were the keyword itself.

**An operator may read the whole table. It pays one full pass over the data.**
`sum(p, over=g)` reads one row per generator. `shift(p, along=t, offset=1)` reads
`sum(p, consume=g)` reads one row per generator. `shift(p, along=t, offset=1)` reads
one row, the one before it. `x * y * a` reads the rows of `a` that pair an `x`
with a `y`. Each reads a bounded number of rows per output row, so an engine
builds the model one chunk of rows at a time.
Expand Down Expand Up @@ -71,7 +71,7 @@ quadratic case:
- **Where it stands.** More solvers and file formats take a quadratic objective
than a quadratic constraint. Which ones is the
[separate question below](#solver-capability).
- **A product of two sums.** `sum(x, over=i) * sum(y, over=j)` multiplies every
- **A product of two sums.** `sum(x, consume=i) * sum(y, consume=j)` multiplies every
term of the first sum by every term of the second, and the file does not say
how many terms either sum has. It is refused. `x[i] * y[j] * a[i, j]` is
allowed, because the table `a` says which pairs exist.
Expand Down
2 changes: 1 addition & 1 deletion docs/about/what-counts-as-language.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The test is one question:

Suppose the engine sums `p` over `generator` and the renderer prints a sum over
`snapshot`. The file now means two things, and that is a bug. So the language
decides what `sum(p, over=generator)` means, and both tools read the answer
decides what `sum(p, consume=generator)` means, and both tools read the answer
instead of working it out.

Suppose instead that the engine writes the model in one solver's file format and
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/commitment.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ expressions:
constraints:
power_balance:
dims: [snapshot]
expression: sum(dispatch, over=generator) == load
expression: sum(dispatch, consume=generator) == load
upper:
description: a unit that is not running produces nothing
dims: [snapshot, generator]
Expand Down
4 changes: 2 additions & 2 deletions docs/examples/dispatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ varies when it needs a base to change one thing in.

The `where:` on `dispatch` deletes the rows where a generator has no capacity, so
[absence](../reference/language/absence.md) is declared in the file rather than
checked at run time. `sum(dispatch, over=generator)` names the dimension it reduces, so
checked at run time. `sum(dispatch, consume=generator)` names the dimension it reduces, so
the constraint's `dims` is what remains.

<!-- gallery:begin -->
Expand All @@ -38,7 +38,7 @@ variables:
constraints:
power_balance:
dims: [snapshot]
expression: sum(dispatch, over=generator) == load
expression: sum(dispatch, consume=generator) == load

objective:
sense: minimize
Expand Down
24 changes: 12 additions & 12 deletions docs/examples/operators.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ objective: { sense: minimize, expression: sum(p) }

$`\sum_{t \in \mathcal{T},\ g \in \mathcal{G}} p_{t,g} \le \mathrm{budget}`$

### `sum(array, over=dim)`
### `sum(array, consume=dim)`

`examples/operators/sum.yaml`

```yaml
description: The plain reduction — `sum(array, over=dim)` collapses one dimension.
description: The plain reduction — `sum(array, consume=dim)` collapses one dimension.

dimensions:
snapshot: { dtype: int }
Expand All @@ -66,7 +66,7 @@ variables:
constraints:
fleet_total:
dims: [snapshot]
expression: sum(p, over=generator) <= limit
expression: sum(p, consume=generator) <= limit

objective: { sense: minimize, expression: sum(p) }
```
Expand Down Expand Up @@ -147,13 +147,13 @@ objective: { sense: minimize, expression: sum(p) }

$`\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = b \wedge \mathrm{gen\_tech}(g) = e} p_{t,g} \le \mathrm{limit}_{t,b,e} \qquad \forall\, t \in \mathcal{T},\ b \in \mathcal{B},\ e \in \mathcal{E}`$

### `sum(array, by=relation, over=a, into=b)`
### `sum(array, by=relation, consume=a, produce=b)`

`examples/operators/sum_by_columns.yaml`

```yaml
description: >-
A walk that names its ends — `sum(array, by=relation, over=a, into=b)`
A walk that names its ends — `sum(array, by=relation, consume=a, produce=b)`
consumes column `a` and lands on column `b`, and the other key column is
joined on, so each zone's total is taken per period.

Expand All @@ -176,20 +176,20 @@ variables:
constraints:
zone_balance:
dims: [zone, period]
expression: sum(p, by=zone_of, over=generator, into=zone) >= demand
expression: sum(p, by=zone_of, consume=generator, produce=zone) >= demand

objective: { sense: minimize, expression: sum(p) }
```

$`\sum_{g \in \mathcal{G} \,:\, \mathrm{zone\_of}(g,\ e) = z} p_{g,e} \ge \mathrm{demand}_{z,e} \qquad \forall\, z \in \mathcal{Z},\ e \in \mathcal{E}`$

### `sum(array, by=relation, over=[a, …], into=[b, …])`
### `sum(array, by=relation, consume=[a, …], produce=[b, …])`

`examples/operators/sum_by_column_lists.yaml`

```yaml
description: >-
A walk with several columns at each end — `sum(array, by=relation, over=[a, …], into=[b, …])`
A walk with several columns at each end — `sum(array, by=relation, consume=[a, …], produce=[b, …])`
consumes both key columns at once and lands on the product of both value
columns in one join.

Expand All @@ -213,7 +213,7 @@ variables:
constraints:
slot_cap:
dims: [bus, technology]
expression: sum(p, by=slot_of, over=[generator, period], into=[bus, technology]) <= cap
expression: sum(p, by=slot_of, consume=[generator, period], produce=[bus, technology]) <= cap

objective: { sense: minimize, expression: sum(p) }
```
Expand Down Expand Up @@ -254,13 +254,13 @@ objective: { sense: minimize, expression: sum(p) }

$`p_{t} \le \mathrm{cap}_{\mathrm{period\_of}(t)} \qquad \forall\, t \in \mathcal{T}`$

### `at(array, by=relation, over=a, into=b)`
### `at(array, by=relation, consume=a, produce=b)`

`examples/operators/at_columns.yaml`

```yaml
description: >-
A read that names its ends — `at(array, by=relation, over=a, into=b)`
A read that names its ends — `at(array, by=relation, consume=a, produce=b)`
reads column `a` where a table has two columns over one dimension, here the
sending end of a line.

Expand All @@ -282,7 +282,7 @@ variables:
constraints:
sending_cap:
dims: [line]
expression: f <= at(cap, by=ends, over=bus0, into=line)
expression: f <= at(cap, by=ends, consume=bus0, produce=line)

objective: { sense: minimize, expression: sum(f) }
```
Expand Down
36 changes: 18 additions & 18 deletions docs/examples/pypsa.md
Original file line number Diff line number Diff line change
Expand Up @@ -1578,7 +1578,7 @@ Generator_e_sum_min:
description: "`Generator-e_sum_min` — energy over the horizon is at least its floor; a floor of minus infinity is no row"
dims: [generator]
where: Generator_e_sum_min
expression: sum(Generator_p * snapshot_weightings_generators, over=snapshot) >= Generator_e_sum_min
expression: sum(Generator_p * snapshot_weightings_generators, consume=snapshot) >= Generator_e_sum_min
```

```math
Expand All @@ -1594,7 +1594,7 @@ Generator_e_sum_max:
description: "`Generator-e_sum_max` — energy over the horizon is at most its budget; a budget of infinity is no row"
dims: [generator]
where: Generator_e_sum_max
expression: sum(Generator_p * snapshot_weightings_generators, over=snapshot) <= Generator_e_sum_max
expression: sum(Generator_p * snapshot_weightings_generators, consume=snapshot) <= Generator_e_sum_max
```

```math
Expand Down Expand Up @@ -2362,7 +2362,7 @@ Kirchhoff_Voltage_Law:
impedance-weighted flows sum to nothing, which is what makes the linear
power flow physical rather than transport
dims: [snapshot, cycle]
expression: sum(Line_s * Line_cycle_weight, over=line) == 0
expression: sum(Line_s * Line_cycle_weight, consume=line) == 0
```

```math
Expand Down Expand Up @@ -3291,9 +3291,9 @@ primary_energy:
the charge left in weighted storage at the horizon's end; the initial
charge it is compared against is folded into the row's constant
expression: >-
sum(sum(Generator_p * snapshot_weightings_generators * Generator_primary_energy_weight, over=snapshot), over=generator)
- sum(sum(StorageUnit_state_of_charge * snapshot_is_last * StorageUnit_primary_energy_weight, over=snapshot), over=storage_unit)
- sum(sum(Store_e * snapshot_is_last * Store_primary_energy_weight, over=snapshot), over=store)
sum(sum(Generator_p * snapshot_weightings_generators * Generator_primary_energy_weight, consume=snapshot), consume=generator)
- sum(sum(StorageUnit_state_of_charge * snapshot_is_last * StorageUnit_primary_energy_weight, consume=snapshot), consume=storage_unit)
- sum(sum(Store_e * snapshot_is_last * Store_primary_energy_weight, consume=snapshot), consume=store)
```

```math
Expand All @@ -3309,9 +3309,9 @@ operational_limit:
generators deliver, plus what its non-cyclic storage draws down; the
initial charge it draws from is folded into the row's constant
expression: >-
sum(sum(Generator_p * snapshot_weightings_generators * Generator_operational_limit_weight, over=snapshot), over=generator)
- sum(sum(StorageUnit_state_of_charge * snapshot_is_last * StorageUnit_operational_limit_weight, over=snapshot), over=storage_unit)
- sum(sum(Store_e * snapshot_is_last * Store_operational_limit_weight, over=snapshot), over=store)
sum(sum(Generator_p * snapshot_weightings_generators * Generator_operational_limit_weight, consume=snapshot), consume=generator)
- sum(sum(StorageUnit_state_of_charge * snapshot_is_last * StorageUnit_operational_limit_weight, consume=snapshot), consume=storage_unit)
- sum(sum(Store_e * snapshot_is_last * Store_operational_limit_weight, consume=snapshot), consume=store)
```

```math
Expand All @@ -3324,8 +3324,8 @@ operational_limit:
transmission_volume_expansion:
description: what a `transmission_volume_expansion_limit` row totals — length times the chosen build of the row's branches
expression: >-
sum(Line_s_nom_ext * Line_volume_weight, over=line)
+ sum(Link_p_nom_ext * Link_volume_weight, over=link)
sum(Line_s_nom_ext * Line_volume_weight, consume=line)
+ sum(Link_p_nom_ext * Link_volume_weight, consume=link)
```

```math
Expand All @@ -3338,8 +3338,8 @@ transmission_volume_expansion:
transmission_expansion_cost:
description: what a `transmission_expansion_cost_limit` row totals — capital cost times the chosen build of the row's branches
expression: >-
sum(Line_s_nom_ext * Line_expansion_cost_weight, over=line)
+ sum(Link_p_nom_ext * Link_expansion_cost_weight, over=link)
sum(Line_s_nom_ext * Line_expansion_cost_weight, consume=line)
+ sum(Link_p_nom_ext * Link_expansion_cost_weight, consume=link)
```

```math
Expand All @@ -3352,11 +3352,11 @@ transmission_expansion_cost:
tech_capacity_expansion:
description: what a `tech_capacity_expansion_limit` row totals — the chosen build of the row's carrier-and-bus set
expression: >-
sum(Generator_p_nom_ext * Generator_tech_capacity_weight, over=generator)
+ sum(Link_p_nom_ext * Link_tech_capacity_weight, over=link)
+ sum(Line_s_nom_ext * Line_tech_capacity_weight, over=line)
+ sum(StorageUnit_p_nom_ext * StorageUnit_tech_capacity_weight, over=storage_unit)
+ sum(Store_e_nom_ext * Store_tech_capacity_weight, over=store)
sum(Generator_p_nom_ext * Generator_tech_capacity_weight, consume=generator)
+ sum(Link_p_nom_ext * Link_tech_capacity_weight, consume=link)
+ sum(Line_s_nom_ext * Line_tech_capacity_weight, consume=line)
+ sum(StorageUnit_p_nom_ext * StorageUnit_tech_capacity_weight, consume=storage_unit)
+ sum(Store_e_nom_ext * Store_tech_capacity_weight, consume=store)
```

```math
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/pypsa_losses.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ Kirchhoff_Voltage_Law:
impedance-weighted flows sum to nothing, which is what makes the linear
power flow physical rather than transport
dims: [snapshot, cycle]
expression: sum(Line_s * Line_cycle_weight, over=line) == 0
expression: sum(Line_s * Line_cycle_weight, consume=line) == 0
```

```math
Expand Down
8 changes: 4 additions & 4 deletions docs/examples/pypsa_stochastic.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ objective:
description: capacity once, operation in expectation, and a share of it at the tail
expression: >-
sum(Generator_p_nom_ext * Generator_capital_cost)
+ (1 - CVaR_omega) * sum(scenario_weight * scenario_opex, over=scenario)
+ (1 - CVaR_omega) * sum(scenario_weight * scenario_opex, consume=scenario)
+ CVaR_omega * CVaR
```

Expand Down Expand Up @@ -302,7 +302,7 @@ a_{s} - \mathit{scenario\_opex}_{s} + \theta \ge 0 \qquad \forall\, s \in \mathc
CVaR_def:
description: "`CVaR-def` — the tail's average is at least where it starts plus the expected excess over the tail's probability"
dims: []
expression: CVaR_theta + CVaR_inv_tail * sum(scenario_weight * CVaR_a, over=scenario) <= CVaR
expression: CVaR_theta + CVaR_inv_tail * sum(scenario_weight * CVaR_a, consume=scenario) <= CVaR
```

```math
Expand All @@ -315,8 +315,8 @@ CVaR_def:
scenario_opex:
description: what a future costs to run — the operating terms, before their weight
expression: >-
sum(sum(Generator_p * Generator_marginal_cost * snapshot_weightings_objective, over=generator), over=snapshot)
+ sum(sum(Link_p * Link_marginal_cost * snapshot_weightings_objective, over=link), over=snapshot)
sum(sum(Generator_p * Generator_marginal_cost * snapshot_weightings_objective, consume=generator), consume=snapshot)
+ sum(sum(Link_p * Link_marginal_cost * snapshot_weightings_objective, consume=link), consume=snapshot)
```

```math
Expand Down
8 changes: 4 additions & 4 deletions docs/reference/language/absence.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ constraints:
expression: x + y >= 1 # rows at wind and gas; no row at old
total:
dims: []
expression: sum(x + y, over=g) >= 1 # x[wind] + y[wind] + x[gas] + y[gas] >= 1
expression: sum(x + y, consume=g) >= 1 # x[wind] + y[wind] + x[gas] + y[gas] >= 1
split:
dims: []
expression: sum(x, over=g) + sum(y, over=g) >= 1 # x[old] is back in
expression: sum(x, consume=g) + sum(y, consume=g) >= 1 # x[old] is back in
```

`each` has no row at `old`, so there is no `x[old] >= 1`. `total` sums the
Expand All @@ -88,7 +88,7 @@ does an output slot stand for several input slots, or for one?

| Operator | An output slot reads | An absent input |
| -------------------------------- | ------------------------------- | ------------------------------------ |
| `sum(x, over=d)` | every position along `d` | is one summand fewer; the row stands |
| `sum(x, consume=d)` | every position along `d` | is one summand fewer; the row stands |
| `sum(x, by=relation)` | every member of the group | is one summand fewer; the row stands |
| `sum_back(x, along=d, window=w)` | the positions the window covers | is one summand fewer; the row stands |
| `shift(x, along=d, offset=n)` | one position, `n` back | _is_ the output, so it spreads |
Expand Down Expand Up @@ -148,7 +148,7 @@ them, and that is the start of the recurrence rather than a bug.
A [reported expression](reported.md) is arithmetic over solved numbers, so it
inherits their absence by the same rule as above. Through pointwise arithmetic,
a null spreads: `cost / delivered` has no value wherever either operand is
masked. Out of a summing operator, it does not: `sum(dispatch, over=g)` is one
masked. Out of a summing operator, it does not: `sum(dispatch, consume=g)` is one
summand shorter where a `dispatch[g]` is masked, and stands as long as one slot
does.

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/language/declarations.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ variables:
constraints:
power_balance:
dims: [snapshot]
expression: sum(dispatch, over=generator) == load
expression: sum(dispatch, consume=generator) == load
```

| Field | | |
Expand Down
Loading
Loading