Your data¶
Attach the model from Your first model to data in files, and keep
what a solve produces. Only the data changes. Every block runs from the
examples/ folder of the repository.
The files¶
generators.csv
has one row for each generator:
generator,p_max,cost,p_min,no_load_cost
wind,80.0,10.0,0.0,0.0
solar,0.0,25.0,0.0,0.0
gas,200.0,50.0,50.0,500.0
load.csv
has the load in each snapshot:
The columns p_min and no_load_cost wait for a later tutorial.
From files to sources¶
Read both files with polars:
import polars as pl
import specsolve as sps
generators = pl.read_csv('tutorial/data/generators.csv')
load = pl.read_csv('tutorial/data/load.csv')
print(generators)
shape: (3, 5)
┌───────────┬───────┬──────┬───────┬──────────────┐
│ generator ┆ p_max ┆ cost ┆ p_min ┆ no_load_cost │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ f64 ┆ f64 ┆ f64 ┆ f64 │
╞═══════════╪═══════╪══════╪═══════╪══════════════╡
│ wind ┆ 80.0 ┆ 10.0 ┆ 0.0 ┆ 0.0 │
│ solar ┆ 0.0 ┆ 25.0 ┆ 0.0 ┆ 0.0 │
│ gas ┆ 200.0 ┆ 50.0 ┆ 50.0 ┆ 500.0 │
└───────────┴───────┴──────┴───────┴──────────────┘
Each parameter needs its own table with a value column, so you pick it out
of generators with select. load.csv already has that shape:
sources = {
'generator': generators['generator'],
'snapshot': load['snapshot'],
'p_max': generators.select('generator', value='p_max'),
'cost': generators.select('generator', value='cost'),
'load': load,
}
A source can also be a pandas frame or a parquet path; see the data contract.
Solve¶
The data is the same as before, so the cost is 10500 again.
Work with the answer¶
The answer is a polars table. Join it to the cost to see what each generator costs over the four snapshots:
spend = (
result.primal('p')
.join(generators, on='generator')
.group_by('generator')
.agg(spend=(pl.col('value') * pl.col('cost')).sum())
.sort('generator')
)
print(spend)
Gas costs 7500 and wind 3000, which add up to the objective.
Keep the run¶
archive= writes the spec, the sources and the answer to a folder:
import tempfile
from pathlib import Path
run = Path(tempfile.mkdtemp()) / 'first_run'
sps.solve('dispatch.yaml', sources, archive=run)
for file in sorted(run.rglob('*.parquet')):
print(file.relative_to(run))
sources/ holds each table as the solve read it, and answer/ holds one
file for each variable and constraint.
load_archive reads the answer
back without solving again:
To zip an archive, see Archiving a solve. To query many as one table, see Reading a directory of runs.
Next¶
In the next tutorial you change the data and solve again.