oemof / oemof-solph

A model generator for energy system modelling and optimisation (LP/MILP).
https://oemof.org
MIT License
301 stars 126 forks source link

Reconfiguration of energy system objects #196

Open SpioradObrach opened 8 years ago

SpioradObrach commented 8 years ago

I would like to reconfigure an existing object, e.g. to change its label or lifetime attribute. Is this possible at the moment? To initialize a component with some parameters but change them in the process?

I would like to to something like:

source.set(label="pv_2", lifetime=20)

Which would change the label and the lifetime of this component.

Similarly, I would like to change other parameters, like the inputs or outputs of a component to reconfigure and output of a source to another bus for example.

SpioradObrach commented 8 years ago

I found a way to modify an objects Flow object in order to reconfigure it. This seems to work, although its a bit tricky to access. I would like to be also able to reconfigure energy systems. I tried to modifiy the .entities list and .groups dict in order to do so, however this leads to errors when calling the solver:

new_entities = [bel, source_1, demand_1]

key_list = []
for key, value in es.groups.items():
    key_list.append(key)

for key in key_list:
    del es.groups[key]

es.entities = []

for entity in new_entities:
    es.add(entity)

It seems like modifying these two object containers this way is not enough, objects are still stored within the energy system. What can I do to really modify an energy system's array of components?

uvchik commented 8 years ago

I do not fully understand where you are heading for. You can create an EnergySystem object and solve it and then you can create another one and solve it, too. Or you can create two EnergySystem objects and then solve them one after the other.

But if a node (old: entity) is once part of an EnergySystem it is difficult to remove it but maybe @gnn could correct me because he wrote that part.

One way to avoid the automatic addition to the EnergySystem is to define the EnergySystem at the end of the definition. You can define variables and add them to a list or directly append you objects to the list. The following code shows both ways. Afterwards you pass the list to you EnergySystem

bus1 = solph.Bus(label="bus1")
bus2 = solph.Bus(label="bus2")

nodes = ([bgas, bel])  # Create a list with objects

# append an object directly to a list
nodes.append(solph.Sink(label=sink1', .....))
nodes.append(solph.Source(label=source1', .....)
nodes.append(solph.Source(label=source2', .....)
nodes.append(solph.LinearTransformer(label=transformer1', .....)

energysystem1 = solph.EnergySystem(entities=nodes, groupings=solph.GROUPINGS,
                                   time_idx=date_time_index)
om = solph.OperationalModel(energysystem1)
om.solve(solver=solvername, solve_kwargs={'tee': True})

# remove an object from list
nodes.remove(bus1)

# energysystem without bus1
energysystem2 = solph.EnergySystem(entities=nodes, groupings=solph.GROUPINGS,
                                   time_idx=date_time_index)
om = solph.OperationalModel(energysystem2)
om.solve(solver=solvername, solve_kwargs={'tee': True})

This should work even though I haven't tested it. Anyhow I would use one application with one EnergySystem object and use a file, database etc. to control the elements of my EnergySystem and the parameters of the nodes. Then you can use loop over different scenarios, systems etc..

SpioradObrach commented 8 years ago

Thank you for your answer, I know there are several ways to achieve the same result. My objective is to make use of object oriented programming as much as possible and this is one of the core strengths of Oemof. Hence I would like to deal with an energy system as much as I would like to in reality, being able to attach or detach components flexibly. This would be nice e.g. in order to recycle and modify an energy system as many times as one would like, reuse it in bigger networks and so on. I know it is already possible with the given structure, its just more technical. Especially in bigger networks I like ease of use and therefore having an object that comes close to reality more closely in its behaviour, in order to facilitate the understanding and having flexibility as this is one additional strength.

For me its rather difficult to see whats going on behind the scenes of Oemof, and what would be necessary to gain that chunk of flexbility.

uvchik commented 8 years ago

For me its rather difficult to see whats going on behind the scenes of Oemof, and what would be necessary to gain that chunk of flexbility.

What is hard to understand "behind the scenes", code or organisation?

ckaldemeyer commented 8 years ago

What can I do to really modify an energy system's array of components?

I am not familiar with the new grouping function but think that @gnn can give you some advice here. You also have the possibility to look at the source code and extend it to your needs. This also holds for the attribute access of the base classes you were asking for in you first post.

For me its rather difficult to see whats going on behind the scenes of Oemof, and what would be necessary to gain that chunk of flexbility. Except for the code (which is public and documented) we are trying to be as transparent as possible inthe long run by improving the documentation and providing more explaining examples for different purposes.

As most people are working on different projects (having deadlines), there's sometimes more and sometimes less progress on different levels. In recent time, a lot of effort was put on the refactoring of the new concept and code by @uvchik , @simnh and @gnn . The documentation and the examples will follow step by step within the next weeks and months.

If you have concrete suggestions for improvements on different levels (code, documentation, concept), feel free to post it here. Feedback is always welcome!

SpioradObrach commented 8 years ago

As I am no programmer, I have difficulties to understand how the behaviour of Oemof regarding attachment of components to an energy system could be altered.

ukrien notifications@github.com writes:

For me its rather difficult to see whats going on behind the scenes of Oemof, and what would be necessary to gain that chunk of flexbility.

What is hard to understand "behind the scenes", code or organisation?

SpioradObrach commented 8 years ago

Thank you, more examples and a documentation that covers different usage scenarios and how they could be achieved would be nice! Especially as several things changed comparing the old and new version.

I will contact @gnn on the grouping function on how components could be detached off an energy system.

Cord Kaldemeyer notifications@github.com writes:

What can I do to really modify an energy system's array of components?

I am not familiar with the new grouping function but think that @gnn can give you some advice here. You also have the possibility to look at the source code and extend it to your needs. This also holds for the attribute access of the base classes you were asking for in you first post.

For me its rather difficult to see whats going on behind the scenes of Oemof, and what would be necessary to gain that chunk of flexbility. Except for the code (which is public and documented) we are trying to be as transparent as possible inthe long run by improving the documentation and providing more explaining examples for different purposes.

As most people are working on different projects (having deadlines), there's sometimes more and sometimes less progress on different levels. In recent time, a lot of effort was put on the refactoring of the new concept and code by @uvchik , @simnh and @gnn . The documentation and the examples will follow step by step within the next weeks and months.

If you have concrete suggestions for improvements on different levels (code, documentation, concept), feel free to post it here. Feedback is always welcome!

gnn commented 8 years ago

Hi Mr. Pilz,

concerning the code you posted above, where you delete everything from es.groups and empty es.entities0, should actually work. Off the top of my head, the only reason I could think of why it doesn't work would be that one of the new_entities has a connection to some X not contained in new_entities. The fact that X is now no longer part of es might then confuse the solver.

Could you post the code that threw the error? (Bonus points if you reduce it to a minimal example.) It's always good to have such examples to see whether that error is expected behaviour or a bug.

Concerning the removal of nodes from the energy system, you do have a valid point in that it seems natural to do this, but it presents at least two problems:

  1. As you have noticed, the energy system also tracks groups. These groups are very general and can actually be nearly anything. Now, if a node is deleted, it's not really straightforward to figure out what to delete from which group. This might actually be a good example for the fact that groups in their current state are too general.
  2. The second problem is the one I have stated in the first paragraph. If node get's deleted from an energy system, what should happen to it's flows? Should all of them be deleted or only those that are connected to nodes still contained in the energy system? Or should none of them be deleted and we deal with it in the solver? What happens if you have two energy systems that share some nodes and you want to delete one of them only from one energy system?1?

While these problems can be solved, the solutions can have consequences which we should talk about in order to make the right decisions. So if anyone has any answers to the questions above, shoot.

In the meantime my advice @Jazzpilz would be to keep track of entities manually and just create a new one with the ones you want to keep instead of deleting the others from the old energy system:

es = EnergySystem()

# Create some nodes.

new_entities = [entities, to, keep]

es = EnergySystem(entities=new_entities)

If you know how to discriminate the candidates to keep from the ones to remove in advance, you might even be able to use the energy system's grouping feature to help with keeping track of entities.

0: By the way, entities is a legacy attribute that is planned to be renamed to nodes in 0.1 because Entity will be renamed to Node too. The reason being that Nodes are just that: nodes in an energy system graph. The rename is not fully done though yet. Thanks for posting an example pointing me at this. 1: Just a heads up: having multiple energy systems has other (as of yet unsolved) caveats too. But it's also an intuitive feature to have for some, so I wanted to mention how it interacts with other intuitive features.

SpioradObrach commented 8 years ago

Hey gnn,

sounds nice that actually it should work and for a simple example like below it does indeed:

import pandas as pd
import oemof.solph as solph

date_time_index = pd.date_range('1/1/2012', periods=24,
                                freq='H')

es = solph.EnergySystem(
    groupings=solph.GROUPINGS, time_idx=date_time_index)

bel = solph.Bus(label="electricity")
sink = solph.Sink(label='excess_bel', inputs={bel: solph.Flow()})

print(es.groups)
print(len(es.groups))
print(len(es.entities))

es.entities = [bel]

print(len(es.groups))    # groups are not changed
print(len(es.entities))

key_list = []
for key, value in es.groups.items():
    key_list.append(key)

for key in key_list:
    del es.groups[key]

print(es.groups)

es.add(bel)

print(es.groups)

om = solph.OperationalModel(es)
om.solve(solve_kwargs={'tee': True})

However when for example trying the same for the storage_invest example, the solver doesn't find a solution for me. Below I just deleted all components from the energysystem and added them again in order to test the behaviour:

    logging.info('Solve the optimization problem')

    energysystem.entities = [bgas, bel, sink, rgas, wind, pv, demand, pp_gas, storage]

    key_list = []
    for key, value in energysystem.groups.items():
        key_list.append(key)

    for key in key_list:
        del energysystem.groups[key]

    for entitiy in energysystem.entities:
        energysystem.add(entitiy)

    om.solve(solver=solvername, solve_kwargs={'tee': True})

Regarding your points:

  1. There are two general types of nodes: busses and others. Busses can not be easiliy deleted as there are possibly Flows specified that refer to them. Other type of nodes such as sources could be safely deleted when the Flow that is linked to them is deleted inline with them. I actually never tried, but would you even specify a Flow object pointing to another component (and no bus)?

A nice feature would be to be able to 'pop' a node from the energy system. Or to create a 'remove' method that can take a single node or a list of nodes to remove.

uvchik commented 8 years ago

@gnn What about this issue?

uvchik commented 6 years ago

This is related to #139.