def test_context(self): m = self.model() comp = m.b.v2[1, 0] context = m.b sets = ComponentSet((m.time, )) _slice = slice_component_along_sets(comp, sets) # Context makes no difference in resulting slice here. self.assertEqual(_slice, m.b.v2[:, 0]) comp = m.b.b2[1, 0].v2[1, 'a'] context = m.b.b2[1, 0] sets = ComponentSet((m.time, )) _slice = slice_component_along_sets(comp, sets, context=context) # Here, context does make a difference self.assertEqual(_slice, m.b.b2[1, 0].v2[:, 'a']) comp = m.b.b2[1, 0].v1['a'] context = m.b.b2[1, 0] sets = ComponentSet((m.time, )) _slice = slice_component_along_sets(comp, sets, context=context) self.assertIs(_slice, m.b.b2[1, 0].v1['a']) sets = ComponentSet((m.comp, )) _slice = slice_component_along_sets(comp, sets, context=context) self.assertEqual(_slice, m.b.b2[1, 0].v1[:]) context = m.b.b2 sets = ComponentSet((m.time, m.comp)) _slice = slice_component_along_sets(comp, sets, context=context) self.assertEqual(_slice, m.b.b2[:, 0].v1[:])
def expand_data_over_space(m, time, space, data): """ data maps time/space cuids to values. We get a data object from the cuid, then generate slices over time only at every point in space. """ sets = (time, ) t0 = next(iter(time)) new_data = {} for name, value in data.items(): var = m.find_component(name) if var is None: # Steady model won't have accumulation variables assert "accumulation" in name continue factor_sets = list(var.index_set().subsets()) if var.is_indexed() and len(factor_sets) == 2: # Assume our var is indexed by time, then space. for x in space: cuid = ComponentUID( slice_component_along_sets(var[t0, x], sets)) new_data[str(cuid)] = value else: new_data[name] = value return new_data
def test_cuid_of_slice(self): m = pyo.ConcreteModel() m.s1 = pyo.Set(initialize=["a", "b"]) m.s2 = pyo.Set(initialize=["c", "d"]) m.b = pyo.Block(m.s1) for i in m.s1: m.b[i].v = pyo.Var(m.s2) slice_ = slice_component_along_sets(m.b["a"].v["c"], ComponentSet((m.s1, ))) cuid = pyo.ComponentUID(slice_) self.assertEqual(str(cuid), "b[*].v[c]") slice_ = slice_component_along_sets(m.b["a"].v[("c", )], ComponentSet((m.s1, ))) cuid = pyo.ComponentUID(slice_) self.assertEqual(str(cuid), "b[*].v[c]")
def get_time_indexed_cuid(var, sets=None, dereference=None): """ Arguments --------- var: Object to process time: Set Set to use if slicing a vardata object dereference: None or int Number of times we may access referent attribute to recover a "base component" from a reference. """ # TODO: Does this function have a good name? # Should this function be generalized beyond a single indexing set? # Is allowing dereference to be an integer worth the confusion it might # add? if dereference is None: # Does this branch make sense? If given an unattached component, # we dereference, otherwise we don't dereference. remaining_dereferences = int(var.parent_block() is None) else: remaining_dereferences = int(dereference) if var.is_indexed(): if var.is_reference() and remaining_dereferences: remaining_dereferences -= 1 referent = var.referent if isinstance(referent, IndexedComponent_slice): return ComponentUID(referent) else: # If dereference is None, we propagate None, dereferencing # until we either reach a component attached to a block # or reach a non-reference component. dereference = dereference if dereference is None else\ remaining_dereferences # NOTE: Calling this function recursively return get_time_indexed_cuid(referent, time, dereference=dereference) else: # Assume that var is indexed only by time # TODO: Get appropriate slice for indexing set. # TODO: Should we call slice_component_along_sets here as well? # To cover the case of b[t0].var, where var is indexed # by a set we care about, and we also care about time... # But then maybe we should slice only the sets we care about... # Don't want to do anything with these sets unless we're # presented with a vardata... #index = tuple( # get_slice_for_set(s) for s in var.index_set().subsets() #) index = get_slice_for_set(var.index_set()) return ComponentUID(var[:]) else: if sets is None: raise ValueError( "A ComponentData %s was provided but no set. We need to know\n" "what set this component should be indexed by." % var.name) slice_ = slice_component_along_sets(var, sets) return ComponentUID(slice_)
def get_max_values_from_steady(m): time = m.fs.time assert len(time) == 1 t0 = next(iter(time)) gas_length = m.fs.MB.gas_phase.length_domain solid_length = m.fs.MB.solid_phase.length_domain sets = (time, gas_length, solid_length) sets_list, comps_list = flatten_components_along_sets(m, sets, pyo.Var) for sets, comps in zip(sets_list, comps_list): if len(sets) == 2 and sets[0] is time and sets[1] is gas_length: gas_comps = comps elif len(sets) == 2 and sets[0] is time and sets[1] is solid_length: solid_comps = comps variables = gas_comps + solid_comps max_values = ComponentMap( ( var, max(abs(data.value) for data in var.values() if data.value is not None), ) for var in variables ) # Maps time indexed vars to their max values over space max_values_time = {} for var in variables: for x in gas_length: sliced = slice_component_along_sets(var[t0, x], (time,)) max_values_time[str(pyo.ComponentUID(sliced))] = max_values[var] return max_values_time
def test_with_tuple_of_sets(self): m = pyo.ConcreteModel() m.s1 = pyo.Set(initialize=[1, 2, 3]) m.s2 = pyo.Set(initialize=[1, 2, 3]) m.v = pyo.Var(m.s1, m.s2) sets = (m.s1, ) slice_ = slice_component_along_sets(m.v[1, 2], sets) # These tests are essentially the same, but we run the CUID test # first as it gives a nicer error message. self.assertEqual(str(pyo.ComponentUID(slice_)), "v[*,2]") self.assertEqual(slice_, m.v[:, 2])
def test_none_dimen(self): m = self.model() comp = m.b.b2[1, 0].vn sets = ComponentSet((m.d_none, )) _slice = slice_component_along_sets(comp, sets) self.assertIs(_slice, m.b.b2[1, 0].vn) comp = m.b.b2[1, 0].vn[1, 'd', 3, 'a', 1] sets = ComponentSet((m.d_2, m.time)) _slice = slice_component_along_sets(comp, sets) self.assertEqual(_slice, m.b.b2[:, 0].vn[:, 'd', 3, :, :]) sets = ComponentSet((m.d_none, m.d_2)) _slice = slice_component_along_sets(comp, sets) self.assertEqual(_slice, m.b.b2[1, 0].vn[1, ..., :, :]) comp = m.b.bn['c', 1, 10, 'a', 1].v3[1, 0, 1] sets = ComponentSet((m.d_none, m.time)) _slice = slice_component_along_sets(comp, sets) self.assertEqual(_slice, m.b.bn[..., 'a', 1].v3[:, 0, :]) comp = m.b.bn['c', 1, 10, 'a', 1].vn[1, 'd', 3, 'b', 2] sets = ComponentSet((m.d_none, )) _slice = slice_component_along_sets(comp, sets) self.assertEqual(_slice, m.b.bn[..., 'a', 1].vn[1, ..., 'b', 2]) sets = ComponentSet((m.d_none, m.d_2)) _slice = slice_component_along_sets(comp, sets) self.assertEqual(_slice, m.b.bn[..., :, :].vn[1, ..., :, :]) comp = m.b.bn['c', 1, 10, 'a', 1].vn[1, 'd', 3, 'b', 2] context = m.b.bn['c', 1, 10, 'a', 1] sets = ComponentSet((m.d_none, )) _slice = slice_component_along_sets(comp, sets, context=context) self.assertEqual(_slice, m.b.bn['c', 1, 10, 'a', 1].vn[1, ..., 'b', 2]) sets = ComponentSet((m.d_none, m.d_2)) _slice = slice_component_along_sets(comp, sets, context=context) self.assertEqual(_slice, m.b.bn['c', 1, 10, 'a', 1].vn[1, ..., :, :]) context = m.b.bn sets = ComponentSet((m.d_none, )) _slice = slice_component_along_sets(comp, sets, context=context) self.assertEqual(_slice, m.b.bn[..., 'a', 1].vn[1, ..., 'b', 2])
def test_no_context(self): m = self.model() comp = m.b.v0 sets = ComponentSet((m.time, m.space)) _slice = slice_component_along_sets(comp, sets) # Use `assertIs` when the "slice" is actually just a component. self.assertIs(_slice, m.b.v0) comp = m.b.v1[1] sets = ComponentSet((m.time, m.space)) _slice = slice_component_along_sets(comp, sets) self.assertEqual(_slice, m.b.v1[:]) comp = m.b.v2[1, 0] sets = ComponentSet((m.time, m.space)) _slice = slice_component_along_sets(comp, sets) self.assertEqual(_slice, m.b.v2[:, :]) comp = m.b.b2[1, 0].v1['a'] sets = ComponentSet((m.time, m.space)) _slice = slice_component_along_sets(comp, sets) self.assertEqual(_slice, m.b.b2[:, :].v1['a']) comp = m.b.b2[1, 0].v1 sets = ComponentSet((m.time, m.space)) _slice = slice_component_along_sets(comp, sets) self.assertEqual(_slice, m.b.b2[:, :].v1) comp = m.b.b2[1, 0].v2[1, 'a'] sets = ComponentSet((m.time, )) _slice = slice_component_along_sets(comp, sets) self.assertEqual(_slice, m.b.b2[:, 0].v2[:, 'a']) comp = m.b.bn['c', 1, 10, 'a', 1].v3[1, 0, 1] sets = ComponentSet((m.time, )) _slice = slice_component_along_sets(comp, sets) self.assertEqual(_slice, m.b.bn['c', 1, 10, 'a', 1].v3[:, 0, :])
def __init__(self, plant_model=None, plant_time_set=None, controller_model=None, controller_time_set=None, inputs_at_t0=None, measurements=None, sample_time=None, **kwargs): """ Measurements must be defined in the controller model. Inputs must be defined in the plant model. """ # To find components in a model given a name, # modulo the index of some set: # i. slice the component along the set # ii. create a cuid from that slice # iii. get a reference to the slice from the cuid on the new model # iv. access the reference at the index you want (optional) self.measurement_cuids = [ ComponentUID( slice_component_along_sets(comp, (controller_time_set, ))) for comp in measurements ] self.input_cuids = [ ComponentUID(slice_component_along_sets(comp, (plant_time_set, ))) for comp in inputs_at_t0 ] p_t0 = plant_time_set.first() init_plant_measurements = [ cuid.find_component_on(plant_model)[p_t0] for cuid in self.measurement_cuids ] self.plant = DynamicBlock( model=plant_model, time=plant_time_set, inputs=inputs_at_t0, measurements=init_plant_measurements, ) self.plant.construct() # Here we repeat essentially the same "find component" # procedure as above. c_t0 = controller_time_set.first() init_controller_inputs = [ cuid.find_component_on(controller_model)[c_t0] for cuid in self.input_cuids ] self.controller = ControllerBlock( model=controller_model, time=controller_time_set, inputs=init_controller_inputs, measurements=measurements, ) self.controller.construct() if sample_time is not None: self.controller.set_sample_time(sample_time) self.plant.set_sample_time(sample_time) self.sample_time = sample_time