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
def get_derivatives_at(b, time, pts): """ Finds derivatives with respect to time at points specified. No distinction made for multiple derivatives or mixed partials. Args: b : Block to search for derivatives time : ContinuousSet to look for derivatives with respect to pts : Value or list of values in time set at which to return derivatives Returns Dictionary mapping time points to lists of derivatives at those points """ if not type(pts) is list: pts = [pts] dvdict = {pt: [] for pt in pts} visited = set() for var in b.component_objects(Var): if id(var) in visited: continue visited.add(id(var)) if not isinstance(var, DerivativeVar): continue if time not in ComponentSet(var.get_continuousset_list()): continue info = get_index_set_except(var, time) non_time_set = info['set_except'] index_getter = info['index_getter'] for pt in pts: for non_time_index in non_time_set: index = index_getter(non_time_index, pt) dvdict[pt].append(var[index]) return dvdict
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)
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)
def test_get_index_set_except(self): ''' Tests: For components indexed by 0, 1, 2, 3, 4 sets: get_index_set_except one, then two (if any) of those sets check two items that should be in set_except insert item(s) back into these sets via index_getter ''' m = ConcreteModel() m.time = ContinuousSet(bounds=(0, 10)) m.space = ContinuousSet(bounds=(0, 10)) m.set1 = Set(initialize=['a', 'b', 'c']) m.set2 = Set(initialize=['d', 'e', 'f']) m.v = Var() m.v1 = Var(m.time) m.v2 = Var(m.time, m.space) m.v3 = Var(m.time, m.space, m.set1) m.v4 = Var(m.time, m.space, m.set1, m.set2) # Multi-dimensional set: m.set3 = Set(initialize=[('a', 1), ('b', 2)]) m.v5 = Var(m.set3) m.v6 = Var(m.time, m.space, m.set3) m.v7 = Var(m.set3, m.space, m.time) 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') # Want this to give a TypeError # info = get_index_set_except(m.v, m.time) # Indexed by one set info = get_index_set_except(m.v1, m.time) set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue(set_except == [None]) # Variable is not indexed by anything except time # Test that index_getter returns only the new value given, # regardless of whether it was part of the set excluded (time): self.assertEqual(index_getter((), -1), -1) # Indexed by two sets info = get_index_set_except(m.v2, m.time) set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue(m.space[1] in set_except and m.space.last() in set_except) # Here (2,) is the partial index, corresponding to space. # Can be provided as a scalar or tuple. 4, the time index, # should be inserted before (2,) self.assertEqual(index_getter((2,), 4), (4, 2)) self.assertEqual(index_getter(2, 4), (4, 2)) # Case where every set is "omitted," now for multiple sets info = get_index_set_except(m.v2, m.space, m.time) set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue(set_except == [None]) # 5, 7 are the desired index values for space, time # index_getter should put them in the right order for m.v2, # even if they are not valid indices for m.v2 self.assertEqual(index_getter((), 5, 7), (7, 5)) # Indexed by three sets info = get_index_set_except(m.v3, m.time) # In this case set_except is a product of the two non-time sets # indexing v3 set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue((m.space[1], 'b') in set_except and (m.space.last(), 'a') in set_except) # index_getter inserts a scalar index into an index of length 2 self.assertEqual(index_getter((2, 'b'), 7), (7, 2, 'b')) info = get_index_set_except(m.v3, m.space, m.time) # Two sets omitted. Now set_except is just set1 set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue('a' in set_except) # index_getter inserts the two new indices in the right order self.assertEqual(index_getter('b', 1.2, 1.1), (1.1, 1.2, 'b')) # Indexed by four sets info = get_index_set_except(m.v4, m.set1, m.space) # set_except is a product, and there are two indices to insert set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue((m.time[1], 'd') in set_except) self.assertEqual(index_getter((4, 'f'), 'b', 8), (4, 8, 'b', 'f')) # The intended usage of this function looks something like: index_set = m.v4.index_set() for partial_index in set_except: complete_index = index_getter(partial_index, 'a', m.space[2]) self.assertTrue(complete_index in index_set) # Do something for every index of v4 at 'a' and space[2] # Indexed by a multi-dimensional set info = get_index_set_except(m.v5, m.set3) set_except = info['set_except'] index_getter = info['index_getter'] self.assertEqual(set_except, [None]) self.assertEqual(index_getter((), ('a', 1)), ('a', 1)) info = get_index_set_except(m.v6, m.set3, m.time) set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue(m.space[1] in set_except) self.assertEqual(index_getter(m.space[1], ('b', 2), m.time[1]), (m.time[1], m.space[1], 'b', 2)) info = get_index_set_except(m.v7, m.time) set_except = info['set_except'] index_getter = info['index_getter'] self.assertIn(('a', 1, m.space[1]), set_except) self.assertEqual(index_getter(('a', 1, m.space[1]), m.time[1]), ('a', 1, m.space[1], m.time[1])) m.v8 = Var(m.time, m.set3, m.time) with self.assertRaises(ValueError): info = get_index_set_except(m.v8, m.time) with self.assertRaises(ValueError): info = get_index_set_except(m.v8, m.space)