Skip to main content
added 1730 characters in body
Source Link
Ursxx
  • 11
  • 2

ThanksEdit:

As pointed out by jsiirola, nesting in combination with abstract models can get very cumbersome. So I tried to model it using concrete models and nest the blocks "by hand".

import pyomo.environ as pyo

def func_model():
    model = pyo.AbstractModel()
    model.idx_lb = pyo.Param()
    model.idx_ub = pyo.Param()
    model.idx = pyo.RangeSet(model.idx_lb, model.idx_ub)
    #model.subblock = pyo.Block(model.idx, rule = subblock)
    return model

def subblock():
    submodel = pyo.AbstractModel()
    submodel.jdx_ub = pyo.Param()
    submodel.jdx = pyo.RangeSet(submodel.jdx_ub)
    #submodel.subsubblock = pyo.Block(submodel.jdx, rule = subsubblock)
    return submodel

def subsubblock():
    subsubmodel = pyo.AbstractModel()
    subsubmodel.kdx_ub = pyo.Param()
    subsubmodel.kdx = pyo.RangeSet(subsubmodel.kdx_ub)
    return subsubmodel

Then, creating the subsubmodel

ssb_data = {None: {"kdx_ub" : {None: 3}}}
ss_model = subsubblock()
ss_instance = ss_model.create_instance(ssb_data)

and adding this into the submodel

import copy
sb_data = {None: {"jdx_ub": {None: 2}}}
s_model = subblock()
s_instance = s_model.create_instance(sb_data)

def copy_func(m,j):
    return copy.deepcopy(ss_instance)

s_instance.subsubblock = pyo.Block(s_instance.jdx, rule = copy_func)

I would also do the same for helpnesting the subblock into the model.

I think this is much better than the cumbersome abstract model instantiation I would normally do. However, in my real example I have a nested model that is interconnected. E.g., my :(outermost) model puts constraints on the subblock's parameters. Is there any way to handle this with the upper approach?

Thanks for help :)

Edit:

As pointed out by jsiirola, nesting in combination with abstract models can get very cumbersome. So I tried to model it using concrete models and nest the blocks "by hand".

import pyomo.environ as pyo

def func_model():
    model = pyo.AbstractModel()
    model.idx_lb = pyo.Param()
    model.idx_ub = pyo.Param()
    model.idx = pyo.RangeSet(model.idx_lb, model.idx_ub)
    #model.subblock = pyo.Block(model.idx, rule = subblock)
    return model

def subblock():
    submodel = pyo.AbstractModel()
    submodel.jdx_ub = pyo.Param()
    submodel.jdx = pyo.RangeSet(submodel.jdx_ub)
    #submodel.subsubblock = pyo.Block(submodel.jdx, rule = subsubblock)
    return submodel

def subsubblock():
    subsubmodel = pyo.AbstractModel()
    subsubmodel.kdx_ub = pyo.Param()
    subsubmodel.kdx = pyo.RangeSet(subsubmodel.kdx_ub)
    return subsubmodel

Then, creating the subsubmodel

ssb_data = {None: {"kdx_ub" : {None: 3}}}
ss_model = subsubblock()
ss_instance = ss_model.create_instance(ssb_data)

and adding this into the submodel

import copy
sb_data = {None: {"jdx_ub": {None: 2}}}
s_model = subblock()
s_instance = s_model.create_instance(sb_data)

def copy_func(m,j):
    return copy.deepcopy(ss_instance)

s_instance.subsubblock = pyo.Block(s_instance.jdx, rule = copy_func)

I would also do the same for nesting the subblock into the model.

I think this is much better than the cumbersome abstract model instantiation I would normally do. However, in my real example I have a nested model that is interconnected. E.g., my (outermost) model puts constraints on the subblock's parameters. Is there any way to handle this with the upper approach?

Became Hot Network Question
Source Link
Ursxx
  • 11
  • 2

variable use of nested blocks in pyomo

I'm using pyomo to model a system consisting of subsystems which themselves consist of subsystems. Therefore, I use nested Blocks. Every block is described in a separate file. I want to be able to switch which models I use as subsystems. I'm wondering whether it's possible to give the outermost model the inner models as arguments. While this is straight forward for one level of hierarchy (a block in the outermost model), I can't seem to find a way to make two levels of hierarchy work (pass the innermost model to the 1st level). This would be very handy as I could change which inner models I load without changing the import model from file in the model file's headers all the time.

Here is an example code that shows my approach. For what I want to do I would need to be able to pass non-model related arguments to the pyo.Block function, which doesn't seem to work.

## model file
import pyomo.environ as pyo

def func_model(subblock,subsubblock):
    model = pyo.AbstractModel()
    model.idx = pyo.RangeSet()
    model.subblock = pyo.Block(model.idx, **subsubblock**, rule = subblock)
    return model

### script

def subblock(submodel,idx, **subsubblock**):
    submodel.jdx = pyo.RangeSet()
    submodel.subsubblock = pyo.Block(submodel.jdx, rule = subsubblock)
    return submodel

def subsubblock(subsubmodel):
    subsubmodel.kdx = pyo.RangeSet()
    return subsubmodel

Now I pass the data from a dict

data = {
    None: {
        "idx" : {None: [1,2]},
        "subblock": {
            "jdx": {None: [1]},
            "subsubblock": {
                "kdx": {None: [1,2,3]}
            }
        }
    }
}

and create the instance

model = func_model(subblock, subsubblock)

instance = model.create_instance(data)

Now checking the model.pprint() results in

2 Set Declarations
    subblock_index : Size=1, Index=None, Ordered=True
        Key  : Dimen : Domain               : Size : Members
        None :     2 : idx*subblock_index_1 :    0 :      {}
    subblock_index_1 : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    1 : {None,}

2 RangeSet Declarations
    idx : Dimen=1, Size=0, Bounds=(None, None)
        Key  : Finite : Members
        None :   True :      []
    kdx : Dimen=1, Size=0, Bounds=(None, None)
        Key  : Finite : Members
        None :   True :      []

1 Block Declarations
    subblock : Size=0, Index=subblock_index, Active=True

5 Declarations: idx subblock_index_1 subblock_index subblock kdx

So the nesting didn't work.

Thanks for help :)