Search code examples
pyomo

Dependent component can't be instantiated in AbstractModel with Pyomo >= 5.7.3


The following code does work on Pyomo 5.7.0, but does not work on Pyomo 5.7.3 and above anymore. The Error is "ValueError: Error retrieving immutable Param value (battery.n_time_steps)" (full traceback at the end) when trying to build the time_steps set.

import pyomo.environ as pyo


def test_param_pyomo5_7():
    def create_battery():
        block = pyo.Block()
        block.n_time_steps = pyo.Param(within=pyo.NonNegativeIntegers, doc='Number of time steps')
        block.time_steps = pyo.RangeSet(1, block.n_time_steps, doc='Time steps')
        return block

    def create_model() -> pyo.AbstractModel:
        model = pyo.AbstractModel()
        model.battery = create_battery()

        return model

    data = {
        None: {
            'battery': {
                'n_time_steps': {None: 24},
            },
        }
    }
    
    model = create_model()
    instance = model.create_instance(data=data)

The full traceback is:

..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:697: in create_instance
    instance.load( data,
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:734: in load
    self._load_model_data(dp,
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:787: in _load_model_data
    self._initialize_component(modeldata, namespaces, component_name, profile_memory)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:825: in _initialize_component
    declaration.construct(data)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\block.py:2207: in construct
    obj.construct(data.get(name, None))
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\disable_methods.py:116: in construct
    return base.construct(self, data)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\set.py:2792: in construct
    args = tuple(value(arg) for arg in args)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\set.py:2792: in <genexpr>
    args = tuple(value(arg) for arg in args)
pyomo\core\expr\numvalue.pyx:153: in pyomo.core.expr.numvalue.value
    ???
pyomo\core\expr\numvalue.pyx:138: in pyomo.core.expr.numvalue.value
    ???
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\param.py:853: in __call__
    return self[None]
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\indexed_component.py:577: in __getitem__
    return self._getitem_when_not_present(index)

Solution

  • There was an inconsistency in how blocks were initialized from dictionary data in Pyomo<5.7.2, which was fixed in 5.7.2 (PR #1703). The correct data dictionary requires "indices" for all components (even scalar components). Your data dictionary is missing the None key (implicit index) for the data associated with the scalar Block battery. The following data dictionary will work in recent versions of Pyomo:

    data = {
        None: {
            'battery': {
                None: {
                    'n_time_steps': {None: 24},
                },
            },
        }
    }