def test_construct_indexed(self): controller_set = pyo.Set(initialize=[0, 1, 2]) controller_set.construct() horizon_map = {0: 1., 1: 3., 2: 5.} nfe_map = {0: 2, 1: 6, 2: 10} model_map = { i: make_model(horizon_map[i], nfe_map[i]) for i in controller_set } time_map = {i: model_map[i].time for i in controller_set} inputs_map = {i: [model_map[i].flow_in[0]] for i in controller_set} controller = ControllerBlock( controller_set, model=model_map, time=time_map, inputs=inputs_map, ) assert type(controller) is IndexedControllerBlock assert isinstance(controller, IndexedControllerBlock) controller.construct() assert all(b.parent_component() is controller for b in controller.values()) for i in controller_set: assert i in controller for i, c in controller.items(): assert c.mod is model_map[i] assert c.time is time_map[i] assert all(i1 is i2 for i1, i2 in zip(c._inputs, inputs_map[i]))
def make_block(self, sample_time=0.5, horizon=1, nfe=2): model = make_model(horizon=horizon, nfe=nfe) time = model.time t0 = time.first() inputs = [model.flow_in[t0]] measurements = [model.conc[t0, 'A'], model.conc[t0, 'B']] scalar_vars, dae_vars = flatten_dae_components( model, time, pyo.Var, ) category_dict = categorize_dae_variables(dae_vars, time, inputs, measurements=measurements) dyn_block = DynamicBlock( model=model, time=time, category_dict={None: category_dict}, #inputs=inputs, #measurements=measurements, ) dyn_block.construct() dyn_block.set_sample_time(sample_time) return dyn_block
def test_empty_category(self): model = make_model(horizon=1, nfe=2) time = model.time t0 = time.first() inputs = [model.flow_in] measurements = [ pyo.Reference(model.conc[:, 'A']), pyo.Reference(model.conc[:, 'B']), ] category_dict = { VC.INPUT: inputs, VC.MEASUREMENT: measurements, VC.ALGEBRAIC: [], } db = DynamicBlock( model=model, time=time, category_dict={None: category_dict}, ) db.construct() db.set_sample_time(0.5) # Categories with no variables are removed. # If they were retained, trying to iterate # over, e.g., vectors.algebraic[:, :] would # fail due to inconsistent dimension. assert VC.ALGEBRAIC not in db.category_dict
def test_extra_category(self): model = make_model(horizon=1, nfe=2) time = model.time t0 = time.first() inputs = [model.flow_in] measurements = [ pyo.Reference(model.conc[:, 'A']), pyo.Reference(model.conc[:, 'B']), ] disturbances = [ pyo.Reference(model.conc_in[:, 'A']), pyo.Reference(model.conc_in[:, 'B']), ] category_dict = { VC.INPUT: inputs, VC.MEASUREMENT: measurements, VC.DISTURBANCE: disturbances, } db = DynamicBlock( model=model, time=time, category_dict={None: category_dict}, ) db.construct() db.set_sample_time(0.5) db.vectors.input[:, t0].set_value(1.1) db.vectors.measurement[:, t0].set_value(2.2) db.vectors.disturbance[:, t0].set_value(3.3) assert model.flow_in[t0].value == 1.1 assert model.conc[t0, 'A'].value == 2.2 assert model.conc[t0, 'B'].value == 2.2 assert model.conc_in[t0, 'A'].value == 3.3 assert model.conc_in[t0, 'B'].value == 3.3
def make_controller(self, sample_time=0.5, horizon=1., nfe=2): model = make_model(horizon=horizon, nfe=nfe) time = model.time t0 = time.first() inputs = [model.flow_in[t0]] controller = ControllerBlock( model=model, time=time, inputs=inputs, ) controller.construct() controller.set_sample_time(sample_time) return controller
def make_block(self, sample_time=0.5, horizon=1, nfe=2): model = make_model(horizon=horizon, nfe=nfe) time = model.time t0 = time.first() inputs = [model.flow_in[t0]] measurements = [model.conc[t0,'A'], model.conc[t0,'B']] dyn_block = DynamicBlock( model=model, time=time, inputs=inputs, measurements=measurements, ) dyn_block.construct() dyn_block.set_sample_time(sample_time) return dyn_block
def test_validate_sample_time(self): model = make_model(horizon=1, nfe=2) time = model.time t0 = time.first() inputs = [model.flow_in[t0]] measurements = [model.conc[t0,'A'], model.conc[t0,'B']] blk = DynamicBlock( model=model, time=time, inputs=inputs, measurements=measurements, ) blk.construct() blk.validate_sample_time(0.5) assert hasattr(blk, 'sample_points') assert hasattr(blk, 'fe_per_sample') assert hasattr(blk, 'sample_point_indices') sample_point_set = set(blk.sample_points) sample_point_indices = set(blk.sample_point_indices) for p in [0.0, 0.5, 1.0]: assert p in sample_point_set for i in [1, 3, 5]: assert i in sample_point_indices assert len(sample_point_set) == 3 assert len(sample_point_indices) == 3 with pytest.raises(ValueError, match=r".*integer divider.*"): blk.validate_sample_time(0.6) with pytest.raises(ValueError, match=r"Could not find a time point.*"): blk.validate_sample_time(1/3.) with pytest.raises(ValueError, match=r".*tolerance is larger than.*not.*unique.*"): blk.validate_sample_time(0.5, tolerance=0.09) # min spacing in continuous set: 0.166667 blk.validate_sample_time(0.5, tolerance=0.08) sample_point_set = set(blk.sample_points) for p in [0.0, 0.5, 1.0]: assert p in sample_point_set for i in [1, 3, 5]: assert i in sample_point_indices assert len(sample_point_set) == 3 assert len(sample_point_indices) == 3
def test_set_sample_time(self): model = make_model(horizon=1, nfe=2) time = model.time t0 = time.first() inputs = [model.flow_in[t0]] measurements = [model.conc[t0,'A'], model.conc[t0,'B']] blk = DynamicBlock( model=model, time=time, inputs=inputs, measurements=measurements, ) blk.construct() blk.set_sample_time(1.0) assert blk.sample_points == [0.0, 1.0] blk.set_sample_time(0.5) assert blk.sample_points == [0.0, 0.5, 1.0]
def test_initialize_only_measurement_input(self): model = make_model(horizon=1, nfe=2) time = model.time t0 = time.first() inputs = [model.flow_in] measurements = [ pyo.Reference(model.conc[:, 'A']), pyo.Reference(model.conc[:, 'B']), ] category_dict = { VC.INPUT: inputs, VC.MEASUREMENT: measurements, } db = DynamicBlock( model=model, time=time, category_dict={None: category_dict}, ) db.construct() db.set_sample_time(0.5) db.mod.flow_in[:].set_value(3.0) initialize_t0(db.mod) copy_values_forward(db.mod) db.mod.flow_in[:].set_value(2.0) # Don't need to know any of the special categories to initialize # by element. This is only because we have an implicit discretization. db.initialize_by_solving_elements(solver) t0 = time.first() tl = time.last() vectors = db.vectors assert vectors.input[0, tl].value == 2.0 assert vectors.measurement[0, tl].value == pytest.approx( 3.185595567867036) assert vectors.measurement[1, tl].value == pytest.approx( 1.1532474073395755) assert model.dcdt[tl, 'A'].value == pytest.approx(0.44321329639889284) assert model.dcdt[tl, 'B'].value == pytest.approx(0.8791007531878847)
def test_init_simple(self): model = make_model(horizon=1, nfe=2) time = model.time t0 = time.first() inputs = [model.flow_in[t0]] measurements = [model.conc[0,'A'], model.conc[0,'B']] block = DynamicBlock( model=model, time=time, inputs=inputs, measurements=measurements, ) # Assert that we have the correct type assert type(block) is SimpleDynamicBlock assert isinstance(block, DynamicBlock) assert isinstance(block, _DynamicBlockData) block.construct() # Assert that we behave like a simple block assert block[None] is block assert all(b is block for b in block[:]) # Assert that input attributes have been processed correctly assert block.mod is model assert block.time is time assert all(i1 is i2 for i1, i2 in zip(block._inputs, inputs)) assert all(i1 is i2 for i1, i2 in zip(block._measurements, measurements)) # Assert that utility attributes have been added assert hasattr(block, 'category_dict') assert hasattr(block, 'vardata_map') assert hasattr(block, 'measurement_vars') assert hasattr(block, 'differential_vars') assert hasattr(block, 'algebraic_vars') assert hasattr(block, 'derivative_vars') assert hasattr(block, 'input_vars') assert hasattr(block, 'fixed_vars') subblocks = [ block.mod, block.vectors, block.DIFFERENTIAL_BLOCK, block.ALGEBRAIC_BLOCK, block.INPUT_BLOCK, block.FIXED_BLOCK, block.DERIVATIVE_BLOCK, block.MEASUREMENT_BLOCK, ] block_objects = ComponentSet( block.component_objects(pyo.Block, descend_into=False)) # Assert that subblocks have been added assert len(subblocks) == len(block_objects) for b in subblocks: assert b in block_objects # Assert that we can add variables and constraints to the block block.v = pyo.Var(initialize=3) block.c = pyo.Constraint(expr=block.v==5) assert block.v.value == 3 assert block.v in ComponentSet(identify_variables(block.c.expr))
def test_init_rule(self): block_set = pyo.Set(initialize=range(3)) block_set.construct() # Create same maps as before horizon_map = {0: 1, 1: 3, 2: 5} nfe_map = {0: 2, 1: 6, 2: 10} model_map = { i: make_model(horizon=horizon_map[i], nfe=nfe_map[i]) for i in block_set } # Create rule to construct DynamicBlock with def dynamic_block_rule(b, i): model = model_map[i] time = model.time t0 = time.first() inputs = [model.flow_in[t0]] measurements = [model.conc[0,'A'], model.conc[0,'B']] # Won't be obvious that these attrs need to be set if # constructing from a rule b.mod = model super(_BlockData, b).__setattr__('time', time) b._inputs = inputs b._measurements = measurements # Create DynamicBlock from a rule block = DynamicBlock(block_set, rule=dynamic_block_rule) assert type(block) is IndexedDynamicBlock assert isinstance(block, DynamicBlock) block.construct() # Make sure iterating over block.values works as expected assert all(b.parent_component() is block for b in block.values()) # Make sure __contains__ works for i in block_set: assert i in block # Assert correct attributes and subblocks for i, b in block.items(): assert b.mod is model_map[i] assert b.time is model_map[i].time t0 = b.time.first() assert all(i1 is i2 for i1, i2 in zip(b._inputs, [model_map[i].flow_in[t0]])) assert all(i1 is i2 for i1, i2 in zip(b._measurements, [model_map[i].conc[t0,'A'], model_map[i].conc[t0,'B']])) assert hasattr(b, 'category_dict') assert hasattr(b, 'vardata_map') assert hasattr(b, 'measurement_vars') assert hasattr(b, 'differential_vars') assert hasattr(b, 'algebraic_vars') assert hasattr(b, 'derivative_vars') assert hasattr(b, 'input_vars') assert hasattr(b, 'fixed_vars') subblocks = [ b.mod, b.vectors, b.DIFFERENTIAL_BLOCK, b.ALGEBRAIC_BLOCK, b.INPUT_BLOCK, b.FIXED_BLOCK, b.DERIVATIVE_BLOCK, b.MEASUREMENT_BLOCK, ] block_objects = ComponentSet( b.component_objects(pyo.Block, descend_into=False)) assert len(subblocks) == len(block_objects) for sb in subblocks: assert sb in block_objects b.v = pyo.Var(initialize=3) b.c = pyo.Constraint(expr=b.v==5) assert b.v.value == 3 assert b.v in ComponentSet(identify_variables(b.c.expr))
def test_init_indexed(self): block_set = pyo.Set(initialize=[0,1,2]) block_set.construct() horizon_map = {0: 1., 1: 3., 2: 5.} nfe_map = {0: 2, 1: 6, 2: 10} model_map = {i: make_model(horizon_map[i], nfe_map[i]) for i in block_set} time_map = {i: model_map[i].time for i in block_set} inputs_map = {i: [model_map[i].flow_in[0]] for i in block_set} measurements_map = { i: [model_map[i].conc[0,'A'], model_map[i].conc[0,'B']] for i in block_set } # Construct block with a dict for each of its arguments block = DynamicBlock( block_set, model=model_map, time=time_map, inputs=inputs_map, measurements=measurements_map, ) # Make sure we have the right type assert type(block) is IndexedDynamicBlock assert isinstance(block, DynamicBlock) block.construct() assert all(b.parent_component() is block for b in block.values()) # Check __contains__ for i in block_set: assert i in block # Check attributes and subblocks of each data object for i, b in block.items(): assert b.mod is model_map[i] assert b.time is time_map[i] assert all(i1 is i2 for i1, i2 in zip(b._inputs, inputs_map[i])) assert all(i1 is i2 for i1, i2 in zip(b._measurements, measurements_map[i])) assert hasattr(b, 'category_dict') assert hasattr(b, 'vardata_map') assert hasattr(b, 'measurement_vars') assert hasattr(b, 'differential_vars') assert hasattr(b, 'algebraic_vars') assert hasattr(b, 'derivative_vars') assert hasattr(b, 'input_vars') assert hasattr(b, 'fixed_vars') subblocks = [ b.mod, b.vectors, b.DIFFERENTIAL_BLOCK, b.ALGEBRAIC_BLOCK, b.INPUT_BLOCK, b.FIXED_BLOCK, b.DERIVATIVE_BLOCK, b.MEASUREMENT_BLOCK, ] block_objects = ComponentSet( b.component_objects(pyo.Block, descend_into=False)) assert len(subblocks) == len(block_objects) for sb in subblocks: assert sb in block_objects b.v = pyo.Var(initialize=3) b.c = pyo.Constraint(expr=b.v==5) assert b.v.value == 3 assert b.v in ComponentSet(identify_variables(b.c.expr))