Esempio n. 1
0
def simulate(es=None, **arguments):
    """Creates the optimization model, solves it and writes back results to
    energy system object

    Parameters
    ----------
    es : :class:`oemof.solph.network.EnergySystem` object
       Energy system holding nodes, grouping functions and other important
       information.
    **arguments : key word arguments
        Arguments passed from command line
    """

    logging.info("Creating optimization model...")
    om = OperationalModel(es=es, constraint_groups=ADD_SOLPH_BLOCKS)

    if arguments['--loglevel'] == 'DEBUG':
        lppath = os.path.join(arguments['--output-directory'], 'lp-file')
        if not os.path.exists(lppath):
            os.mkdir(lppath)
        lpfilepath = os.path.join(lppath,
                                  ''.join([om.name, '_', es.timestamp, '.lp']))
        logging.info("Writing lp-file to '{}'".format(lpfilepath))
        om.write(lpfilepath, io_options={'symbolic_solver_labels': True})

    logging.info('Solving optimization model...')

    om.solve(arguments['--solver'],
             solve_kwargs={'tee': arguments['--solver-output']},
             cmdline_options={"mipgap": arguments.get('--mipgap', 0)})

    om.results()

    return om
Esempio n. 2
0
    def test_bus_to_sink_outputs_in_results_dataframe(self):
        bus = Bus(uid="bus")
        source = FS(label="source", outputs={bus: Flow(nominal_value=1, actual_value=0.5, fixed=True)})
        sink = Sink(label="sink", inputs={bus: Flow(nominal_value=1)})

        es = self.es
        om = OM(es)
        es.results = om.results()
        es.results[bus][sink] = [0.7]
        rdf = RDF(energy_system=es)
        try:
            eq_(
                rdf.loc[(slice(None), slice(None), slice(None), "sink"), :].val[0],
                0.7,
                "Output from bus to sink does not have the correct value.",
            )
        except KeyError:
            self.failed = True
        if self.failed:
            ok_(False, "Output from bus to sink does not appear in results dataframe.")

        es.results[bus][bus] = [-1]
        rdf = RDF(energy_system=es)
        try:
            eq_(
                rdf.loc[(slice(None), slice(None), slice(None), "sink"), :].val[0],
                0.7,
                "Output from bus to sink does not have the correct value.",
            )
        except KeyError:
            self.failed = True
        if self.failed:
            ok_(False, "Output from bus (with duals) to sink " + "does not appear in results dataframe.")
Esempio n. 3
0
    def test_issue_74(self):
        Storage.optimization_options.update({"investment": True})
        bus = Bus(uid="bus")
        store = Storage(uid="store", inputs=[bus], outputs=[bus], c_rate_out=0.1, c_rate_in=0.1)
        sink = Sink(uid="sink", inputs=[bus], val=[1])

        es = self.es
        om = OM(es)
        om.objective.set_value(-1)
        es.results = om.results()

        try:
            es.dump()
        except AttributeError as ae:
            self.failed = ae
        if self.failed:
            ok_(
                False, "EnergySystem#dump should not raise `AttributeError`: \n" + " Error message: " + str(self.failed)
            )
Esempio n. 4
0
    def test_bus_to_sink_outputs_in_results_dataframe(self):
        bus = Bus(uid="bus")
        source = FS(
            label="source",
            outputs={bus: Flow(nominal_value=1, actual_value=0.5, fixed=True)})
        sink = Sink(label="sink", inputs={bus: Flow(nominal_value=1)})

        es = self.es
        om = OM(es)
        es.results = om.results()
        es.results[bus][sink] = [0.7]
        rdf = RDF(energy_system=es)
        try:
            eq_(
                rdf.loc[(slice(None), slice(None), slice(None),
                         "sink"), :].val[0], 0.7,
                "Output from bus to sink does not have the correct value.")
        except KeyError:
            self.failed = True
        if self.failed:
            ok_(
                False,
                "Output from bus to sink does not appear in results dataframe."
            )

        es.results[bus][bus] = [-1]
        rdf = RDF(energy_system=es)
        try:
            eq_(
                rdf.loc[(slice(None), slice(None), slice(None),
                         "sink"), :].val[0], 0.7,
                "Output from bus to sink does not have the correct value.")
        except KeyError:
            self.failed = True
        if self.failed:
            ok_(
                False, "Output from bus (with duals) to sink " +
                "does not appear in results dataframe.")
Esempio n. 5
0
    def test_issue_74(self):
        Storage.optimization_options.update({'investment': True})
        bus = Bus(uid="bus")
        store = Storage(uid="store",
                        inputs=[bus],
                        outputs=[bus],
                        c_rate_out=0.1,
                        c_rate_in=0.1)
        sink = Sink(uid="sink", inputs=[bus], val=[1])

        es = self.es
        om = OM(es)
        om.objective.set_value(-1)
        es.results = om.results()

        try:
            es.dump()
        except AttributeError as ae:
            self.failed = ae
        if self.failed:
            ok_(
                False,
                "EnergySystem#dump should not raise `AttributeError`: \n" +
                " Error message: " + str(self.failed))
Esempio n. 6
0
def simulate(energysystem,
             filename=None,
             solver='cbc',
             tee_switch=True,
             keep=True):
    """
    """
    if filename is None:
        filename = os.path.join(os.path.dirname(__file__), 'input_data.csv')
    logging.info("Creating objects")
    data = pd.read_csv(filename, sep=",")
    # resource buses
    bcoal = Bus(label="coal", balanced=False)
    bgas = Bus(label="gas", balanced=False)
    boil = Bus(label="oil", balanced=False)
    blig = Bus(label="lignite", balanced=False)

    # electricity and heat
    b_el = Bus(label="b_el")
    b_th = Bus(label="b_th")

    # adding an excess variable can help to avoid infeasible problems
    Sink(label="excess", inputs={b_el: Flow()})

    # adding an excess variable can help to avoid infeasible problems
    # Source(label="shortage", outputs={b_el: Flow(variable_costs=200)})

    # Sources
    Source(label="wind",
           outputs={
               b_el:
               Flow(actual_value=data['wind'], nominal_value=66.3, fixed=True)
           })

    Source(label="pv",
           outputs={
               b_el: Flow(actual_value=data['pv'],
                          nominal_value=65.3,
                          fixed=True)
           })

    # Demands (electricity/heat)
    Sink(label="demand_el",
         inputs={
             b_el:
             Flow(nominal_value=85, actual_value=data['demand_el'], fixed=True)
         })

    Sink(label="demand_th",
         inputs={
             b_th:
             Flow(nominal_value=40, actual_value=data['demand_th'], fixed=True)
         })

    # Power plants
    LinearTransformer(
        label='pp_coal',
        inputs={bcoal: Flow()},
        outputs={b_el: Flow(nominal_value=20.2, variable_costs=25)},
        conversion_factors={b_el: 0.39})

    LinearTransformer(
        label='pp_lig',
        inputs={blig: Flow()},
        outputs={b_el: Flow(nominal_value=11.8, variable_costs=19)},
        conversion_factors={b_el: 0.41})

    LinearTransformer(
        label='pp_gas',
        inputs={bgas: Flow()},
        outputs={b_el: Flow(nominal_value=41, variable_costs=40)},
        conversion_factors={b_el: 0.50})

    LinearTransformer(label='pp_oil',
                      inputs={boil: Flow()},
                      outputs={b_el: Flow(nominal_value=5, variable_costs=50)},
                      conversion_factors={b_el: 0.28})

    # CHP
    LinearTransformer(label='pp_chp',
                      inputs={bgas: Flow()},
                      outputs={
                          b_el: Flow(nominal_value=30, variable_costs=42),
                          b_th: Flow(nominal_value=40)
                      },
                      conversion_factors={
                          b_el: 0.3,
                          b_th: 0.4
                      })

    # Heatpump with a coefficient of performance (COP) of 3
    b_heat_source = Bus(label="b_heat_source")

    Source(label="heat_source", outputs={b_heat_source: Flow()})

    cop = 3
    LinearN1Transformer(label='heat_pump',
                        inputs={
                            b_el: Flow(),
                            b_heat_source: Flow()
                        },
                        outputs={b_th: Flow(nominal_value=10)},
                        conversion_factors={
                            b_el: cop,
                            b_heat_source: cop / (cop - 1)
                        })

    # ################################ optimization ###############################
    # create Optimization model based on energy_system
    logging.info("Create optimization problem")
    om = OperationalModel(es=energysystem)

    # solve with specific optimization options (passed to pyomo)
    logging.info("Solve optimization problem")
    om.solve(solver=solver,
             solve_kwargs={
                 'tee': tee_switch,
                 'keepfiles': keep
             })

    # write back results from optimization object to energysystem
    om.results()

    return om
Esempio n. 7
0
def simulate(folder, **kwargs):
    # This is how you get a scenario object from the database.
    # Since the iD editor prefixes element ids with their type ('r' for
    # relation, 'w' for way and 'n' for node), we have to strip a leading
    # character from the scenario id string before converting it to int.
    # This is what the [1:] is for.

    engine = db.engine(osm.configsection)

    Session = sessionmaker(bind=engine)
    session = Session()

    scenario = session.query(
        osm.Relation).filter_by(id=int(kwargs['scenario'][1:])).first()
    #id = 1).first()

    # Delete the scenario id from `kwargs` so that is doesn't show up in the
    # response later.
    del kwargs['scenario']

    # Now you can access the nodes, ways and relations this scenario contains
    # and build oemof objects from them. I'll only show you how to access the
    # contents here.
    # These are lists with Node, Way and Relation objects.
    # See the .schemas.osm module for the API.
    elements = scenario.elements
    nodes = [n for n in elements if isinstance(n, osm.Node)]
    ways = [w for w in elements if isinstance(w, osm.Way)]
    relations = [r for r in elements if isinstance(r, osm.Relation)]

    # emission factor (hardcoded for now....) t/MWh
    emission_factors = {
        'gas': 0.2,
        'coal': 0.34,
        'oil': 0.27,
        'lignite': 0.4,
        'waste': 0.3,
        'biomass': 0,
        'wind': 0,
        'solar': 0
    }
    #########################################################################
    # OEMOF SOLPH
    #########################################################################
    # We need a datetimeindex for the optimization problem / energysystem
    first = pd.to_datetime(scenario.tags.get('scenario_year' + '0101', '2016'))
    start = first + pd.DateOffset(
        hours=int(scenario.tags.get('start_timestep', 1)) - 1)
    end = first + pd.DateOffset(
        hours=int(scenario.tags.get('end_timestep', 8760)) - 1)
    datetimeindex = pd.date_range(start=start, end=end, freq='H')

    energy_system = EnergySystem(groupings=GROUPINGS, timeindex=datetimeindex)

    ## CREATE BUSES FROM RELATIONS OF TYPE "HUB RELATION"
    buses = {}
    for r in relations:
        if r.tags.get('type') is not None:
            if r.tags['type'] == 'hub_relation':
                name = r.tags.get('name')
                buses[name] = Bus(label=str(name))
                buses[name].energy_sector = r.tags['energy_sector']
        else:
            raise ValueError('Missing tag type of component with ' +
                             'name {0}.'.format(r.tags['name']))

    ## GLOBAL FUEL BUSES FOR TRANSFORMER INPUTS (THAT ARE NOT IN RELATIONS)
    global_buses = {}
    for n in nodes:
        if n.tags.get('oemof_class') == 'linear_transformer':
            # Only create global bus if not already exist
            if global_buses.get(n.tags['fuel_type']) is None:
                global_buses[n.tags['fuel_type']] = Bus(
                    label=n.tags['fuel_type'], balanced=False)

    ## Create Nodes (added automatically to energysystem)
    for n in nodes:
        # GET RELATIONS 'HUB ASSIGNMENT' FOR NODE
        node_bus = [
            r.tags['name'] for r in n.referencing_relations
            if r.tags['name'] in list(buses.keys())
        ]
        # create the variable cost timeseries if specified, otherwise use
        # variable costs key from tags
        if n.tags.get('variable_costs', 0) == 'timeseries':
            variable_costs = n.timeseries.get('variable_costs')
            if variable_costs is None:
                raise ValueError('No timeseries `variable cost` found for ' +
                                 'node {0}.'.format(n.tags.get('name')))
        else:
            variable_costs = _float(n, 'variable_costs')

        # CREATE SINK OBJECTS
        if n.tags.get('oemof_class') == 'sink':
            if n.tags.get('energy_amount') is None:
                nominal_value = None
                if n.timeseries.get('load_profile') is not None:
                    raise ValueError('No enery amount has been specified' +
                                     ' but the load_profile has been set!')
            else:
                nominal_value = _float(n, 'energy_amount')
            # calculate actual value
            if n.timeseries.get('load_profile') is None:
                actual_value = None
            else:
                try:
                    actual_value = [
                        i / sum(n.timeseries.get('load_profile'))
                        for i in n.timeseries.get('load_profile')
                    ]
                except Exception:
                    actual_value = None
            s = Sink(label=n.tags['name'],
                     inputs={
                         buses[node_bus[0]]:
                         Flow(nominal_value=nominal_value,
                              actual_value=actual_value,
                              variable_costs=variable_costs,
                              fixed=True)
                     })
            s.type = n.tags['type']
        # CREATE SOURCE OBJECTS
        if n.tags.get('oemof_class') == 'source':
            s = Source(label=n.tags['name'],
                       outputs={
                           buses[node_bus[0]]:
                           Flow(nominal_value=_float(n, 'installed_power'),
                                actual_value=n.timeseries['load_profile'],
                                variable_costs=variable_costs,
                                fixed=True)
                       })
            s.fuel_type = n.tags['fuel_type']
            s.type = n.tags['type']
        # CREATE TRANSFORMER OBJECTS
        if n.tags.get('oemof_class') == 'linear_transformer':
            # CREATE LINEAR TRANSFORMER
            if n.tags.get('type') == 'flexible_generator':
                ins = global_buses[n.tags['fuel_type']]
                outs = buses[node_bus[0]]
                t = LinearTransformer(
                    label=n.tags['name'],
                    inputs={ins: Flow(variable_costs=variable_costs)},
                    outputs={
                        outs: Flow(nominal_value=_float(n, 'installed_power'))
                    },
                    conversion_factors={outs: _float(n, 'efficiency')})
                # store fuel_type as attribute for identification
                t.fuel_type = n.tags['fuel_type']
                t.type = n.tags['type']

            # CREATE COMBINED HEAT AND POWER AS LINEAR TRANSFORMER
            if n.tags.get('type') == 'combined_flexible_generator':
                ins = global_buses[n.tags['fuel_type']]
                heat_out = [
                    buses[k] for k in node_bus
                    if buses[k].energy_sector == 'heat'
                ][0]
                power_out = [
                    buses[k] for k in node_bus
                    if buses[k].energy_sector == 'electricity'
                ][0]
                t = LinearTransformer(
                    label=n.tags['name'],
                    inputs={ins: Flow(variable_costs=variable_costs)},
                    outputs={
                        power_out:
                        Flow(nominal_value=_float(n, 'installed_power')),
                        heat_out: Flow()
                    },
                    conversion_factors={
                        heat_out: _float(n, 'thermal_efficiency'),
                        power_out: _float(n, 'electrical_efficiency')
                    })
                t.fuel_type = n.tags['fuel_type']
                t.type = n.tags['type']

        # CRAETE STORAGE OBJECTS
        if n.tags.get('oemof_class') == 'storage':
            # Oemof solph does not provide direct way to set power in/out of
            # storage hence, we need to caculate the needed ratios upfront
            nicr = (_float(n, 'installed_power') /
                    _float(n, 'installed_energy'))
            nocr = (_float(n, 'installed_power') /
                    _float(n, 'installed_energy'))
            s = Storage(label=n.tags['name'],
                        inputs={
                            buses[node_bus[0]]:
                            Flow(variable_costs=variable_costs)
                        },
                        outputs={
                            buses[node_bus[0]]:
                            Flow(variable_costs=variable_costs)
                        },
                        nominal_capacity=_float(n, 'installed_energy'),
                        nominal_input_capacity_ratio=nicr,
                        nominal_output_capacity_ration=nocr)
            s.energy_sector = n.tags['energy_sector']
            s.type = n.tags['type']

    # loop over all ways to create transmission objects
    for w in ways:
        way_bus = [
            r.tags['name'] for r in w.referencing_relations
            if r.tags['name'] in list(buses.keys())
        ]
        if w.tags.get('oemof_class') == 'linear_transformer':
            # CREATE TWO TRANSFORMER OBJECTS WITH DIFFERENT DIRECTIONS IN/OUTS
            if w.tags.get('type') == 'transmission':
                # transmission lines are modelled as two transformers with
                # the same technical parameters
                ins = buses[way_bus[0]]
                outs = buses[way_bus[1]]
                # 1st transformer
                t1 = LinearTransformer(
                    label=w.tags['name'] + '_1',
                    inputs={outs: Flow()},
                    outputs={
                        ins: Flow(nominal_value=_float(w, 'installed_power'))
                    },
                    conversion_factors={ins: _float(w, 'efficiency')})
                t1.type = w.tags.get('type')
                # 2nd transformer
                t2 = LinearTransformer(
                    label=w.tags['name'] + '_2',
                    inputs={ins: Flow()},
                    outputs={
                        outs: Flow(nominal_value=_float(w, 'installed_power'))
                    },
                    conversion_factors={outs: _float(w, 'efficiency')})
                t2.type = w.tags.get('type')

    # Create optimization model, solve it, wrtie back results
    om = OperationalModel(es=energy_system)

    solver = scenario.tags.get('solver')
    if solver is None:
        solver = 'glpk'

    om.solve(solver=solver, solve_kwargs={'tee': True, 'keepfiles': False})
    om.results()

    # create results dataframe based on oemof's outputlib (multiindex)
    esplot = output.DataFramePlot(energy_system=energy_system)

    # select subsets of data frame (full hub balances) and write to temp-csv
    csv_links = {}
    for b in buses.values():
        subset = esplot.slice_by(bus_label=b.label,
                                 type='to_bus').unstack([0, 1, 2])
        fd, temp_path = mkstemp(dir=folder, suffix='.csv')
        file = open(temp_path, 'w')
        file.write(subset.to_csv())
        file.close()
        os.close(fd)

        head, tail = os.path.split(temp_path)
        link = "/static/" + tail
        # storage csv-file links in dictionary for html result page
        csv_links[b.label] = link

    ####################### CALCULATIONS FOR OUTPUT ###########################
    # get electical hubs production

    el_buses = [
        b.label for b in buses.values() if b.energy_sector == 'electricity'
    ]
    components = [n for n in energy_system.nodes if not isinstance(n, Bus)]

    #plot_nodes = [c.label for c in components if c.type != 'transmission']
    renewables = [c for c in components if isinstance(c, Source)]
    wind = [c.label for c in renewables if c.fuel_type == 'wind']
    solar = [c.label for c in renewables if c.fuel_type == 'solar']

    wind_production = esplot.slice_by(bus_label=el_buses,
                                      obj_label=wind,
                                      type='to_bus').unstack(2).sum(axis=1)
    wind_production.index = wind_production.index.droplevel(1)
    wind_production = wind_production.unstack(0)
    #pdb.set_trace()
    if not wind_production.empty:
        wind_production.columns = ['wind']
    solar_production = esplot.slice_by(bus_label=el_buses,
                                       obj_label=solar,
                                       type='to_bus').unstack(2).sum(axis=1)
    solar_production.index = solar_production.index.droplevel(1)
    solar_production = solar_production.unstack(0)
    if not solar_production.empty:
        solar_production.columns = ['solar']

    # slice fuel types, unstack components and sum components by fuel type
    fossil_production = esplot.slice_by(bus_label=global_buses.keys(),
                                        type='from_bus').unstack(2).sum(axis=1)
    # drop level 'from_bus' that all rows have anyway
    fossil_production.index = fossil_production.index.droplevel(1)
    # turn index with fuel type to columns
    fossil_production = fossil_production.unstack(0)

    all_production = pd.concat(
        [fossil_production, wind_production, solar_production], axis=1)
    all_production = all_production.resample('1D', how='sum')

    fossil_emissions = fossil_production.copy()
    #pdb.set_trace()
    for col in fossil_production:
        fossil_emissions[col] = fossil_production[col] * emission_factors[col]
    # sum total emissions
    emission = fossil_emissions.sum(axis=1)
    emission = emission.resample('1D', how='sum')
    # helpers for generating python-html ouput
    help_fill = ['tozeroy'] + ['tonexty'] * (len(all_production.columns) - 1)
    fill_dict = dict(zip(all_production.columns, help_fill))

    colors = {
        'gas': '#9bc8c8',
        'coal': '#9b9499',
        'oil': '#2e1629',
        'lignite': '#c89b9b',
        'waste': '#8b862a',
        'biomass': '#187c66',
        'wind': '#2b99ff',
        'solar': '#ffc125'
    }
    p = Bar(all_production.sum() / 1e3,
            legend=False,
            title="Summend energy production",
            xlabel="Type",
            ylabel="Energy Production in GWh",
            width=400,
            height=300,
            palette=[colors[col] for col in all_production])
    output_file(os.path.join(folder, 'all_production.html'))

    #show(p)

    e = Bar(fossil_emissions.sum(),
            legend=False,
            title="Summend CO2-emissions of production",
            xlabel="Type",
            ylabel="Energy Production in tons",
            width=400,
            height=300,
            palette=[colors[col] for col in all_production])
    output_file(os.path.join(folder, 'emissions.html'))
    #show(e)

    plots = {'production': p, 'emissions': e}
    script, div = bokeh_components(plots)

    ########## RENDER PLOTS ################

    # Define our html template for out plots
    template = Template('''<!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>openmod.sh Scenario Results</title>
            {{ js_resources }}
            {{ css_resources }}
            <script src='https://cdn.plot.ly/plotly-latest.min.js'></script>
        </head>
        <body>
        <table>
            <tr>
                <td>
                    <h3> Total CO2 - Emission </h3>
                    {{ plot_div.emissions }}
                </td>
                <td>
                </td>
                <td>
                    <h3> Total energy production </h3>
                    {{ plot_div.production }}
                </td>
            </tr>
       </table>

        {{ plot_script }}

      <h3> Daily production and emissions </h3>
        {{ timeplot }}
      <h3> Download your results </h3>
        {{ download }}
        </body>
    </html>
    ''')

    timeplot = (
        "<div id='myDiv' style='width: 800px; height: 500px;'></div>" +
        "<script>" + "var traces = [" + ", ".join([
            "{{x: {0}, y: {1}, fill: '{fillarg}', name: '{name}'}}".format(
                list(range(len(all_production.index.values))),
                list(all_production[col].values),
                name=col,
                fillarg=fill_dict[col]) for col in all_production
        ]) + "];" + "function stackedArea(traces) {" +
        "for(var i=1; i<traces.length; i++) {" +
        "for(var j=0; j<(Math.min(traces[i]['y'].length, traces[i-1]['y'].length)); j++) {"
        + "traces[i]['y'][j] += traces[i-1]['y'][j];}}" + "return traces;}" +
        "var layout = {title: 'Total electricity production on all hubs'," +
        "xaxis: {title: 'Day of the year'}," +
        "yaxis : {title: 'Energy in MWh'}," +
        "yaxis2: {title: 'CO2-emissions in tons', " +
        "range: [0, {0}],".format(emission.max() * 1.1) +
        #"titlefont: {color: 'rgb(148, 103, 189)'}, " +
        #"tickfont: {color: 'rgb(148, 103, 189)'}," +
        "overlaying: 'y', side: 'right'}," + "legend: {x: 0, y: 1,}};" +
        #"var data = " + "["+",".join(["{0}".format(col) for col in subset]) + "];"
        "var emission = {{x: {0}, y: {1}, type: 'scatter', yaxis: 'y2', name: 'CO2-Emissions'}};"
        .format(list(range(len(emission.index.values))), list(emission.values))
        + "data = stackedArea(traces);" + "data.push(emission);" +
        "Plotly.newPlot('myDiv', data, layout);" + "</script>")

    download = (
        "<br />You can download your results below:<br />  Hub: " +
        "<br /> Hub: ".join(
            ["<a href='{1}'>{0}</a>".format(*x) for x in csv_links.items()]))
    resources = INLINE

    js_resources = resources.render_js()
    css_resources = resources.render_css()

    html = template.render(js_resources=js_resources,
                           css_resources=css_resources,
                           plot_script=script,
                           plot_div=div,
                           download=download,
                           timeplot=timeplot)

    #filename = 'embed_multiple_responsive.html'

    #with open(filename, 'w') as f:
    #    f.write(html)
    #pdb.set_trace()
    response = (html)

    return response
Esempio n. 8
0
def simulate(energysystem, filename=None, solver='cbc', tee_switch=True,
             keep=True):
    """
    """
    if filename is None:
        filename = os.path.join(os.path.dirname(__file__), 'input_data.csv')
    logging.info("Creating objects")
    data = pd.read_csv(filename, sep=",")
    # resource buses
    bcoal = Bus(label="coal", balanced=False)
    bgas = Bus(label="gas", balanced=False)
    boil = Bus(label="oil", balanced=False)
    blig = Bus(label="lignite", balanced=False)

    # electricity and heat
    b_el = Bus(label="b_el")
    b_th = Bus(label="b_th")

    # adding an excess variable can help to avoid infeasible problems
    Sink(label="excess", inputs={b_el: Flow()})

    # adding an excess variable can help to avoid infeasible problems
    # Source(label="shortage", outputs={b_el: Flow(variable_costs=200)})

    # Sources
    Source(label="wind",
           outputs={b_el: Flow(actual_value=data['wind'],
                               nominal_value=66.3,
                               fixed=True)})

    Source(label="pv",
           outputs={b_el: Flow(actual_value=data['pv'],
                               nominal_value=65.3,
                               fixed=True)})

    # Demands (electricity/heat)
    Sink(label="demand_el",
         inputs={b_el: Flow(nominal_value=85,
                            actual_value=data['demand_el'],
                            fixed=True)})

    Sink(label="demand_th",
         inputs={b_th: Flow(nominal_value=40,
                            actual_value=data['demand_th'],
                            fixed=True)})

    # Power plants
    LinearTransformer(label='pp_coal',
                      inputs={bcoal: Flow()},
                      outputs={b_el: Flow(nominal_value=20.2,
                                          variable_costs=25)},
                      conversion_factors={b_el: 0.39})

    LinearTransformer(label='pp_lig',
                      inputs={blig: Flow()},
                      outputs={b_el: Flow(nominal_value=11.8,
                                          variable_costs=19)},
                      conversion_factors={b_el: 0.41})

    LinearTransformer(label='pp_gas',
                      inputs={bgas: Flow()},
                      outputs={b_el: Flow(nominal_value=41,
                                          variable_costs=40)},
                      conversion_factors={b_el: 0.50})

    LinearTransformer(label='pp_oil',
                      inputs={boil: Flow()},
                      outputs={b_el: Flow(nominal_value=5,
                                          variable_costs=50)},
                      conversion_factors={b_el: 0.28})

    # CHP
    LinearTransformer(label='pp_chp',
                      inputs={bgas: Flow()},
                      outputs={b_el: Flow(nominal_value=30,
                                          variable_costs=42),
                               b_th: Flow(nominal_value=40)},
                      conversion_factors={b_el: 0.3, b_th: 0.4})

    # Heatpump with a coefficient of performance (COP) of 3
    b_heat_source = Bus(label="b_heat_source")

    Source(label="heat_source", outputs={b_heat_source: Flow()})

    cop = 3
    LinearN1Transformer(label='heat_pump',
                        inputs={b_el: Flow(), b_heat_source: Flow()},
                        outputs={b_th: Flow(nominal_value=10)},
                        conversion_factors={b_el: cop,
                                            b_heat_source: cop/(cop-1)})

# ################################ optimization ###############################
    # create Optimization model based on energy_system
    logging.info("Create optimization problem")
    om = OperationalModel(es=energysystem)

    # solve with specific optimization options (passed to pyomo)
    logging.info("Solve optimization problem")
    om.solve(solver=solver,
             solve_kwargs={'tee': tee_switch, 'keepfiles': keep})

    # write back results from optimization object to energysystem
    om.results()

    return om