Using the datapackage-reader

[1]:
import os
import pandas as pd
import pkg_resources as pkg
import pprint

from pyomo.opt import SolverFactory
from oemof.solph import EnergySystem, Model
from oemof.tabular.facades import TYPEMAP
import oemof.tabular.tools.postprocessing as pp

from oemof.tabular import datapackage

Setting Path to Datapackage

The package comes with some example datapackage that you can use for testing. You can adapt this path to point to your datapackage. This scripts should work without any necessary additional changes.

[2]:
name = "investment" # choose from ['dispatch', 'investment']

# path to directory with datapackage to load
datapackage_dir = pkg.resource_filename(
    "oemof.tabular", "examples/datapackages/{}".format(name)
)

The results path points to your home directory, a subdirectory oemof-results and the name of the datapackage specified above.

[3]:
# create  path for results (we use the datapackage_dir to store results)
results_path = os.path.join(os.path.expanduser("~"), "oemof-results", name, "output")
if not os.path.exists(results_path):
    os.makedirs(results_path)

Setting attributmap and typemap

The two arguments allow for adjusting the datapackage reader to your needs. The attribute map lets you specifiy to map column names of your datapackage resource (field names) to the facades. Take the following example:

The Load facade requires the argument amount. If you like (for whatever reason) to use a different naming in your csv-file like total_energy you can do this be specifying the following:

from oemof.tabular import facades as fc

...

attributemap = {
    fc.Load: {'amount', 'total_energy'}
}

So you can set the attribute map individually for all facades. However, we will use no mapping here for attributemap argument.

[4]:
attributemap= {}

The typemap argument can be specified for your field (column name) type that specifcies which facade class should be used for instantiating the objects. We provide a default typemap. If you add your own facade classes, you must add these to typemap

typemap.update(
    {'my_new_class': my_class}
)
[5]:
typemap = TYPEMAP

# Look at current typemap
pprint.pprint(typemap)
{'backpressure': <class 'oemof.tabular.facades.BackpressureTurbine'>,
 'bus': <class 'oemof.solph.network.bus.Bus'>,
 'commodity': <class 'oemof.tabular.facades.Commodity'>,
 'conversion': <class 'oemof.tabular.facades.Conversion'>,
 'dispatchable': <class 'oemof.tabular.facades.Dispatchable'>,
 'electrical bus': <class 'oemof.solph.custom.electrical_line.ElectricalBus'>,
 'electrical line': <class 'oemof.solph.custom.electrical_line.ElectricalLine'>,
 'excess': <class 'oemof.tabular.facades.Excess'>,
 'extraction': <class 'oemof.tabular.facades.ExtractionTurbine'>,
 'generator': <class 'oemof.tabular.facades.Generator'>,
 'heatpump': <class 'oemof.tabular.facades.HeatPump'>,
 'link': <class 'oemof.tabular.facades.Link'>,
 'load': <class 'oemof.tabular.facades.Load'>,
 'reservoir': <class 'oemof.tabular.facades.Reservoir'>,
 'shortage': <class 'oemof.tabular.facades.Shortage'>,
 'storage': <class 'oemof.tabular.facades.Storage'>,
 'volatile': <class 'oemof.tabular.facades.Volatile'>}

Create EnergySystem from Datapackage

Using the .from_datapackge method, creating your EnergySystem is straight forward

[6]:
# create energy system object
es = EnergySystem.from_datapackage(
    os.path.join(datapackage_dir, "datapackage.json"),
    attributemap=attributemap,
    typemap=typemap,
)
pprint.pprint(
    {n.label: n for n in es.nodes}
)
{'bp': "<oemof.tabular.facades.BackpressureTurbine: 'bp'>",
 'bus0': "<oemof.solph.network.bus.Bus: 'bus0'>",
 'bus1': "<oemof.solph.network.bus.Bus: 'bus1'>",
 'coal-st': "<oemof.tabular.facades.Dispatchable: 'coal-st'>",
 'conn1': "<oemof.tabular.facades.Link: 'conn1'>",
 'conn2': "<oemof.tabular.facades.Link: 'conn2'>",
 'demand0': "<oemof.tabular.facades.Load: 'demand0'>",
 'demand1': "<oemof.tabular.facades.Load: 'demand1'>",
 'el-storage': "<oemof.tabular.facades.Storage: 'el-storage'>",
 'ext': "<oemof.tabular.facades.ExtractionTurbine: 'ext'>",
 'gas-bus': "<oemof.solph.network.bus.Bus: 'gas-bus'>",
 'gas-gt': "<oemof.tabular.facades.Dispatchable: 'gas-gt'>",
 'heat-bus': "<oemof.solph.network.bus.Bus: 'heat-bus'>",
 'lignite-st': "<oemof.tabular.facades.Dispatchable: 'lignite-st'>",
 'power2heat': "<oemof.tabular.facades.Conversion: 'power2heat'>",
 'pv': "<oemof.tabular.facades.Volatile: 'pv'>",
 'wind': "<oemof.tabular.facades.Volatile: 'wind'>"}

Create Model

This again is straight forward and just the way you would use the oemof.solph package.

[7]:
# check if the coin-branch-and-cut (cbc) solver library is available
cbc = SolverFactory('cbc').available()

if cbc:
    # create model from energy system (this is just oemof.solph)
    m = Model(es)

    # if you want dual variables / shadow prices uncomment line below
    # m.receive_duals()

    # select solver 'gurobi', 'cplex', 'glpk' etc
    m.solve("cbc")

    # get the results from the the solved model(still oemof.solph)
    results = m.results()
WARNING: Could not locate the 'cbc' executable, which is required for solver
    cbc

Writing Results

The nice thing about oemof.tabular.facades classes is their data model that allows for writing results in a standardized way. If you want more indidual result postprocessing, you can use all functionalities of the oemof.outputlib as the results object is a standard object.

[8]:
if cbc:
    # now we use the write results method to write the results in oemof-tabular
    # format
    pp.write_results(m, results, results_path)


Postprocessing Results

[9]:
if cbc:
    print(os.listdir(results_path))
    bus = 'bus0'
    path = os.path.join(results_path, ("").join([bus, '.csv']))
    df = pd.read_csv(path, index_col=0, parse_dates=True)