def test_update_contset_indexed_component_block_single2(self): model = ConcreteModel() model.t = ContinuousSet(bounds=(0, 10)) def _block_rule(_b_, t): m = _b_.model() b = Block() b.s1 = Set(initialize=['A1', 'A2', 'A3']) def _init(m, j): return j * 2 b.p1 = Param(m.t, default=_init) b.v1 = Var(m.t, initialize=5) b.v2 = Var(m.t, initialize=2) b.v3 = Var(m.t, b.s1, initialize=1) def _con1(_b, ti): return _b.v1[ti] * _b.p1[ti] == _b.v1[t]**2 b.con1 = Constraint(m.t, rule=_con1) def _con2(_b, i, ti): return _b.v2[ti] - _b.v3[ti, i] + _b.p1[ti] b.con2 = Expression(b.s1, m.t, rule=_con2) return b model.blk = Block(model.t, rule=_block_rule) expansion_map = ComponentMap() self.assertTrue(len(model.blk), 2) generate_finite_elements(model.t, 5) missing_idx = set(model.blk.index_set()) - set(model.blk._data.keys()) model.blk._dae_missing_idx = missing_idx update_contset_indexed_component(model.blk, expansion_map) self.assertEqual(len(model.blk), 6) self.assertEqual(len(model.blk[10].con1), 2) self.assertEqual(len(model.blk[2].con1), 6) self.assertEqual(len(model.blk[10].v2), 2) self.assertEqual(model.blk[2].p1[2], 4) self.assertEqual(model.blk[8].p1[6], 12) self.assertEqual(model.blk[4].con1[4](), 15) self.assertEqual(model.blk[6].con1[8](), 55) self.assertEqual(model.blk[0].con2['A1', 10](), 21) self.assertEqual(model.blk[4].con2['A2', 6](), 13)
def test_non_supported_single_index(self): # Can't simulate a model with no ContinuousSet m = ConcreteModel() with self.assertRaises(DAE_Error): Simulator(m) # Can't simulate a model with multiple ContinuousSets m = ConcreteModel() m.s = ContinuousSet(bounds=(0, 10)) m.t = ContinuousSet(bounds=(0, 5)) with self.assertRaises(DAE_Error): Simulator(m) # Can't simulate a model with no Derivatives m = ConcreteModel() m.t = ContinuousSet(bounds=(0, 10)) with self.assertRaises(DAE_Error): Simulator(m) # Can't simulate a model with multiple RHS for a derivative m = self.m def _diffeq(m, t): return m.dv[t] == m.v[t]**2 + m.v[t] m.con1 = Constraint(m.t, rule=_diffeq) m.con2 = Constraint(m.t, rule=_diffeq) with self.assertRaises(DAE_Error): Simulator(m) m.del_component('con1') m.del_component('con2') # Can't simulate a model with multiple derivatives in an # equation m = self.m def _diffeq(m, t): return m.dv[t] == m.dv[t] + m.v[t]**2 m.con1 = Constraint(m.t, rule=_diffeq) with self.assertRaises(DAE_Error): Simulator(m) m.del_component('con1')
def test_invalid_derivative(self): m = ConcreteModel() m.t = ContinuousSet(bounds=(0, 10)) m.v = Var(m.t) m.dv = DerivativeVar(m.v, wrt=(m.t, m.t, m.t)) try: TransformationFactory('dae.collocation').apply_to(m) self.fail('Expected DAE_Error') except DAE_Error: pass
def testtime_units_external(self): # Should ignore time set m = ConcreteModel() m.s = ContinuousSet(initialize=[4, 5]) m.fs = FlowsheetBlock(default={ "dynamic": True, "time": m.s, "time_units": units.s }) assert m.fs.time_units is units.s
def test_set_changed(self): model = ConcreteModel() model.t = ContinuousSet(initialize=[1, 2, 3]) self.assertFalse(model.t._changed) model.t.set_changed(True) self.assertTrue(model.t._changed) model.t.set_changed(False) self.assertFalse(model.t._changed) with self.assertRaises(ValueError): model.t.set_changed(3)
def test_get_lower_element_boundary(self): m = ConcreteModel() m.t = ContinuousSet(initialize=[1, 2, 3]) self.assertEqual(m.t.get_lower_element_boundary(1.5), 1) self.assertEqual(m.t.get_lower_element_boundary(2.5), 2) self.assertEqual(m.t.get_lower_element_boundary(2), 2) log_out = StringIO() with LoggingIntercept(log_out, 'pyomo.dae'): temp = m.t.get_lower_element_boundary(0.5) self.assertIn('Returning the lower bound', log_out.getvalue())
def test_update_contset_indexed_component_unsupported_single(self): m = ConcreteModel() m.t = ContinuousSet(bounds=(0, 10)) m.s = Set(m.t) generate_finite_elements(m.t, 5) expansion_map = ComponentMap() # Expected TypeError because Set is not a component that supports # indexing by a ContinuousSet with self.assertRaises(TypeError): update_contset_indexed_component(m.s, expansion_map)
def m(): m = ConcreteModel() m.s = Set(initialize=["a", "b"]) m.cs = ContinuousSet(bounds=(0, 1)) m.v = Var(m.cs, initialize=1) m.dv = DerivativeVar(m.v) m.discretizer = TransformationFactory("dae.finite_difference") m.discretizer.apply_to(m, nfe=10, wrt=m.cs, scheme="BACKWARD") m.e = Expression(expr=m.v[1]) m.b1 = Block() m.b1.v1 = Var(initialize=1) m.b1.v2 = Var(m.s, initialize=1) m.b1.v1.fix(1) m.b1.c1 = Constraint(expr=1 == m.b1.v1) m.b1.c2 = Constraint(expr=1 <= m.b1.v1) m.b1.sb = Block() m.b1.sb.v1 = Var(initialize=1) m.b1.sb.v2 = Var(m.s, initialize=1) m.b1.sb.v1.fix(1) m.b1.sb.e1 = Expression(expr=m.b1.sb.v1) m.b1.sb.o1 = Objective(expr=1 <= m.b1.sb.v1) m.b1.sb.o2 = Objective(expr=1 <= m.b1.sb.v1) m.b1.sb.o2.deactivate() m.b1.sb.c1 = Constraint(expr=1 == m.b1.sb.v1) m.b1.sb.c2 = Constraint(expr=1 >= m.b1.sb.v1) m.b1.deactivate() m.b2 = Block(m.s) for i in m.s: m.b2[i].v1 = Var(initialize=1) m.b2[i].v2 = Var(m.s, initialize=1) m.b2[i].v1.fix(1) m.b2[i].e1 = Expression(expr=m.b2[i].v1) m.b2[i].c1 = Constraint(expr=2 == m.b2[i].v1) m.b2[i].c2 = Constraint(expr=2 <= m.b2[i].v1) if i == "a": m.b2[i].o1 = Objective(expr=1 <= m.b2[i].v1) m.b2[i].o2 = Objective(expr=1 <= m.b2[i].v1) m.b2[i].o2.deactivate() m.b2[i].c1.deactivate() m.b2[i].c2.deactivate() return m
def test_setup_dynamics_sub_dynamic_external(): m = ConcreteModel() m.s = ContinuousSet(initialize=[4, 5]) m.fs = Flowsheet(default={"dynamic": True}) m.fs._setup_dynamics() m.fs.sub = Flowsheet(default={"dynamic": True, "time": m.s}) m.fs.sub._setup_dynamics() assert m.fs.sub.config.dynamic is True assert m.fs.sub.config.time is m.s
def test_dynamic_external_time_and_time_set(self): # Should ignore time set m = ConcreteModel() m.s = ContinuousSet(initialize=[4, 5]) m.fs = FlowsheetBlock(default={ "dynamic": True, "time": m.s, "time_set": [1, 2]}) assert m.fs.config.dynamic is True assert m.fs.config.time is m.s assert not hasattr(m.fs, "time")
def test_update_contset_indexed_component_block_multiple(self): model = ConcreteModel() model.t = ContinuousSet(bounds=(0, 10)) model.s1 = Set(initialize=['A', 'B', 'C']) model.s2 = Set(initialize=[('x1', 'x1'), ('x2', 'x2')]) def _block_rule(b, t, s1): m = b.model() def _init(m, i, j): return j * 2 b.p1 = Param(m.s1, m.t, mutable=True, default=_init) b.v1 = Var(m.s1, m.t, initialize=5) b.v2 = Var(m.s2, m.t, initialize=2) b.v3 = Var(m.t, m.s2, initialize=1) def _con1(_b, si, ti): return _b.v1[si, ti] * _b.p1[si, ti] == _b.v1[si, t]**2 b.con1 = Constraint(m.s1, m.t, rule=_con1) def _con2(_b, i, j, ti): return _b.v2[i, j, ti] - _b.v3[ti, i, j] + _b.p1['A', ti] b.con2 = Expression(m.s2, m.t, rule=_con2) model.blk = Block(model.t, model.s1, rule=_block_rule) expansion_map = ComponentMap() self.assertTrue(len(model.blk), 6) generate_finite_elements(model.t, 5) missing_idx = set(model.blk._index) - set(iterkeys(model.blk._data)) model.blk._dae_missing_idx = missing_idx update_contset_indexed_component(model.blk, expansion_map) self.assertEqual(len(model.blk), 18) self.assertEqual(len(model.blk[10, 'C'].con1), 6) self.assertEqual(len(model.blk[2, 'B'].con1), 18) self.assertEqual(len(model.blk[10, 'C'].v2), 4) self.assertEqual(model.blk[2, 'A'].p1['A', 2], 4) self.assertEqual(model.blk[8, 'C'].p1['B', 6], 12) self.assertEqual(model.blk[4, 'B'].con1['B', 4](), 15) self.assertEqual(model.blk[6, 'A'].con1['C', 8](), 55) self.assertEqual(model.blk[0, 'A'].con2['x1', 'x1', 10](), 21) self.assertEqual(model.blk[4, 'C'].con2['x2', 'x2', 6](), 13)
def test_duplicate_construct(self): m = ConcreteModel() m.t = ContinuousSet(initialize=[1,2,3]) self.assertEqual(m.t, [1,2,3]) self.assertEqual(m.t._fe, [1,2,3]) m.t.add(1.5) m.t.add(2.5) self.assertEqual(m.t, [1,1.5,2,2.5,3]) self.assertEqual(m.t._fe, [1,2,3]) m.t.construct() self.assertEqual(m.t, [1,1.5,2,2.5,3]) self.assertEqual(m.t._fe, [1,2,3])
def test_io6(self): OUTPUT = open("diffset.dat", "w") OUTPUT.write("data;\n") OUTPUT.write("set B := 1;\n") OUTPUT.write("end;\n") OUTPUT.close() # Expected ValueError because data set has only one value and no # bounds are specified self.model.B = ContinuousSet() with self.assertRaises(ValueError): self.instance = self.model.create_instance("diffset.dat")
def test_dynamic_external_time(self): m = ConcreteModel() m.s = ContinuousSet(initialize=[4, 5]) m.fs = FlowsheetBlock(default={"dynamic": True, "time_units": units.s}) m.fs.sub = FlowsheetBlock(default={ "dynamic": True, "time": m.s, "time_units": units.minute }) assert m.fs.sub.config.dynamic is True assert m.fs.sub.config.time is m.s assert m.fs.sub.time_units == units.minute
def test_io6(self): OUTPUT = open("diffset.dat", "w") OUTPUT.write("data;\n") OUTPUT.write("set B := 1;\n") OUTPUT.write("end;\n") OUTPUT.close() self.model.B = ContinuousSet() try: self.instance = self.model.create_instance("diffset.dat") self.fail("Expected ValueError because data set has only one value" " and no bounds are specified") except ValueError: pass
def test_number_derivative_variables(): m = ConcreteModel() m.cs = ContinuousSet(bounds=(0, 1)) m.v = Var(m.cs, initialize=1) m.dv = DerivativeVar(m.v) assert number_derivative_variables(m) == 2 m.discretizer = TransformationFactory("dae.finite_difference") m.discretizer.apply_to(m, nfe=10, wrt=m.cs, scheme="BACKWARD") assert number_derivative_variables(m) == 0
def test_set_changed(self): model = ConcreteModel() model.t = ContinuousSet(initialize=[1, 2, 3]) self.assertFalse(model.t._changed) model.t.set_changed(True) self.assertTrue(model.t._changed) model.t.set_changed(False) self.assertFalse(model.t._changed) try: model.t.set_changed(3) self.fail("Expected a ValueError") except ValueError: pass
def test_2dim_set(self): m = ConcreteModel() m.time = ContinuousSet(bounds=(0, 1)) m.v = Var(m.time, [('a', 1), ('b', 2)]) scalar, dae = flatten_dae_variables(m, m.time) self.assertEqual(len(scalar), 0) ref_data = { self._hashRef(Reference(m.v[:, 'a', 1])), self._hashRef(Reference(m.v[:, 'b', 2])), } self.assertEqual(len(dae), len(ref_data)) for ref in dae: self.assertIn(self._hashRef(ref), ref_data)
def test_assert_units_consistent_all_components(self): # test all scalar components consistent u = units m = self._create_model_and_vars() m.obj = Objective(expr=m.dx / m.t - m.vx) m.con = Constraint(expr=m.dx / m.t == m.vx) # vars already added m.exp = Expression(expr=m.dx / m.t - m.vx) m.suff = Suffix(direction=Suffix.LOCAL) # params already added # sets already added m.rs = RangeSet(5) m.disj1 = Disjunct() m.disj1.constraint = Constraint(expr=m.dx / m.t <= m.vx) m.disj2 = Disjunct() m.disj2.constraint = Constraint(expr=m.dx / m.t <= m.vx) m.disjn = Disjunction(expr=[m.disj1, m.disj2]) # block tested as part of model m.extfn = ExternalFunction(python_callback_function, units=u.m / u.s, arg_units=[u.m, u.s]) m.conext = Constraint(expr=m.extfn(m.dx, m.t) - m.vx == 0) m.cset = ContinuousSet(bounds=(0, 1)) m.svar = Var(m.cset, units=u.m) m.dvar = DerivativeVar(sVar=m.svar, units=u.m / u.s) def prt1_rule(m): return {'avar': m.dx} def prt2_rule(m): return {'avar': m.dy} m.prt1 = Port(rule=prt1_rule) m.prt2 = Port(rule=prt2_rule) def arcrule(m): return dict(source=m.prt1, destination=m.prt2) m.arc = Arc(rule=arcrule) # complementarities do not work yet # The expression system removes the u.m since it is multiplied by zero. # We need to change the units_container to allow 0 when comparing units # m.compl = Complementarity(expr=complements(m.dx/m.t >= m.vx, m.dx == 0*u.m)) assert_units_consistent(m)
def test_valid_declaration(self): model = ConcreteModel() model.t = ContinuousSet(bounds=(0, 1)) self.assertEqual(len(model.t), 2) self.assertIn(0, model.t) self.assertIn(1, model.t) model = ConcreteModel() model.t = ContinuousSet(initialize=[1, 2, 3]) self.assertEqual(len(model.t), 3) self.assertEqual(model.t.first(), 1) self.assertEqual(model.t.last(), 3) model = ConcreteModel() model.t = ContinuousSet(bounds=(1, 3), initialize=[1, 2, 3]) self.assertEqual(len(model.t), 3) self.assertEqual(model.t.first(), 1) self.assertEqual(model.t.last(), 3) model = ConcreteModel() model.t = ContinuousSet(bounds=(0, 4), initialize=[1, 2, 3]) self.assertEqual(len(model.t), 5) self.assertEqual(model.t.first(), 0) self.assertEqual(model.t.last(), 4) model = ConcreteModel() with self.assertRaisesRegex( ValueError, r"value is not in the domain \[0..4\]"): model.t = ContinuousSet(bounds=(0, 4), initialize=[1, 2, 3, 5]) # self.assertEqual(len(model.t), 5) # self.assertEqual(model.t.first(), 0) # self.assertEqual(model.t.last(), 5) # self.assertNotIn(4, model.t) # del model.t model = ConcreteModel() with self.assertRaisesRegex( ValueError, r"value is not in the domain \[2..6\]"): model.t = ContinuousSet(bounds=(2, 6), initialize=[1, 2, 3, 5]) # self.assertEqual(len(model.t), 5) # self.assertEqual(model.t.first(), 1) # self.assertEqual(model.t.last(), 6) # del model.t model = ConcreteModel() with self.assertRaisesRegex( ValueError, r"value is not in the domain \[2..4\]"): model.t = ContinuousSet(bounds=(2, 4), initialize=[1, 3, 5])
def test_bad_arg(self): m = ConcreteModel() m.t = ContinuousSet(bounds=(0, 1)) m.a = Param(initialize=1, mutable=True) m.b = Param(initialize=2, mutable=True) m.c = Param(initialize=3, mutable=False) m.x = Var(m.t) list_one = [m.a, m.b] list_two = [m.a, m.b, m.c] list_three = [m.a, m.x] list_four = [m.a, m.c] #verify ValueError thrown when param and perturb list are different # lengths try: Result = sipopt(m, list_one, list_two) self.fail("Expected ValueError: for different length lists") except ValueError: pass #verify ValueError thrown when param list has a Var in it try: Result = sipopt(m, list_three, list_two) self.fail( "Expected ValueError: variable sent through paramSubList") except ValueError: pass #verify ValueError thrown when perturb list has Var in it try: Result = sipopt(m, list_one, list_three) self.fail("Expected ValueError: variable sent through perturbList") except ValueError: pass #verify ValueError thrown when param list has an unmutable param try: Result = sipopt(m, list_four, list_one) self.fail("Expected ValueError:" "unmutable param sent through paramSubList") except ValueError: pass
def test_instanciate_prog(self): from lms2 import ProgrammableLoad, DebugSource from pyomo.environ import AbstractModel, TransformationFactory, Param, Var from pyomo.dae import ContinuousSet import pandas as pd m = AbstractModel() m.time = ContinuousSet(bounds=(0, 10)) m.prog = ProgrammableLoad() UB = 1e6 df = pd.Series({0: 0, 1: 1, 2: 2, 3: 1, 4: 0}) data_prog = { 'time': { None: [0, 10] }, 'w1': { None: 3 }, 'w2': { None: 8 }, 'window': { None: [2, 8] }, 'profile_index': { None: df.index }, 'profile_value': df.to_dict() } data = \ {None: { 'time': {None: [0, 10]}, 'prog': data_prog } } inst = m.create_instance(data) TransformationFactory('dae.finite_difference').apply_to(inst, nfe=10) inst.prog.compile()
def test_update_contset_indexed_component_other(self): m = ConcreteModel() m.t = ContinuousSet(bounds=(0, 10)) m.junk = Suffix() m.s = Set(initialize=[1, 2, 3]) m.v = Var(m.s) def _obj(m): return sum(m.v[i] for i in m.s) m.obj = Objective(rule=_obj) expansion_map = ComponentMap generate_finite_elements(m.t, 5) update_contset_indexed_component(m.junk, expansion_map) update_contset_indexed_component(m.s, expansion_map) update_contset_indexed_component(m.obj, expansion_map)
def test_discretized_params_multiple(self): m = ConcreteModel() m.t = ContinuousSet(bounds=(0, 10)) m.s1 = Set(initialize=[1, 2, 3]) m.s2 = Set(initialize=[(1, 1), (2, 2)]) def _rule1(m, i): return i**2 m.p1 = Param(m.s1, m.t, initialize=2, default=_rule1) m.p2 = Param(m.t, m.s1, default=5) def _rule2(m, i, j): return i + j m.p3 = Param(m.s1, m.t, initialize=2, default=_rule2) def _rule3(m, i, j, k): return i + j + k m.p4 = Param(m.s2, m.t, default=_rule3) generate_finite_elements(m.t, 5) # Expected TypeError because a function with the wrong number of # arguments was specified as the default with self.assertRaises(TypeError): for i in m.p1: m.p1[i] for i in m.p2: self.assertEqual(m.p2[i], 5) for i in m.t: for j in m.s1: if i == 0 or i == 10: self.assertEqual(m.p3[j, i], 2) else: self.assertEqual(m.p3[j, i], i + j) for i in m.t: for j in m.s2: self.assertEqual(m.p4[j, i], sum(j, i))
def test_fix_profile(self): from lms2 import FlowSource, fix_profile from pyomo.environ import AbstractModel, TransformationFactory, Param, Set from pyomo.dae import ContinuousSet from pyomo.network import Port m = AbstractModel() m.time = ContinuousSet() m.u = FlowSource(flow_name='p') fix_profile(m.u, flow_name='p', profile_name='pro', index_name='ind') data_unit = { 'time': { None: (0, 15) }, 'ind': { None: [0, 10, 15] }, 'pro': dict(zip([0, 10, 15], [10, 11, 12])) } data = \ {None: { 'time': {None: [0, 15]}, 'u': data_unit } } inst = m.create_instance(data) TransformationFactory('dae.finite_difference').apply_to(inst, nfe=2) self.assertTrue(hasattr(m.u, 'p')) self.assertTrue(hasattr(m.u, 'outlet')) self.assertIsInstance(m.u.outlet, Port) self.assertTrue(hasattr(m.u, 'ind')) self.assertTrue(hasattr(m.u, 'pro')) self.assertIsInstance(m.u.pro, Param) self.assertIsInstance(m.u.ind, Set) self.assertEqual(inst.u.time.data(), (0, 7.5, 15)) self.assertEqual(inst.time.data(), (0, 7.5, 15))
def test_abs(self): from lms2 import FixedFlowLoad from pyomo.environ import AbstractModel, TransformationFactory, Param, Set from pyomo.dae import ContinuousSet from pyomo.network import Port m = AbstractModel() m.time = ContinuousSet() m.u = FixedFlowLoad(flow_name='p') self.assertTrue(hasattr(m.u, 'p')) self.assertTrue(hasattr(m.u, 'profile_index')) self.assertTrue(hasattr(m.u, 'profile_value')) self.assertIsInstance(m.u.profile_value, Param) self.assertIsInstance(m.u.profile_index, Set) self.assertTrue(hasattr(m.u, 'inlet')) self.assertIsInstance(m.u.inlet, Port) data_source = \ { 'time': {None: (0, 15)}, 'profile_index': {None: [0, 10, 15]}, 'profile_value': dict(zip([0, 10, 15], [10, 11, 12])) } data = \ {None: { 'time': {None: [0, 15]}, 'u': data_source } } inst = m.create_instance(data) TransformationFactory('dae.finite_difference').apply_to(inst, nfe=2) self.assertEqual(inst.u.time.data(), (0, 7.5, 15)) self.assertEqual(inst.time.data(), (0, 7.5, 15)) self.assertEqual(inst.u.p.extract_values(), { 0: 10.0, 7.5: 10.75, 15: 12.0 })
def test_invalid_declaration(self): model = ConcreteModel() model.s = Set(initialize=[1, 2, 3]) try: model.t = ContinuousSet(model.s, bounds=(0, 1)) self.fail("Expected TypeError") except TypeError: pass try: model.t = ContinuousSet(bounds=(0, 0)) self.fail("Expected ValueError") except ValueError: pass try: model.t = ContinuousSet(initialize=[1]) self.fail("Expected ValueError") except ValueError: pass try: model.t = ContinuousSet(bounds=(None, 1)) self.fail("Expected ValueError") except ValueError: pass try: model.t = ContinuousSet(bounds=(0, None)) self.fail("Expected ValueError") except ValueError: pass try: model.t = ContinuousSet(initialize=[(1, 2), (3, 4)]) self.fail("Expected ValueError") except ValueError: pass try: model.t = ContinuousSet(initialize=['foo', 'bar']) self.fail("Expected ValueError") except ValueError: pass
def test_constraint_skip(self): m = ConcreteModel() m.time = ContinuousSet(bounds=(0, 1)) m.v = Var(m.time) def c_rule(m, t): if t == m.time.first(): return Constraint.Skip return m.v[t] == 1. m.c = Constraint(m.time, rule=c_rule) scalar, dae = flatten_dae_components(m, m.time, Constraint) ref_data = { self._hashRef(Reference(m.c[:])), } self.assertEqual(len(dae), len(ref_data)) for ref in dae: self.assertIn(self._hashRef(ref), ref_data)
def test_config_validation_time(self, model): # Test validation of time argument model.test_set = Set(initialize=[0, 1, 2]) model.test_contset = ContinuousSet(bounds=[0, 1]) model.fs.config.time = model.test_set assert model.fs.config.time == model.test_set model.fs.config.time = model.test_contset assert model.fs.config.time == model.test_contset with pytest.raises(ValueError): model.fs.config.time = "foo" with pytest.raises(ValueError): model.fs.config.time = 1 with pytest.raises(ValueError): model.fs.config.time = 2.0 with pytest.raises(ValueError): model.fs.config.time = [1] with pytest.raises(ValueError): model.fs.config.time = {"foo": 1}
def test_external_function(self): m = ConcreteModel() m.t = ContinuousSet(bounds=(0, 10)) def _fun(x): return x**2 m.x_func = ExternalFunction(_fun) m.y = Var(m.t, initialize=3) m.dy = DerivativeVar(m.y, initialize=3) def _con(m, t): return m.dy[t] == m.x_func(m.y[t]) m.con = Constraint(m.t, rule=_con) generate_finite_elements(m.t, 5) expand_components(m) self.assertEqual(len(m.y), 6) self.assertEqual(len(m.con), 6)