Exemplo n.º 1
0
    def test_initialize_by_solving_elements(self):
        # Make nmpc
        # add setpoint to controller
        # add pwc_constraints
        # call initialize_by_solving_elements
        # assert that values are as expected.
        nmpc = self.make_nmpc()
        time = nmpc.controller_time
        t0 = time.first()
        tl = time.last()
        controller = nmpc.controller
        namespace = getattr(controller, nmpc.namespace_name)
        setpoint = [
            (nmpc.controller.flow_in[t0], 3.0),
        ]
        # Note: without this initialization, the setpoint arrives at a
        # local optimum with inlet flow ~= 0.
        nmpc.controller.flow_in[:].set_value(3.0)
        initialize_t0(nmpc.controller)
        copy_values_forward(nmpc.controller)
        nmpc.calculate_full_state_setpoint(setpoint, outlvl=idaeslog.DEBUG)
        override = [
            (nmpc.controller.conc[t0, 'A'], 1),
            (nmpc.controller.conc[t0, 'B'], 1),
            (nmpc.controller.rate[t0, 'A'], 1),
            (nmpc.controller.rate[t0, 'B'], 1),
            (nmpc.controller.flow_out[t0], 1),
            (nmpc.controller.flow_in[t0], 1),
        ]
        nmpc.add_setpoint_to_controller(objective_weight_override=override)
        nmpc.constrain_control_inputs_piecewise_constant()
        nmpc.controller.flow_in[:].set_value(2.0)
        nmpc.initialize_by_solving_elements(
            controller,
            time,
            input_type=ElementInitializationInputOption.INITIAL,
        )
        input_vars = namespace.input_vars
        diff_vars = namespace.diff_vars
        deriv_vars = namespace.deriv_vars
        assert input_vars[0][tl].value == 2.0
        assert diff_vars[0][tl].value == pytest.approx(3.185595567867036)
        assert diff_vars[1][tl].value == pytest.approx(1.1532474073395755)
        assert deriv_vars[0][tl].value == pytest.approx(0.44321329639889284)
        assert deriv_vars[1][tl].value == pytest.approx(0.8791007531878847)

        nmpc.initialize_by_solving_elements(
            controller,
            time,
            input_type=ElementInitializationInputOption.SET_POINT,
        )
        for t in time:
            if t != t0:
                assert input_vars[0][t] == 3.0
        assert diff_vars[0][tl].value == pytest.approx(3.7037037037037037)
        assert diff_vars[1][tl].value == pytest.approx(1.0746896480968502)
        assert deriv_vars[0][tl].value == pytest.approx(0.1851851851851849)
        assert deriv_vars[1][tl].value == pytest.approx(0.47963475941315314)
Exemplo n.º 2
0
def test_constrain_control_inputs_piecewise_constant(nmpc):
    sample_time = 0.5
    nmpc.constrain_control_inputs_piecewise_constant(sample_time=sample_time)

    controller = nmpc.controller

    assert nmpc.sample_time == sample_time
    assert nmpc.controller._NMPC_NAMESPACE.samples_per_horizon == 6

    # Test that components were added
    assert hasattr(controller._NMPC_NAMESPACE, 'pwc_constraint')

    # Test that constraints have the correct indexing set
    n_sample = int(controller.time.last()/sample_time)
    sample_points = [sample_time*i
            for i in range(n_sample+1)]
    # sample_points should include time.first()

    assert (sample_points == nmpc.controller._NMPC_NAMESPACE.sample_points)

    for t in sample_points:
        for i in range(controller._NMPC_NAMESPACE.n_input_vars):
            assert (t, i) not in controller._NMPC_NAMESPACE.pwc_constraint
            # ^ tuple because pwc_constraint is now indexed by time and the location
            # into the input list

    # Rough test that the constraints are correct - contain the correct
    # variables.
    time = controller._NMPC_NAMESPACE.get_time()
    for i, t in enumerate(controller._NMPC_NAMESPACE.get_time()):
        if t not in sample_points and t != time.first():
            t_next = time[i+2]
            var_in_0 = [id(v) for v in
                identify_variables(controller._NMPC_NAMESPACE.pwc_constraint[t, 0].expr)]
            var_in_1 = [id(v) for v in
                identify_variables(controller._NMPC_NAMESPACE.pwc_constraint[t, 1].expr)]
            assert len(var_in_0) == 2
            assert len(var_in_1) == 2
            assert (id(controller._NMPC_NAMESPACE.input_vars.varlist[0][t])
                    in var_in_0)
            assert (id(controller._NMPC_NAMESPACE.input_vars.varlist[0][t_next])
                    in var_in_0)
            assert (id(controller._NMPC_NAMESPACE.input_vars.varlist[1][t])
                    in var_in_1)
            assert (id(controller._NMPC_NAMESPACE.input_vars.varlist[1][t_next])
                    in var_in_1)
Exemplo n.º 3
0
 def test_solve_control_problem(self):
     # make nmpc
     # add setpoint
     # initialize, from ICs probably
     # solve control problem
     # assert values are as expected.
     # Could probably even do this without initialization
     nmpc = self.make_nmpc()
     time = nmpc.controller_time
     t0 = time.first()
     tl = time.last()
     controller = nmpc.controller
     namespace = getattr(controller, nmpc.namespace_name)
     t1 = namespace.sample_points[1]
     setpoint = [
         (nmpc.controller.flow_in[t0], 3.0),
     ]
     # Note: without this initialization, the setpoint arrives at a
     # local optimum with inlet flow ~= 0.
     # One way to deal with this pitfall is to add bounds to inlet flow.
     nmpc.controller.flow_in[:].set_value(3.0)
     initialize_t0(nmpc.controller)
     copy_values_forward(nmpc.controller)
     nmpc.calculate_full_state_setpoint(setpoint, outlvl=idaeslog.DEBUG)
     override = [
         (nmpc.controller.conc[t0, 'A'], 1),
         (nmpc.controller.conc[t0, 'B'], 1),
         (nmpc.controller.rate[t0, 'A'], 1),
         (nmpc.controller.rate[t0, 'B'], 1),
         (nmpc.controller.flow_out[t0], 1),
         (nmpc.controller.flow_in[t0], 1),
     ]
     nmpc.add_setpoint_to_controller(objective_weight_override=override)
     nmpc.constrain_control_inputs_piecewise_constant()
     nmpc.solve_control_problem()
     input_vars = namespace.input_vars
     diff_vars = namespace.diff_vars
     assert input_vars[0][t1].value == pytest.approx(3.192261151432352)
     assert input_vars[0][tl].value == pytest.approx(2.9818775607191648)
     assert diff_vars[0][tl].value == pytest.approx(3.7101450012850137)
     assert diff_vars[1][tl].value == pytest.approx(1.0898406680173942)
     assert nmpc.controller_solved
Exemplo n.º 4
0
 def test_constrain_control_inputs_piecewise_constant(self):
     # construct nmpc
     # constrain_control_inputs
     # assert hasattr pwc_constraint_list, pwc_constraint
     # for each, assert has correct variables
     nmpc = self.make_nmpc()
     namespace = getattr(nmpc.controller, nmpc.namespace_name)
     time = nmpc.controller_time
     t0 = time.first()
     sample_points = namespace.sample_points
     sample_point_set = set(sample_points)
     nmpc.constrain_control_inputs_piecewise_constant()
     assert hasattr(namespace, 'pwc_constraint')
     assert hasattr(namespace, 'pwc_constraint_list')
     for var, con in zip(namespace.input_vars,
                         namespace.pwc_constraint_list):
         for t in time:
             if t in sample_point_set:
                 continue
             t_next = time.next(t)
             incident_vars = ComponentSet(identify_variables(con[t].expr))
             assert var[t] in incident_vars
             assert var[t_next] in incident_vars
Exemplo n.º 5
0
    def test_initialize_control_problem(self):
        # Each initialization strategy should be tested in more detail
        # in other functions.
        # This function should test that each strategy can be passed to
        # the user-facing function, and that the values left in the
        # controller model are somewhat reasonable
        nmpc = self.make_nmpc()
        time = nmpc.controller_time
        t0 = time.first()
        namespace = getattr(nmpc.controller, nmpc.namespace_name)
        setpoint = [
            (nmpc.controller.flow_in[t0], 3.0),
        ]
        # Note: without this initialization, the setpoint arrives at a
        # local optimum with inlet flow ~= 0.
        nmpc.controller.flow_in[:].set_value(3.0)
        initialize_t0(nmpc.controller)
        copy_values_forward(nmpc.controller)
        nmpc.calculate_full_state_setpoint(setpoint, outlvl=idaeslog.DEBUG)
        override = [
            (nmpc.controller.conc[t0, 'A'], 1),
            (nmpc.controller.conc[t0, 'B'], 1),
            (nmpc.controller.rate[t0, 'A'], 1),
            (nmpc.controller.rate[t0, 'B'], 1),
            (nmpc.controller.flow_out[t0], 1),
            (nmpc.controller.flow_in[t0], 1),
        ]
        nmpc.add_setpoint_to_controller(objective_weight_override=override)
        nmpc.constrain_control_inputs_piecewise_constant()

        nmpc.initialize_control_problem(
            control_init_option=ControlInitOption.FROM_INITIAL_CONDITIONS)
        nmpc.initialize_control_problem(
            control_init_option=ControlInitOption.BY_TIME_ELEMENT)
        with pytest.raises(RuntimeError):
            nmpc.initialize_control_problem(
                control_init_option=ControlInitOption.FROM_PREVIOUS)
Exemplo n.º 6
0
    def test_initialize_from_previous_sample(self):
        nmpc = self.make_nmpc()
        time = nmpc.controller_time
        t0 = time.first()
        tl = time.last()
        controller = nmpc.controller
        namespace = getattr(controller, nmpc.namespace_name)
        sample_points = namespace.sample_points
        t1 = sample_points[1]
        setpoint = [
            (nmpc.controller.flow_in[t0], 3.0),
        ]
        # Note: without this initialization, the setpoint arrives at a
        # local optimum with inlet flow ~= 0.
        # One way to deal with this pitfall is to add bounds to inlet flow.
        nmpc.controller.flow_in[:].set_value(3.0)
        initialize_t0(nmpc.controller)
        copy_values_forward(nmpc.controller)
        nmpc.calculate_full_state_setpoint(setpoint, outlvl=idaeslog.DEBUG)
        override = [
            (nmpc.controller.conc[t0, 'A'], 1),
            (nmpc.controller.conc[t0, 'B'], 1),
            (nmpc.controller.rate[t0, 'A'], 1),
            (nmpc.controller.rate[t0, 'B'], 1),
            (nmpc.controller.flow_out[t0], 1),
            (nmpc.controller.flow_in[t0], 1),
        ]
        nmpc.add_setpoint_to_controller(objective_weight_override=override)
        nmpc.constrain_control_inputs_piecewise_constant()
        nmpc.solve_control_problem()

        diff_vars = namespace.diff_vars
        input_vars = namespace.input_vars
        sample_time = nmpc.sample_time
        n_samples = namespace.samples_per_horizon
        cat_dict = namespace.category_dict
        categories = [
            VariableCategory.DIFFERENTIAL,
            VariableCategory.INPUT,
        ]
        expected = {
            categ: {
                s: [{
                    t - sample_time: cat_dict[categ][i][t].value
                    for t in time
                    if sample_points[s] < t and t <= sample_points[s + 1]
                } for i in range(len(cat_dict[categ]))]
                for s in range(1, n_samples)
            }
            for categ in categories
        }
        for categ in categories:
            expected[categ][n_samples] = [{
                t: cat_dict[categ].setpoint[i]
                for t in time
                if sample_points[n_samples -
                                 1] < t and t <= sample_points[n_samples]
            } for i in range(len(cat_dict[categ]))]

        nmpc.initialize_from_previous_sample(nmpc.controller)

        for s in range(1, n_samples):
            interval = [
                t for t in time
                if sample_points[s - 1] < t and t <= sample_points[s]
            ]
            for categ in categories:
                for i, var in enumerate(cat_dict[categ]):
                    for t in interval:
                        assert var[t].value == expected[categ][s][i][t]