def test_no_strip_domain(self): """Test bounds stripping without domain change.""" m = ConcreteModel() m.v0 = Var(bounds=(2, 4)) m.v1 = Var(domain=NonNegativeReals) m.v2 = Var(domain=PositiveReals) m.v3 = Var(bounds=(-1, 1)) m.v4 = Var(domain=Binary) m.v5 = Var(domain=Integers, bounds=(15, 16)) xfrm = TransformationFactory('contrib.strip_var_bounds') xfrm.apply_to(m, strip_domains=False, reversible=True) self.assertEqual(m.v0.bounds, (None, None)) self.assertEqual(m.v1.bounds, (0, None)) self.assertEqual(m.v2.bounds, (0, None)) self.assertEqual(m.v3.bounds, (None, None)) self.assertEqual(m.v4.bounds, (0, 1)) self.assertEqual(m.v5.bounds, (None, None)) self.assertEqual(m.v0.domain, Reals) self.assertEqual(m.v1.domain, NonNegativeReals) self.assertEqual(m.v2.domain, PositiveReals) self.assertEqual(m.v3.domain, Reals) self.assertEqual(m.v4.domain, Binary) self.assertEqual(m.v5.domain, Integers) xfrm.revert(m) self.assertEqual(m.v0.bounds, (2, 4)) self.assertEqual(m.v1.bounds, (0, None)) self.assertEqual(m.v2.bounds, (0, None)) self.assertEqual(m.v3.bounds, (-1, 1)) self.assertEqual(m.v4.bounds, (0, 1)) self.assertEqual(m.v5.bounds, (15, 16)) self.assertEqual(m.v0.domain, Reals) self.assertEqual(m.v1.domain, NonNegativeReals) self.assertEqual(m.v2.domain, PositiveReals) self.assertEqual(m.v3.domain, Reals) self.assertEqual(m.v4.domain, Binary) self.assertEqual(m.v5.domain, Integers)
def test_abs(self): from lms2 import DynUnit from pyomo.environ import AbstractModel, TransformationFactory from pyomo.dae import ContinuousSet m = AbstractModel() m.time = ContinuousSet() m.u = DynUnit() data_absdyn = dict(time={None: [0, 15]}) data = \ {None: { 'time': {None: [0, 15]}, 'u': data_absdyn } } inst = m.create_instance(data) TransformationFactory('dae.finite_difference').apply_to(inst, nfe=1) self.assertEqual(inst.u.time.data(), (0, 15)) self.assertEqual(inst.time.data(), (0, 15))
def test_cut_is_correct_facet_rescaled_fme(self): m = models.to_break_constraint_tolerances() TransformationFactory('gdp.cuttingplane').apply_to( m, create_cuts=create_cuts_fme, post_process_cut=None) cuts = m._pyomo_gdp_cuttingplane_transformation.cuts self.assertEqual(len(cuts), 1) # we don't get a whole facet. We get 0 <= 129y_1 + 123y_2 - x - y, which # is the sum of two facets: # 0 <= 2y_1 + 120y_2 - x and # 0 <= 127y_1 + 3y_2 - y # But this is valid and the only cut needed, so we won't complain. cut_extreme_points = [(1, 0, 2, 127), (0, 1, 120, 3)] for pt in cut_extreme_points: m.x.fix(pt[2]) m.y.fix(pt[3]) m.disjunct1.indicator_var.fix(pt[0]) m.disjunct2.indicator_var.fix(pt[1]) # tiny bit of numerical error self.assertAlmostEqual(value(cuts[0].lower), value(cuts[0].body)) self.assertLessEqual(value(cuts[0].lower), value(cuts[0].body))
def test_link_with_gdp_indicators(self): m = _generate_boolean_model(4) m.d1 = Disjunct() m.d2 = Disjunct() m.x = Var() m.dd = Disjunct([1, 2]) m.d1.c = Constraint(expr=m.x >= 2) m.d2.c = Constraint(expr=m.x <= 10) m.dd[1].c = Constraint(expr=m.x >= 5) m.dd[2].c = Constraint(expr=m.x <= 6) m.Y[1].associate_binary_var(m.d1.indicator_var) m.Y[2].associate_binary_var(m.d2.indicator_var) m.Y[3].associate_binary_var(m.dd[1].indicator_var) m.Y[4].associate_binary_var(m.dd[2].indicator_var) m.p = LogicalConstraint(expr=m.Y[1].implies(lor(m.Y[3], m.Y[4]))) m.p2 = LogicalConstraint(expr=atmost(2, *m.Y[:])) TransformationFactory('core.logical_to_linear').apply_to(m) _constrs_contained_within( self, [(1, m.dd[1].indicator_var + m.dd[2].indicator_var + 1 - m.d1.indicator_var, None), (None, m.d1.indicator_var + m.d2.indicator_var + m.dd[1].indicator_var + m.dd[2].indicator_var, 2)], m.logic_to_linear.transformed_constraints)
def test_induced_linear_in_disjunct(self): m = ConcreteModel() m.x = Var([0], bounds=(-3, 8)) m.y = Var(RangeSet(2), domain=Binary) m.logical = ConstraintList() m.logical.add(expr=m.y[1] + m.y[2] == 1) m.v = Var([1]) m.v[1].setlb(-2) m.v[1].setub(7) m.bilinear_outside = Constraint( expr=m.x[0] * m.v[1] >= 2) m.disjctn = Disjunction(expr=[ [m.x[0] * m.v[1] == 3, 2 * m.x[0] == m.y[1] + m.y[2]], [m.x[0] * m.v[1] == 4] ]) TransformationFactory('contrib.induced_linearity').apply_to(m) self.assertEqual( m.disjctn.disjuncts[0].constraint[1].body.polynomial_degree(), 1) self.assertEqual( m.bilinear_outside.body.polynomial_degree(), 2) self.assertEqual( m.disjctn.disjuncts[1].constraint[1].body.polynomial_degree(), 2)
def test_initialize_dyn(build_turbine_dyn): """Initialize a turbine model""" m = build_turbine_dyn hin = iapws95.htpx(T=880, P=2.4233e7) discretizer = TransformationFactory('dae.finite_difference') discretizer.apply_to(m, nfe=4, wrt=m.fs.time, scheme='BACKWARD') # fix inlet m.fs.turb.inlet[:].enth_mol.fix(hin) m.fs.turb.inlet[:].flow_mol.fix(26000 / 4.0) m.fs.turb.inlet[:].pressure.fix(2.4233e7) m.fs.turb.flow_coeff[:].fix() assert (degrees_of_freedom(m) == 0) m.fs.turb.initialize() eq_cons = activated_equalities_generator(m) for c in eq_cons: assert (abs(c.body() - c.lower) < 1e-4) m.display() assert (degrees_of_freedom(m) == 0)
def test_reclassify_deactivated_disjuncts(self): m = ConcreteModel() m.d = Disjunct([1, 2, 3]) m.disjunction = Disjunction(expr=[m.d[1], m.d[2], m.d[3]]) m.d[1].deactivate() m.d[2].indicator_var = True m.d[3].indicator_var = False TransformationFactory('gdp.fix_disjuncts').apply_to(m) self.assertTrue(m.d[1].indicator_var.fixed) self.assertFalse(value(m.d[1].indicator_var)) self.assertFalse(m.d[1].active) self.assertEqual(m.d[1].ctype, Block) self.assertTrue(m.d[2].indicator_var.fixed) self.assertTrue(value(m.d[2].indicator_var)) self.assertTrue(m.d[2].active) self.assertTrue(m.d[3].indicator_var.fixed) self.assertFalse(value(m.d[3].indicator_var)) self.assertFalse(m.d[3].active) self.assertEqual(m.d[1].ctype, Block) self.assertEqual(m.d[2].ctype, Block)
def test_disc_second_order_backward(self): m = self.m.clone() m.dv1dt2 = DerivativeVar(m.v1, wrt=(m.t, m.t)) disc = TransformationFactory('dae.finite_difference') disc.apply_to(m, nfe=2) self.assertTrue(hasattr(m, 'dv1dt2_disc_eq')) self.assertEqual(len(m.dv1dt2_disc_eq), 1) self.assertEqual(len(m.v1), 3) self.assertTrue(hasattr(m, '_pyomo_dae_reclassified_derivativevars')) self.assertIn(m.dv1, m._pyomo_dae_reclassified_derivativevars) self.assertIn(m.dv1dt2, m._pyomo_dae_reclassified_derivativevars) output = \ """\ dv1dt2_disc_eq : Size=1, Index=t, Active=True Key : Lower : Body : Upper : Active 10 : 0.0 : dv1dt2[10] - 0.04*(v1[10] - 2*v1[5.0] + v1[0]) : 0.0 : True """ out = StringIO() m.dv1dt2_disc_eq.pprint(ostream=out) self.assertEqual(output, out.getvalue())
def test_instanciate(self): from lms2 import AbsLModel from lms2 import ScalablePowerSource import pandas as pd from pyomo.dae import ContinuousSet from pyomo.environ import TransformationFactory m = AbsLModel() m.time = ContinuousSet() m.u = ScalablePowerSource(curtailable=False) df = pd.Series({0: 0, 1: 1, 2: 2, 3: 1, 4: 0}) data_u = { 'time': { None: [0, 4] }, 'profile_index': { None: df.index }, 'profile_value': df.to_dict() } data = \ {None: { 'time': {None: [0, 4]}, 'u': data_u } } inst = m.create_instance(data) TransformationFactory('dae.finite_difference').apply_to(inst, nfe=4) self.assertFalse(hasattr(inst.u, 'p_curt')) self.assertTrue(hasattr(inst.u, 'p')) self.assertTrue(hasattr(inst.u, 'p_scaled')) self.assertTrue(hasattr(inst.u, 'scale_fact'))
def test_disc_second_order_legendre(self): m = self.m.clone() m.dv1dt2 = DerivativeVar(m.v1, wrt=(m.t, m.t)) disc = TransformationFactory('dae.collocation') disc.apply_to(m, nfe=2, ncp=2, scheme='LAGRANGE-LEGENDRE') self.assertTrue(hasattr(m, 'dv1dt2_disc_eq')) self.assertTrue(hasattr(m, 'v1_t_cont_eq')) self.assertTrue(len(m.dv1dt2_disc_eq) == 4) self.assertTrue(len(m.v1_t_cont_eq) == 2) self.assertTrue(len(m.v1) == 7) self.assertTrue(hasattr(m, '_pyomo_dae_reclassified_derivativevars')) self.assertTrue(m.dv1 in m._pyomo_dae_reclassified_derivativevars) self.assertTrue(m.dv1dt2 in m._pyomo_dae_reclassified_derivativevars) repn_baseline = { id(m.dv1dt2[1.056624]): 1, id(m.v1[0]): -0.48, id(m.v1[1.056624]): 0.65569, id(m.v1[3.943376]): -0.17569 } repn = generate_standard_repn(m.dv1dt2_disc_eq[1.056624].body) repn_gen = repn_to_rounded_dict(repn, 5) self.assertEqual(repn_baseline, repn_gen) repn_baseline = { id(m.dv1dt2[6.056624]): 1, id(m.v1[5.0]): -0.48, id(m.v1[6.056624]): 0.65569, id(m.v1[8.943376]): -0.17569 } repn = generate_standard_repn(m.dv1dt2_disc_eq[6.056624].body) repn_gen = repn_to_rounded_dict(repn, 5) self.assertEqual(repn_baseline, repn_gen)
def test_xfrm_atleast_nested(self): m = _generate_boolean_model(4) m.p = LogicalConstraint(expr=atleast( 1, atleast(2, m.Y[1], m.Y[1].lor(m.Y[2]), m.Y[2]).lor(m.Y[3]), m.Y[4])) TransformationFactory('core.logical_to_linear').apply_to(m) Y_aug = m.logic_to_linear.augmented_vars self.assertEqual(len(Y_aug), 3) _constrs_contained_within( self, [(1, Y_aug[1].get_associated_binary() + m.Y[4].get_associated_binary(), None), (1, 1 - Y_aug[2].get_associated_binary() + Y_aug[1].get_associated_binary(), None), (1, 1 - m.Y[3].get_associated_binary() + Y_aug[1].get_associated_binary(), None), (1, Y_aug[2].get_associated_binary() + m.Y[3].get_associated_binary() + 1 - Y_aug[1].get_associated_binary(), None), (1, 1 - m.Y[1].get_associated_binary() + Y_aug[3].get_associated_binary(), None), (1, 1 - m.Y[2].get_associated_binary() + Y_aug[3].get_associated_binary(), None), (1, m.Y[1].get_associated_binary() + m.Y[2].get_associated_binary() + 1 - Y_aug[3].get_associated_binary(), None), (None, 2 - 2 * (1 - Y_aug[2].get_associated_binary()) - (m.Y[1].get_associated_binary() + Y_aug[3].get_associated_binary() + m.Y[2].get_associated_binary()), 0), (None, m.Y[1].get_associated_binary() + Y_aug[3].get_associated_binary() + m.Y[2].get_associated_binary() - (1 + 2 * Y_aug[2].get_associated_binary()), 0)], m.logic_to_linear.transformed_constraints)
def test_cuts_are_correct_facets_fme(self): m = models.makeTwoTermDisj_boxes() TransformationFactory('gdp.cuttingplane').apply_to( m, create_cuts=create_cuts_fme, post_process_cut=None, zero_tolerance=0) # This would also be a valid cut, it just doesn't happen to be what we # choose. # facet_extreme_pts = [ # (1,0,3,1), # (1,0,3,2), # (0,1,1,3), # (0,1,1,4) # ] facet_extreme_pts = [ (0,1,1,3), (0,1,2,3), (1,0,3,1), (1,0,4,1) ] cuts = m._pyomo_gdp_cuttingplane_transformation.cuts # Here, we get just one facet self.assertEqual(len(cuts), 1) cut = cuts[0] cut_expr = cut.body lower = cut.lower upper = cut.upper for pt in facet_extreme_pts: m.d[0].indicator_var.fix(pt[0]) m.d[1].indicator_var.fix(pt[1]) m.x.fix(pt[2]) m.y.fix(pt[3]) if lower is not None: self.assertEqual(value(lower), value(cut_expr)) if upper is not None: self.assertEqual(value(upper), value(cut_expr))
def test_disc_multi_index2(self): m = self.m.clone() m.t2 = ContinuousSet(bounds=(0, 5)) m.v2 = Var(m.t, m.t2) m.dv2dt = DerivativeVar(m.v2, wrt=m.t) m.dv2dt2 = DerivativeVar(m.v2, wrt=m.t2) disc = TransformationFactory('dae.finite_difference') disc.apply_to(m, nfe=2) self.assertTrue(hasattr(m, 'dv2dt_disc_eq')) self.assertTrue(hasattr(m, 'dv2dt2_disc_eq')) self.assertEqual(len(m.dv2dt_disc_eq), 6) self.assertEqual(len(m.dv2dt2_disc_eq), 6) self.assertEqual(len(m.v2), 9) expected_t_disc_points = [0, 5.0, 10] expected_t2_disc_points = [0, 2.5, 5] for idx, val in enumerate(list(m.t)): self.assertAlmostEqual(val, expected_t_disc_points[idx]) for idx, val in enumerate(list(m.t2)): self.assertAlmostEqual(val, expected_t2_disc_points[idx])
def build(self): # Call UnitModel.build to setup dynamics super(HydrogenTurbineData, self).build() self.compressor = Compressor( default={"property_package": self.config.property_package}) self.stoic_reactor = StoichiometricReactor( default={ "property_package": self.config.property_package, "reaction_package": self.config.reaction_package, "has_heat_of_reaction": True, "has_heat_transfer": False, "has_pressure_change": False }) self.turbine = Turbine( default={"property_package": self.config.property_package}) # Declare var for reactor conversion self.stoic_reactor.conversion = Var(initialize=0.75, bounds=(0, 1)) self.stoic_reactor.conv_constraint = Constraint( expr=self.stoic_reactor.conversion * self.stoic_reactor.inlet.mole_frac_comp[0, "hydrogen"] == ( self.stoic_reactor.inlet.mole_frac_comp[0, "hydrogen"] - self.stoic_reactor.outlet.mole_frac_comp[0, "hydrogen"])) # Connect arcs self.comp_to_reactor = Arc(source=self.compressor.outlet, destination=self.stoic_reactor.inlet) self.reactor_to_turbine = Arc(source=self.stoic_reactor.outlet, destination=self.turbine.inlet) TransformationFactory("network.expand_arcs").apply_to(self)
def solve_flowsheet(**desal_kwargs): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) build(m, **desal_kwargs) TransformationFactory("network.expand_arcs").apply_to(m) # scale scale(m, **desal_kwargs) calculate_scaling_factors(m) # initialize m.fs.feed.initialize() propagate_state(m.fs.s_pretrt_tb) initialize(m, **desal_kwargs) check_dof(m) solve_block(m, tee=False, fail_flag=True) # report print("===================================" "\n Simulation ") report(m, **desal_kwargs) return m
def test_relax_integrality1(self): # Coverage of the _clear_attribute method self.model.A = RangeSet(1,4) self.model.a = Var() self.model.b = Var(within=self.model.A) self.model.c = Var(within=NonNegativeIntegers) self.model.d = Var(within=Integers, bounds=(-2,3)) self.model.e = Var(within=Boolean) self.model.f = Var(domain=Boolean) instance=self.model.create_instance() xfrm = TransformationFactory('core.relax_integer_vars') rinst = xfrm.create_using(instance) self.assertEqual(type(rinst.a.domain), RealSet) self.assertEqual(type(rinst.b.domain), RealSet) self.assertEqual(type(rinst.c.domain), RealSet) self.assertEqual(type(rinst.d.domain), RealSet) self.assertEqual(type(rinst.e.domain), RealSet) self.assertEqual(type(rinst.f.domain), RealSet) self.assertEqual(rinst.a.bounds, instance.a.bounds) self.assertEqual(rinst.b.bounds, instance.b.bounds) self.assertEqual(rinst.c.bounds, instance.c.bounds) self.assertEqual(rinst.d.bounds, instance.d.bounds) self.assertEqual(rinst.e.bounds, instance.e.bounds) self.assertEqual(rinst.f.bounds, instance.f.bounds)
def test_mgv1(self): from lms2 import MainGridV1 from pyomo.environ import AbstractModel, TransformationFactory, Param, Var from pyomo.dae import ContinuousSet from pyomo.network import Port m = AbstractModel() m.time = ContinuousSet(bounds=(0, 10)) m.mg = MainGridV1() data_main_grid_v1 = { 'time': { None: [0, 2] }, 'pmax': { None: +100.0 }, 'pmin': { None: -100.0 }, 'cost_in': { None: 0.15 }, 'cost_out': { None: 0.15 } } data = {None: {'time': {None: [0, 10]}, 'mg': data_main_grid_v1}} inst = m.create_instance(data) TransformationFactory('dae.finite_difference').apply_to(inst, nfe=2) self.assertTrue(hasattr(m.mg, 'outlet')) self.assertIsInstance(m.mg.outlet, Port)
def test_relax_integrality2(self): # Coverage of the _clear_attribute method self.model.A = RangeSet(1,4) self.model.a = Var([1,2,3], dense=True) self.model.b = Var([1,2,3], within=self.model.A, dense=True) self.model.c = Var([1,2,3], within=NonNegativeIntegers, dense=True) self.model.d = Var([1,2,3], within=Integers, bounds=(-2,3), dense=True) self.model.e = Var([1,2,3], within=Boolean, dense=True) self.model.f = Var([1,2,3], domain=Boolean, dense=True) instance=self.model.create_instance() xfrm = TransformationFactory('core.relax_integer_vars') rinst = xfrm.create_using(instance) self.assertEqual(type(rinst.a[1].domain), RealSet) self.assertEqual(type(rinst.b[1].domain), RealSet) self.assertEqual(type(rinst.c[1].domain), RealSet) self.assertEqual(type(rinst.d[1].domain), RealSet) self.assertEqual(type(rinst.e[1].domain), RealSet) self.assertEqual(type(rinst.f[1].domain), RealSet) self.assertEqual(rinst.a[1].bounds, instance.a[1].bounds) self.assertEqual(rinst.b[1].bounds, instance.b[1].bounds) self.assertEqual(rinst.c[1].bounds, instance.c[1].bounds) self.assertEqual(rinst.d[1].bounds, instance.d[1].bounds) self.assertEqual(rinst.e[1].bounds, instance.e[1].bounds) self.assertEqual(rinst.f[1].bounds, instance.f[1].bounds)
def test_get_stream_table_contents(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.props = PhysicalParameterTestBlock() m.fs.config.default_property_package = m.fs.props m.fs.unit1 = Heater() m.fs.unit2 = Heater() m.fs.stream = Arc(source=m.fs.unit1.outlet, destination=m.fs.unit2.inlet) TransformationFactory("network.expand_arcs").apply_to(m) df = m.fs._get_stream_table_contents() assert df.loc["pressure"]["stream"] == 1e5 assert df.loc["temperature"]["stream"] == 300 assert df.loc["component_flow_phase ('p1', 'c1')"]["stream"] == 2.0 assert df.loc["component_flow_phase ('p1', 'c2')"]["stream"] == 2.0 assert df.loc["component_flow_phase ('p2', 'c1')"]["stream"] == 2.0 assert df.loc["component_flow_phase ('p2', 'c2')"]["stream"] == 2.0 m.fs.report()
def test_zero_term_removal(self): """Test for removing zero terms from linear constraints.""" m = ConcreteModel() m.v0 = Var() m.v1 = Var() m.v2 = Var() m.v3 = Var() m.c = Constraint(expr=m.v0 == m.v1 * m.v2 + m.v3) m.c2 = Constraint(expr=m.v1 * m.v2 + m.v3 <= m.v0) m.c3 = Constraint(expr=m.v0 <= m.v1 * m.v2 + m.v3) m.c4 = Constraint(expr=EXPR.inequality(1, m.v1 * m.v2 + m.v3, 3)) m.v1.fix(0) TransformationFactory('contrib.remove_zero_terms').apply_to(m) m.v1.unfix() # Check that the term no longer exists self.assertFalse( any(id(m.v1) == id(v) for v in EXPR.identify_variables(m.c.body))) self.assertFalse( any(id(m.v1) == id(v) for v in EXPR.identify_variables(m.c2.body))) self.assertFalse( any(id(m.v1) == id(v) for v in EXPR.identify_variables(m.c3.body))) self.assertFalse( any(id(m.v1) == id(v) for v in EXPR.identify_variables(m.c4.body)))
def test_induced_linearity_case2(self): m = ConcreteModel() m.x = Var([0], bounds=(-3, 8)) m.y = Var(RangeSet(4), domain=Binary) m.z = Var(domain=Integers, bounds=(-1, 2)) m.constr = Constraint(expr=m.x[0] == m.y[1] + 2 * m.y[2] + m.y[3] + 2 * m.y[4] + m.z) m.logical = ConstraintList() m.logical.add(expr=m.y[1] + m.y[2] == 1) m.logical.add(expr=m.y[3] + m.y[4] == 1) m.logical.add(expr=m.y[2] + m.y[4] <= 1) m.b = Var(bounds=(-2, 7)) m.c = Var() m.bilinear = Constraint(expr=(m.x[0] - 3) * (m.b + 2) - (m.c + 4) * m.b + exp(m.b**2) * m.x[0] <= m.c) TransformationFactory('contrib.induced_linearity').apply_to(m) xfrmed_blk = m._induced_linearity_info.x0_b_bilinear self.assertSetEqual(set(xfrmed_blk.valid_values), set([1, 2, 3, 4, 5])) select_one_repn = generate_standard_repn( xfrmed_blk.select_one_value.body) self.assertEqual( ComponentSet(select_one_repn.linear_vars), ComponentSet(xfrmed_blk.x_active[i] for i in xfrmed_blk.valid_values))
def test_disc_invalid_options(self): m = self.m.clone() try: TransformationFactory('dae.finite_difference').apply_to(m, wrt=m.s) self.fail('Expected TypeError') except TypeError: pass try: TransformationFactory('dae.finite_difference').apply_to(m, nfe=-1) self.fail('Expected ValueError') except ValueError: pass try: TransformationFactory('dae.finite_difference').apply_to( m, scheme='foo') self.fail('Expected ValueError') except ValueError: pass TransformationFactory('dae.finite_difference').apply_to(m, wrt=m.t) try: TransformationFactory('dae.finite_difference').apply_to(m, wrt=m.t) self.fail('Expected ValueError') except ValueError: pass m = self.m.clone() disc = TransformationFactory('dae.finite_difference') disc.apply_to(m) try: disc.apply_to(m) self.fail('Expected ValueError') except ValueError: pass
def main(): """ Make the flowsheet object, fix some variables, and solve the problem """ # Create a Concrete Model as the top level object m = ConcreteModel() # Add a flowsheet object to the model m.fs = FlowsheetBlock(default={"dynamic": False}) # Add property packages to flowsheet library m.fs.thermo_params = thermo_props.SaponificationParameterBlock() m.fs.reaction_params = reaction_props.SaponificationReactionParameterBlock( default={"property_package": m.fs.thermo_params}) # Create unit models m.fs.Tank1 = CSTR( default={ "property_package": m.fs.thermo_params, "reaction_package": m.fs.reaction_params, "has_equilibrium_reactions": False, "has_heat_of_reaction": True, "has_heat_transfer": True, "has_pressure_change": False }) m.fs.Tank2 = CSTR( default={ "property_package": m.fs.thermo_params, "reaction_package": m.fs.reaction_params, "has_equilibrium_reactions": False, "has_heat_of_reaction": True, "has_heat_transfer": True, "has_pressure_change": False }) # Make Streams to connect units m.fs.stream = Arc(source=m.fs.Tank1.outlet, destination=m.fs.Tank2.inlet) TransformationFactory("network.expand_arcs").apply_to(m) # Set inlet and operating conditions, and some initial conditions. m.fs.Tank1.inlet.flow_vol[0].fix(1.0) m.fs.Tank1.inlet.conc_mol_comp[0, "H2O"].fix(55388.0) m.fs.Tank1.inlet.conc_mol_comp[0, "NaOH"].fix(100.0) m.fs.Tank1.inlet.conc_mol_comp[0, "EthylAcetate"].fix(100.0) m.fs.Tank1.inlet.conc_mol_comp[0, "SodiumAcetate"].fix(0.0) m.fs.Tank1.inlet.conc_mol_comp[0, "Ethanol"].fix(0.0) m.fs.Tank1.inlet.temperature.fix(303.15) m.fs.Tank1.inlet.pressure.fix(101325.0) m.fs.Tank1.volume.fix(1.0) m.fs.Tank1.heat_duty.fix(0.0) m.fs.Tank2.volume.fix(1.0) m.fs.Tank2.heat_duty.fix(0.0) # Initialize Units m.fs.Tank1.initialize() m.fs.Tank2.initialize( state_args={ "flow_vol": 1.0, "conc_mol_comp": { "H2O": 55388.0, "NaOH": 100.0, "EthylAcetate": 100.0, "SodiumAcetate": 0.0, "Ethanol": 0.0 }, "temperature": 303.15, "pressure": 101325.0 }) # Create a solver solver = SolverFactory('ipopt') results = solver.solve(m, tee=False) # Print results print(results) print() print("Results") print() print("Tank 1 Outlet") m.fs.Tank1.outlet.display() print() print("Tank 2 Outlet") m.fs.Tank2.outlet.display() # For testing purposes return (m, results)
def build(number_of_stages=2): # ---building model--- m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = props.NaClParameterBlock() m.fs.costing = WaterTAPCosting() m.fs.NumberOfStages = Param(initialize=number_of_stages) m.fs.StageSet = RangeSet(m.fs.NumberOfStages) m.fs.LSRRO_StageSet = RangeSet(2, m.fs.NumberOfStages) m.fs.NonFinal_StageSet = RangeSet(m.fs.NumberOfStages-1) m.fs.feed = Feed(default={'property_package': m.fs.properties}) m.fs.product = Product(default={'property_package': m.fs.properties}) m.fs.disposal = Product(default={'property_package': m.fs.properties}) # Add the mixers m.fs.Mixers = Mixer(m.fs.NonFinal_StageSet, default={ "property_package": m.fs.properties, "momentum_mixing_type": MomentumMixingType.equality, # booster pump will match pressure "inlet_list": ['upstream', 'downstream']}) total_pump_work = 0 # Add the pumps m.fs.PrimaryPumps = Pump(m.fs.StageSet, default={"property_package": m.fs.properties}) for pump in m.fs.PrimaryPumps.values(): pump.costing = UnitModelCostingBlock(default={ "flowsheet_costing_block":m.fs.costing}) m.fs.costing.cost_flow(pyunits.convert(pump.work_mechanical[0], to_units=pyunits.kW), "electricity") # Add the equalizer pumps m.fs.BoosterPumps = Pump(m.fs.LSRRO_StageSet, default={"property_package": m.fs.properties}) for pump in m.fs.BoosterPumps.values(): pump.costing = UnitModelCostingBlock(default={ "flowsheet_costing_block":m.fs.costing}) m.fs.costing.cost_flow(pyunits.convert(pump.work_mechanical[0], to_units=pyunits.kW), "electricity") # Add the stages ROs m.fs.ROUnits = ReverseOsmosis0D(m.fs.StageSet, default={ "property_package": m.fs.properties, "has_pressure_change": True, "pressure_change_type": PressureChangeType.calculated, "mass_transfer_coefficient": MassTransferCoefficient.calculated, "concentration_polarization_type": ConcentrationPolarizationType.calculated}) for ro_unit in m.fs.ROUnits.values(): ro_unit.costing = UnitModelCostingBlock(default={ "flowsheet_costing_block":m.fs.costing}) # Add EnergyRecoveryDevice m.fs.EnergyRecoveryDevice = Pump(default={"property_package": m.fs.properties}) m.fs.EnergyRecoveryDevice.costing = UnitModelCostingBlock(default={ "flowsheet_costing_block":m.fs.costing, "costing_method_arguments":{"pump_type":PumpType.energy_recovery_device}}) m.fs.costing.cost_flow(pyunits.convert(m.fs.EnergyRecoveryDevice.work_mechanical[0], to_units=pyunits.kW), "electricity") # additional variables or expressions # system water recovery m.fs.water_recovery = Var( initialize=0.5, bounds=(0, 1), domain=NonNegativeReals, units=pyunits.dimensionless, doc='System Water Recovery') m.fs.eq_water_recovery = Constraint(expr=\ sum(m.fs.feed.flow_mass_phase_comp[0,'Liq',:]) * m.fs.water_recovery == \ sum(m.fs.product.flow_mass_phase_comp[0,'Liq',:]) ) # costing m.fs.costing.cost_process() product_flow_vol_total = m.fs.product.properties[0].flow_vol m.fs.costing.add_LCOW(product_flow_vol_total) m.fs.costing.add_specific_energy_consumption(product_flow_vol_total) # objective m.fs.objective = Objective(expr=m.fs.costing.LCOW) # connections # Connect the feed to the first pump m.fs.feed_to_pump = Arc(source=m.fs.feed.outlet, destination=m.fs.PrimaryPumps[1].inlet) # Connect the primary RO permeate to the product m.fs.primary_RO_to_product = Arc(source=m.fs.ROUnits[1].permeate, destination=m.fs.product.inlet) # Connect the Pump n to the Mixer n m.fs.pump_to_mixer = Arc(m.fs.NonFinal_StageSet, rule=lambda fs,n : {'source':fs.PrimaryPumps[n].outlet, 'destination':fs.Mixers[n].upstream}) # Connect the Mixer n to the Stage n m.fs.mixer_to_stage = Arc(m.fs.NonFinal_StageSet, rule=lambda fs,n : {'source':fs.Mixers[n].outlet, 'destination':fs.ROUnits[n].inlet}) # Connect the Stage n to the Pump n+1 m.fs.stage_to_pump = Arc(m.fs.NonFinal_StageSet, rule=lambda fs,n : {'source':fs.ROUnits[n].retentate, 'destination':fs.PrimaryPumps[n+1].inlet}) # Connect the Stage n to the Eq Pump n m.fs.stage_to_eq_pump = Arc(m.fs.LSRRO_StageSet, rule=lambda fs,n : {'source':fs.ROUnits[n].permeate, 'destination':fs.BoosterPumps[n].inlet}) # Connect the Eq Pump n to the Mixer n-1 m.fs.eq_pump_to_mixer = Arc(m.fs.LSRRO_StageSet, rule=lambda fs,n : {'source':fs.BoosterPumps[n].outlet, 'destination':fs.Mixers[n-1].downstream}) # Connect the Pump N to the Stage N last_stage = m.fs.StageSet.last() m.fs.pump_to_stage = Arc(source=m.fs.PrimaryPumps[last_stage].outlet, destination=m.fs.ROUnits[last_stage].inlet) # Connect Final Stage to EnergyRecoveryDevice Pump m.fs.stage_to_erd = Arc(source=m.fs.ROUnits[last_stage].retentate, destination=m.fs.EnergyRecoveryDevice.inlet) # Connect the EnergyRecoveryDevice to the disposal m.fs.erd_to_disposal = Arc(source=m.fs.EnergyRecoveryDevice.outlet, destination=m.fs.disposal.inlet) # additional bounding for b in m.component_data_objects(Block, descend_into=True): # NaCl solubility limit if hasattr(b, 'mass_frac_phase_comp'): b.mass_frac_phase_comp['Liq', 'NaCl'].setub(0.26) TransformationFactory("network.expand_arcs").apply_to(m) return m
m.use4implies6or7 = LogicalConstraint( expr=m.Y[4].implies(lor(m.Y[6], m.Y[7]))) m.use3implies8 = LogicalConstraint(expr=m.Y[3].implies(m.Y[8])) m.use6or7implies4 = LogicalConstraint( expr=lor(m.Y[6], m.Y[7]).implies(m.Y[4])) m.use6or7 = LogicalConstraint(expr=m.Y[6].xor(m.Y[7])) """Profit (objective) function definition""" m.profit = Objective(expr=sum(m.yCF[unit] for unit in m.units) + sum(m.flow[stream] * CV[stream] for stream in m.streams) + CONSTANT, sense=minimize) """Bound definitions""" # x (flow) upper bounds x_ubs = {3: 2, 5: 2, 9: 2, 10: 1, 14: 1, 17: 2, 19: 2, 21: 2, 25: 3} for i, x_ub in x_ubs.item(): m.flow[i].setub(x_ub) # Optimal solution uses units 2, 4, 6, 8 with objective value 68. return m if __name__ == "__main__": m = build_eight_process_flowsheet() from pyomo.environ import TransformationFactory TransformationFactory('core.logical_to_linear').apply_to(m) SolverFactory('gdpopt').solve(m, tee=True) update_boolean_vars_from_binary(m) m.Y.display() m.flow.display()
def test_initialize_by_time_element(): horizon = 6 time_set = [0, horizon] ntfe = 60 # For a finite element every six seconds ntcp = 2 m = ConcreteModel(name='CSTR model for testing') m.fs = FlowsheetBlock(default={ 'dynamic': True, 'time_set': time_set, 'time_units': pyunits.minute }) m.fs.properties = AqueousEnzymeParameterBlock() m.fs.reactions = EnzymeReactionParameterBlock( default={'property_package': m.fs.properties}) m.fs.cstr = CSTR( default={ "property_package": m.fs.properties, "reaction_package": m.fs.reactions, "material_balance_type": MaterialBalanceType.componentTotal, "energy_balance_type": EnergyBalanceType.enthalpyTotal, "momentum_balance_type": MomentumBalanceType.none, "has_heat_of_reaction": True }) # Time discretization disc = TransformationFactory('dae.collocation') disc.apply_to(m, wrt=m.fs.time, nfe=ntfe, ncp=ntcp, scheme='LAGRANGE-RADAU') # Fix geometry variables m.fs.cstr.volume[0].fix(1.0) # Fix initial conditions: for p, j in m.fs.properties.phase_list * m.fs.properties.component_list: if j == 'Solvent': continue m.fs.cstr.control_volume.material_holdup[0, p, j].fix(0) # Fix inlet conditions # This is a huge hack because I didn't know that the proper way to # have multiple inlets to a CSTR was to use a mixer. # I 'combine' both my inlet streams before sending them to the CSTR. for t, j in m.fs.time * m.fs.properties.component_list: if t <= 2: if j == 'E': m.fs.cstr.inlet.conc_mol[t, j].fix(11.91 * 0.1 / 2.2) elif j == 'S': m.fs.cstr.inlet.conc_mol[t, j].fix(12.92 * 2.1 / 2.2) elif j != 'Solvent': m.fs.cstr.inlet.conc_mol[t, j].fix(0) elif t <= 4: if j == 'E': m.fs.cstr.inlet.conc_mol[t, j].fix(5.95 * 0.1 / 2.2) elif j == 'S': m.fs.cstr.inlet.conc_mol[t, j].fix(12.92 * 2.1 / 2.2) elif j != 'Solvent': m.fs.cstr.inlet.conc_mol[t, j].fix(0) else: if j == 'E': m.fs.cstr.inlet.conc_mol[t, j].fix(8.95 * 0.1 / 2.2) elif j == 'S': m.fs.cstr.inlet.conc_mol[t, j].fix(16.75 * 2.1 / 2.2) elif j != 'Solvent': m.fs.cstr.inlet.conc_mol[t, j].fix(0) m.fs.cstr.inlet.conc_mol[:, 'Solvent'].fix(1.) m.fs.cstr.inlet.flow_vol.fix(2.2) m.fs.cstr.inlet.temperature.fix(300) # Fix outlet conditions m.fs.cstr.outlet.flow_vol.fix(2.2) m.fs.cstr.outlet.temperature[m.fs.time.first()].fix(300) assert degrees_of_freedom(m) == 0 initialize_by_time_element(m.fs, m.fs.time, solver=solver) assert degrees_of_freedom(m) == 0 # Assert that the result looks how we expect assert m.fs.cstr.outlet.conc_mol[0, 'S'].value == 0 assert abs(m.fs.cstr.outlet.conc_mol[2, 'S'].value - 11.389) < 1e-2 assert abs(m.fs.cstr.outlet.conc_mol[4, 'P'].value - 0.2191) < 1e-3 assert abs(m.fs.cstr.outlet.conc_mol[6, 'E'].value - 0.0327) < 1e-3 assert abs(m.fs.cstr.outlet.temperature[6].value - 289.7) < 1 # Assert that model is still fixed and deactivated as expected assert (m.fs.cstr.control_volume.material_holdup[m.fs.time.first(), 'aq', 'S'].fixed) for t in m.fs.time: if t != m.fs.time.first(): assert (not m.fs.cstr.control_volume.material_holdup[t, 'aq', 'S'].fixed) assert not m.fs.cstr.outlet.temperature[t].fixed assert ( m.fs.cstr.control_volume.material_holdup_calculation[t, 'aq', 'C'].active) assert m.fs.cstr.control_volume.properties_out[t].active assert not m.fs.cstr.outlet.conc_mol[t, 'S'].fixed assert m.fs.cstr.inlet.conc_mol[t, 'S'].fixed # Assert that constraints are feasible after initialization for con in m.fs.component_data_objects(Constraint, active=True): assert value(con.body) - value(con.upper) < 1e-5 assert value(con.lower) - value(con.body) < 1e-5 results = solver.solve(m.fs) assert check_optimal_termination(results)
def test_ConstraintDatatarget_target_transformed_create_using(self): m = self.makeModel() m2 = TransformationFactory('core.add_slack_variables').create_using( m, targets=[m.rule1[2]]) self.checkTransformedRule1(m2, 2)
def test_ConstraintDatatarget_target_transformed(self): m = self.makeModel() TransformationFactory('core.add_slack_variables').apply_to( m, targets=[m.rule1[2]]) self.checkTransformedRule1(m, 2)
def test_trans_block_name_collision(self): m = self.makeModel() m._core_add_slack_variables = Block() TransformationFactory('core.add_slack_variables').apply_to(m) xblock = m.component("_core_add_slack_variables_4") self.assertIsInstance(xblock, Block)
def test_indexedtarget_nontarget_same_create_using(self): m = self.makeModel() m2 = TransformationFactory('core.add_slack_variables').create_using( m, targets=[m.rule1]) self.checkRule2(m2)