Exemplo n.º 1
0
def get_implicit_index_of_set(comp, wrt):
    """For some data object contained (at some level of the hierarchy) in a
    block indexed by wrt, returns the index corresponding to wrt in that
    block.

    Args:
        comp : Component data object whose (parent blocks') indices will be
               searched
        wrt : Set whose index will be searched for

    Returns:
        Value of the specified set 
    """
    val = None
    found = False
    if is_explicitly_indexed_by(comp.parent_component(), wrt):
        val = get_index_of_set(comp, wrt)
        found = True

    parent_block = comp.parent_block()
    while parent_block is not None:
        parent_component = parent_block.parent_component()
        if is_explicitly_indexed_by(parent_component, wrt):
            if found:
                raise ValueError(
                    "Cannot get the index of set %s because it appears "
                    "multiple times in the hierarchy" % (wrt.name))
            val = get_index_of_set(parent_block, wrt)
            found = True
        parent_block = parent_block.parent_block()

    # Will return val even if it is None.
    # User can decide what to do in this case.
    return val
Exemplo n.º 2
0
def fix_vars_unindexed_by(b, time):
    """
    Searches block b for variables not indexed by time
    and fixes them. 

    Args:
        b : Block to search
        time : Set with respect to which to find unindexed variables

    Returns:
        List of variables fixed
    """
    varlist = []

    visited = set()
    for var in b.component_objects(Var):
        if id(var) in visited:
            continue
        visited.add(id(var))

        if (not is_explicitly_indexed_by(var, time)
                and not is_in_block_indexed_by(var, time)):
            for index in var:
                vardata = var[index]
                if (not vardata.fixed and vardata.value is not None):
                    # Can't fix a variable with a value of None, but this
                    # should be called after a solve, so any variable with
                    # value of None is stale and won't be sent to solver,
                    # so it doesn't need to be fixed to maintain correct
                    # degrees of freedom
                    vardata.fix()
                    varlist.append(vardata)

    return varlist
Exemplo n.º 3
0
def deactivate_constraints_unindexed_by(b, time):
    """
    Searches block b for and constraints not indexed by time
    and deactivates them. 

    Args:
        b : Block to search
        time : Set with respect to which to find unindexed constraints

    Returns:
        List of constraints deactivated
    """
    conlist = []

    visited = set()
    for comp in b.component_objects(Constraint, active=True):
        if id(comp) in visited:
            continue
        visited.add(id(comp))

        if (not is_explicitly_indexed_by(comp, time)
                and not is_in_block_indexed_by(comp, time)):
            for index in comp:
                compdata = comp[index]
                if compdata.active:
                    compdata.deactivate()
                    conlist.append(compdata)

    return conlist
Exemplo n.º 4
0
def deactivate_model_at(b, cset, pts, outlvl=idaeslog.NOTSET):
    """
    Finds any block or constraint in block b, indexed explicitly (and not 
    implicitly) by cset, and deactivates it at points specified. 
    Implicitly indexed components are excluded because one of their parent 
    blocks will be deactivated, so deactivating them too would be redundant.

    Args:
        b : Block to search
        cset : ContinuousSet of interest
        pts : Value or list of values, in ContinuousSet, to deactivate at

    Returns:
        A dictionary mapping points in pts to lists of
        component data that have been deactivated there
    """
    if not type(pts) is list:
        pts = [pts]
    for pt in pts:
        if not pt in cset:
            msg = str(pt) + ' is not in ContinuousSet ' + cset.name
            raise ValueError(msg)
    deactivated = {pt: [] for pt in pts}

    visited = set()
    for comp in b.component_objects([Block, Constraint], active=True):
        # Record components that have been visited in case component_objects
        # contains duplicates (due to references)
        if id(comp) in visited:
            continue
        visited.add(id(comp))

        if (is_explicitly_indexed_by(comp, cset)
                and not is_in_block_indexed_by(comp, cset)):
            info = get_index_set_except(comp, cset)
            non_cset_set = info['set_except']
            index_getter = info['index_getter']

            for non_cset_index in non_cset_set:
                for pt in pts:
                    index = index_getter(non_cset_index, pt)
                    try:
                        comp[index].deactivate()
                        deactivated[pt].append(comp[index])
                    except KeyError:
                        # except KeyError to allow Constraint/Block.Skip
                        msg = (comp.name + ' has no index ' + str(index))
                        init_log = idaeslog.getInitLogger(__name__, outlvl)
                        init_log.warning(msg)
                        continue

    return deactivated
Exemplo n.º 5
0
def get_index_of_set(comp, wrt):
    """For some data object of an indexed component, gets the value of the
    index corresponding to some 1-dimensional pyomo set.

    Args: 
        comp : Component data object whose index will be searched
        wrt : Set whose index will be searched for

    Returns:
        Value of the specified set in the component data object
    """
    parent = comp.parent_component()
    if not is_explicitly_indexed_by(parent, wrt):
        raise ValueError("Component %s is not explicitly indexed by set %s." %
                         (comp.name, wrt.name))

    index = comp.index()
    if not type(index) is tuple:
        index = (index, )
    loc = get_location_of_coordinate_set(parent.index_set(), wrt)
    return index[loc]
Exemplo n.º 6
0
def get_inconsistent_initial_conditions(model,
                                        time,
                                        tol=1e-8,
                                        t0=None,
                                        allow_skip=True,
                                        suppress_warnings=False):
    """Finds constraints of the model that are implicitly or explicitly
    indexed by time and checks if they are consistent to within a tolerance
    at the initial value of time.

    Args:
        model: Model whose constraints to check
        time: Set whose initial condition will be checked
        tol: Maximum constraint violation
        t0: Point in time at which to check constraints

    Returns:
        List of constraint data objects that were found to be inconsistent.
    """
    if t0 is None:
        t0 = time.first()

    inconsistent = ComponentSet()
    for con in model.component_objects(Constraint, active=True):
        if not is_explicitly_indexed_by(con, time):
            continue
        if is_in_block_indexed_by(con, time):
            continue
        info = get_index_set_except(con, time)
        non_time_set = info['set_except']
        index_getter = info['index_getter']
        for non_time_index in non_time_set:
            index = index_getter(non_time_index, t0)
            try:
                condata = con[index]
            except KeyError:
                # To allow Constraint.Skip
                if not suppress_warnings:
                    print(index_warning(con.name, index))
                if not allow_skip:
                    raise
                continue
            if (value(condata.body) - value(condata.upper) > tol
                    or value(condata.lower) - value(condata.body) > tol):
                inconsistent.add(condata)

    for blk in model.component_objects(Block, active=True):
        # What if there are time-indexed blocks at multiple levels
        # of a hierarchy?
        # My preferred convention is to only check the first (highest-
        # level) time index, but distinguishing between different-level
        # time indices is an expensive operation.
        if not is_explicitly_indexed_by(blk, time):
            continue
        if is_in_block_indexed_by(blk, time):
            continue
        info = get_index_set_except(blk, time)
        non_time_set = info['set_except']
        index_getter = info['index_getter']
        for non_time_index in non_time_set:
            index = index_getter(non_time_index, t0)
            blkdata = blk[index]
            for condata in blkdata.component_data_objects(Constraint,
                                                          active=True):
                if (value(condata.body) - value(condata.upper) > tol
                        or value(condata.lower) - value(condata.body) > tol):
                    if condata in inconsistent:
                        raise ValueError(
                            '%s has already been visited. The only way this '
                            'should happen is if the model has nested time-'
                            'indexed blocks, which is not supported.')
                    inconsistent.add(condata)

    return list(inconsistent)
Exemplo n.º 7
0
def copy_values_at_time(fs_tgt,
                        fs_src,
                        t_target,
                        t_source,
                        copy_fixed=True,
                        outlvl=idaeslog.NOTSET):
    """
    Function to set the values of all (explicitly or implicitly) time-indexed 
    variables in a flowsheet to similar values (with the same name) but at 
    different points in time and (potentially) in different flowsheets.

    Args:
        fs_tgt : Target flowsheet, whose variables' values will get set
        fs_src : Source flowsheet, whose variables' values will be used to 
                 set those of the target flowsheet. Could be the target
                 flowsheet
        t_target : Target time point
        t_source : Source time point
        copy_fixed : Bool of whether or not to copy over fixed variables in 
                     target model 
        outlvl : IDAES logger output level

    Returns:
        None
    """
    time_target = fs_tgt.time
    var_visited = set()
    for var_target in fs_tgt.component_objects(Var):
        if id(var_target) in var_visited:
            continue
        var_visited.add(id(var_target))

        if not is_explicitly_indexed_by(var_target, time_target):
            continue
        n = var_target.index_set().dimen

        local_parent = fs_src

        varname = var_target.getname(fully_qualified=True, relative_to=fs_tgt)
        # Calling find_component here makes the assumption that varname does not
        # contain decimal indices.
        var_source = fs_src.find_component(varname)
        if var_source is None:
            # Log a warning
            msg = ('Warning copying values: ' + varname +
                   ' does not exist in source block ' + fs_src.name)
            init_log = idaeslog.getInitLogger(__name__, outlvl)
            init_log.warning(msg)
            continue

        if n == 1:
            if not copy_fixed and var_target[t_target].fixed:
                continue
            var_target[t_target].set_value(var_source[t_source].value)
        elif n >= 2:
            index_info = get_index_set_except(var_target, time_target)
            non_time_index_set = index_info['set_except']
            index_getter = index_info['index_getter']
            for non_time_index in non_time_index_set:
                source_index = index_getter(non_time_index, t_source)
                target_index = index_getter(non_time_index, t_target)
                if not copy_fixed and var_target[target_index].fixed:
                    continue
                var_target[target_index].set_value(
                    var_source[source_index].value)

    blk_visited = set()
    for blk_target in fs_tgt.component_objects(Block):
        if id(blk_target) in blk_visited:
            continue
        blk_visited.add(id(blk_target))

        if not is_explicitly_indexed_by(blk_target, time_target):
            continue
        n = blk_target.index_set().dimen

        blkname = blk_target.getname(fully_qualified=True, relative_to=fs_tgt)
        blk_source = fs_src.find_component(blkname)
        if blk_source is None:
            # log warning
            msg = ('Warning copying values: ' + blkname +
                   ' does not exist in source' + fs_src.name)
            init_log = idaeslog.getInitLogger(__name__, outlvl)
            init_log.warning(msg)
            continue

        if n == 1:
            target_index = t_target
            source_index = t_source

            var_visited = set()
            for var_target in blk_target[target_index].component_data_objects(
                    Var):
                if id(var_target) in var_visited:
                    continue
                var_visited.add(id(var_target))

                if not copy_fixed and var_target.fixed:
                    continue

                # Here, find_component will not work from BlockData object
                local_parent = blk_source[source_index]
                for r in path_from_block(var_target, blk_target[target_index]):
                    local_parent = getattr(local_parent, r[0])[r[1]]
                var_source = getattr(local_parent,
                                     var_target.parent_component().local_name)[
                                         var_target.index()]
                var_target.set_value(var_source.value)

        elif n >= 2:
            index_info = get_index_set_except(blk_target, time_target)
            non_time_index_set = index_info['set_except']
            index_getter = index_info['index_getter']
            for non_time_index in non_time_index_set:
                source_index = index_getter(non_time_index, t_source)
                target_index = index_getter(non_time_index, t_target)

                var_visited = set()
                for var_target in blk_target[
                        target_index].component_data_objects(Var):
                    if id(var_target) in var_visited:
                        continue
                    var_visited.add(id(var_target))

                    if not copy_fixed and var_target.fixed:
                        continue

                    local_parent = blk_source[source_index]
                    for r in path_from_block(var_target,
                                             blk_target[target_index]):
                        local_parent = getattr(local_parent, r[0])[r[1]]
                    var_source = getattr(
                        local_parent,
                        var_target.parent_component().local_name)[
                            var_target.index()]
                    var_target.set_value(var_source.value)
Exemplo n.º 8
0
def copy_non_time_indexed_values(
    fs_tgt,
    fs_src,
    copy_fixed=True,
    outlvl=idaeslog.NOTSET,
):
    """
    Function to set the values of all variables that are not (implicitly
    or explicitly) indexed by time to their values in a different flowsheet.

    Args:
        fs_tgt : Flowsheet into which values will be copied.
        fs_src : Flowsheet from which values will be copied.
        copy_fixed : Bool marking whether or not to copy over fixed variables
                     in the target flowsheet.
        outlvl : Outlevel for the IDAES logger.

    Returns:
        None
    """
    time_tgt = fs_tgt.time

    var_visited = set()
    for var_tgt in fs_tgt.component_objects(Var, descend_into=False):
        if id(var_tgt) in var_visited:
            continue
        var_visited.add(id(var_tgt))

        if is_explicitly_indexed_by(var_tgt, time_tgt):
            continue
        var_src = fs_src.find_component(var_tgt.local_name)
        # ^ this find_component is fine because var_tgt is a Var not VarData
        # and its local_name is used. Assumes that there are no other decimal
        # indices in between fs_src and var_src

        if var_src is None:
            # Log a warning
            msg = ('Warning copying values: ' + var_src.name +
                   ' does not exist in source block ' + fs_src.name)
            init_log = idaeslog.getInitLogger(__name__, outlvl)
            init_log.warning(msg)
            continue

        for index in var_tgt:
            if not copy_fixed and var_tgt[index].fixed:
                continue
            var_tgt[index].set_value(var_src.value)

    blk_visited = set()
    for blk_tgt in fs_tgt.component_objects(Block):

        if id(blk_tgt) in blk_visited:
            continue
        blk_visited.add(id(blk_tgt))

        if (is_in_block_indexed_by(blk_tgt, time_tgt)
                or is_explicitly_indexed_by(blk_tgt, time_tgt)):
            continue
        # block is not even implicitly indexed by time
        for b_index in blk_tgt:

            var_visited = set()
            for var_tgt in blk_tgt[b_index].component_objects(
                    Var, descend_into=False):
                if id(var_tgt) in var_visited:
                    continue
                var_visited.add(id(var_tgt))

                if is_explicitly_indexed_by(var_tgt, time_tgt):
                    continue

                # can't used find_component(local_name) here because I might
                # have decimal indices
                try:
                    local_parent = fs_src
                    for r in path_from_block(var_tgt, fs_tgt):
                        local_parent = getattr(local_parent, r[0])[r[1]]
                except AttributeError:
                    # log warning
                    msg = ('Warning copying values: ' + r[0] +
                           ' does not exist in source' + local_parent.name)
                    init_log = idaeslog.getInitLogger(__name__, outlvl)
                    init_log.warning(msg)
                    continue
                except KeyError:
                    msg = ('Warning copying values: ' + str(r[1]) +
                           ' is not a valid index for' +
                           getattr(local_parent, r[0]).name)
                    init_log = idaeslog.getInitLogger(__name__, outlvl)
                    init_log.warning(msg)
                    continue

                var_src = getattr(local_parent, var_tgt.local_name)

                for index in var_tgt:
                    if not copy_fixed and var_tgt[index].fixed:
                        continue
                    var_tgt[index].set_value(var_src[index].value)
Exemplo n.º 9
0
def find_comp_in_block_at_time(tgt_block,
                               src_block,
                               src_comp,
                               time,
                               t0,
                               allow_miss=False):
    """This function finds a component in a source block, then uses the same
    local names and indices to try to find a corresponding component in a target
    block, with the exception of time index in the target component, which is
    replaced by a specified time point. This is used for validation of a
    component by its name in the case where blocks may differ by at most time
    indices, for example validating a steady-state model or a model with a
    different time discretization.

    Args:
        tgt_block : Target block that will be searched for component
        src_block : Source block in which the original component is located
        src_comp : Component whose name will be searched for in target block
        time : Set whose index will be replaced in the target component
        t0 : Index of the time set that will be used in the target
             component
        allow_miss : If True, will ignore attribute and key errors due to 
                     searching for non-existant components in the target model

    """
    # Could extend this to allow replacing indices of multiple sets
    # (useful for PDEs)

    if t0 not in time:
        raise KeyError('t0 must be in the time set')
    if time.model() is not tgt_block.model():
        raise ValueError(
            'time must belong to the same model as the target block')
    if src_block.model() is not src_comp.model():
        raise ValueError(
            'src_block and src_comp must be components of the same model')

    local_parent = tgt_block
    for r in path_from_block(src_comp, src_block, include_comp=False):
        # Don't include comp as I want to use this to find IndexedComponents,
        # for which [r[1]] will result in a KeyError.

        # If local_parent is indexed by time, need to replace time index
        # in r[1]

        try:
            local_parent = getattr(local_parent, r[0])
        except AttributeError:
            if allow_miss:
                return None
            else:
                raise AttributeError(
                    '%s has no attribute %s. Use allow_miss=True if this '
                    'is expected and acceptable.' % (local_parent.name, r[0]))

        index = r[1]

        # Can abstract the following into a function:
        # replace_time_index or something
        if is_explicitly_indexed_by(local_parent, time):
            index_set = local_parent.index_set()
            time_loc = get_location_of_coordinate_set(index_set, time)

            if type(index) is not tuple:
                index = (index, )
            index = list(index)

            # Replace time index with t0
            index[time_loc] = t0
            index = tuple(index)

        try:
            local_parent = local_parent[index]
        except KeyError:
            if allow_miss:
                return None
            else:
                raise KeyError(
                    '%s is not a valid index for %s, use allow_miss=True '
                    'if this is expected and acceptable.' %
                    (str(index), local_parent.name))

    # This logic should return the IndexedComponent or ComponentData,
    # whichever is appropriate
    try:
        tgt_comp = getattr(local_parent,
                           src_comp.parent_component().local_name)
    except AttributeError:
        if allow_miss:
            return None
        else:
            raise AttributeError(
                '%s has no attribute %s. Use allow_miss=True if this '
                'is expected and acceptable.' %
                (local_parent.name, src_comp.parent_component().local_name))
    # tgt_comp is now an indexed component or simple component

    if hasattr(src_comp, 'index'):
        # If comp has index, attempt to access it in tgt_comp
        index = src_comp.index()

        if is_explicitly_indexed_by(tgt_comp, time):
            index_set = tgt_comp.index_set()
            time_loc = get_location_of_coordinate_set(index_set, time)

            if type(index) is not tuple:
                index = (index, )
            index = list(index)

            # Replace time index with t0
            index[time_loc] = t0
            index = tuple(index)

        try:
            tgt_comp = tgt_comp[index]
        except KeyError:
            if allow_miss:
                return None
            else:
                raise KeyError(
                    '%s is not a valid index for %s, use allow_miss=True '
                    'if this is expected and acceptable.' %
                    (str(index), tgt_comp.name))

    return tgt_comp
Exemplo n.º 10
0
    def test_indexed_by(self):
        m = ConcreteModel()
        m.time = ContinuousSet(bounds=(0, 10))
        m.space = ContinuousSet(bounds=(0, 10))
        m.set = Set(initialize=['a', 'b', 'c'])
        m.set2 = Set(initialize=[('a', 1), ('b', 2)])
        m.v = Var()
        m.v1 = Var(m.time)
        m.v2 = Var(m.time, m.space)
        m.v3 = Var(m.set, m.space, m.time)
        m.v4 = Var(m.time, m.set2)
        m.v5 = Var(m.set2, m.time, m.space)

        @m.Block()
        def b(b):
            b.v = Var()
            b.v1 = Var(m.time)
            b.v2 = Var(m.time, m.space)
            b.v3 = Var(m.set, m.space, m.time)

        @m.Block(m.time)
        def b1(b):
            b.v = Var()
            b.v1 = Var(m.space)
            b.v2 = Var(m.space, m.set)

        @m.Block(m.time, m.space)
        def b2(b):
            b.v = Var()
            b.v1 = Var(m.set)

            @b.Block()
            def b(bl):
                bl.v = Var()
                bl.v1 = Var(m.set)
                bl.v2 = Var(m.time)

        @m.Block(m.set2, m.time)
        def b3(b):
            b.v = Var()
            b.v1 = Var(m.space)

            @b.Block(m.space)
            def b(bb):
                bb.v = Var(m.set)

        disc = TransformationFactory('dae.collocation')
        disc.apply_to(m, wrt=m.time, nfe=5, ncp=2, scheme='LAGRANGE-RADAU')
        disc.apply_to(m, wrt=m.space, nfe=5, ncp=2, scheme='LAGRANGE-RADAU')

        self.assertFalse(is_explicitly_indexed_by(m.v, m.time))
        self.assertTrue(is_explicitly_indexed_by(m.b.v2, m.space))
        self.assertTrue(is_explicitly_indexed_by(m.b.v3, m.time, m.space))

        self.assertFalse(is_in_block_indexed_by(m.v1, m.time))
        self.assertFalse(is_in_block_indexed_by(m.v2, m.set))
        self.assertTrue(is_in_block_indexed_by(m.b1[m.time[1]].v2, m.time))

        self.assertTrue(is_in_block_indexed_by(
            m.b2[m.time[1], m.space[1]].b.v1, m.time))
        self.assertTrue(is_in_block_indexed_by(
            m.b2[m.time[1], m.space[1]].b.v2, m.time))
        self.assertTrue(is_explicitly_indexed_by(
            m.b2[m.time[1], m.space[1]].b.v2, m.time))
        self.assertFalse(is_in_block_indexed_by(
            m.b2[m.time[1], m.space[1]].b.v1, m.set))

        self.assertFalse(is_in_block_indexed_by(
            m.b2[m.time[1], m.space[1]].b.v1, 
            m.space, stop_at=m.b2[m.time[1], m.space[1]]))

        # Explicit indexing with multi-dimensional set:
        self.assertTrue(is_explicitly_indexed_by(m.v4, m.time, m.set2))
        self.assertTrue(is_explicitly_indexed_by(m.v5, m.time, m.set2, m.space))

        # Implicit indexing with multi-dimensional set:
        self.assertTrue(is_in_block_indexed_by(
            m.b3['a', 1, m.time[1]].v, m.set2))
        self.assertTrue(is_in_block_indexed_by(
            m.b3['a', 1, m.time[1]].v, m.time))
        self.assertTrue(is_in_block_indexed_by(
            m.b3['a', 1, m.time[1]].v1[m.space[1]], m.set2))
        self.assertFalse(is_in_block_indexed_by(
            m.b3['a', 1, m.time[1]].v1[m.space[1]], m.space))
        self.assertTrue(is_in_block_indexed_by(
            m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.set2))
        self.assertTrue(is_in_block_indexed_by(
            m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.time))
        self.assertTrue(is_in_block_indexed_by(
            m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.space))
        self.assertFalse(is_in_block_indexed_by(
            m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.set))
        self.assertFalse(is_in_block_indexed_by(
            m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.time,
            stop_at=m.b3['b', 2, m.time[2]]))
        self.assertFalse(is_in_block_indexed_by(
            m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.time,
            stop_at=m.b3))