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_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.º 3
0
    def test_calculate_error_between_states(self):
        # make nmpc
        # artificially change values
        # calculate error.
        nmpc = self.make_nmpc()
        initialize_t0(nmpc.controller)
        copy_values_forward(nmpc.controller)
        initialize_t0(nmpc.controller)
        copy_values_forward(nmpc.controller)

        nmpc.controller.conc[1, 'A'].set_value(5)
        nmpc.controller.conc[1, 'B'].set_value(5)
        nmpc.plant.conc[1, 'A'].set_value(3)
        nmpc.plant.conc[1, 'B'].set_value(3)
        Q_matrix = [1, 1]
        error = nmpc.calculate_error_between_states(
            nmpc.controller,
            nmpc.plant,
            1,
            1,
            Q_matrix=Q_matrix,
        )
        assert error == 1 * 2**2 + 1 * 2**2
Exemplo n.º 4
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.º 5
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]
Exemplo n.º 6
0
    def test_add_objective_function(self):
        # populate setpoints,
        # construct weights (with override everywhere)
        # add objective function
        # compare objective function to prediction
        # for diff+error, diff+action, diff+alg+action setpoints
        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.construct_objective_weights(
            nmpc.controller,
            objective_weight_override=override,
        )
        pred_obj = {i: 0. for i in range(1, 4)}
        sample_points = namespace.sample_points[1:]
        setpoint = namespace.diff_vars.setpoint
        for i, v in enumerate(namespace.diff_vars):
            for t in sample_points:
                pred_obj[1] += (v[t] - setpoint[i])**2
                pred_obj[2] += (v[t] - setpoint[i])**2
                pred_obj[3] += (v[t] - setpoint[i])**2
        setpoint = namespace.alg_vars.setpoint
        for i, v in enumerate(namespace.alg_vars):
            for t in sample_points:
                pred_obj[3] += (v[t] - setpoint[i])**2
        setpoint = namespace.input_vars.setpoint
        for i, v in enumerate(namespace.input_vars):
            for t in sample_points:
                t_prev = t - nmpc.sample_time
                pred_obj[1] += (v[t] - setpoint[i])**2
                pred_obj[2] += (v[t] - v[t_prev])**2
                pred_obj[3] += (v[t] - v[t_prev])**2

        nmpc.add_objective_function(
            nmpc.controller,
            control_penalty_type=ControlPenaltyType.ERROR,
            objective_state_categories=[
                VariableCategory.DIFFERENTIAL,
            ])
        assert aml.value(namespace.objective.expr == pred_obj[1])
        namespace.del_component(namespace.objective)

        nmpc.add_objective_function(
            nmpc.controller,
            control_penalty_type=ControlPenaltyType.ACTION,
            objective_state_categories=[
                VariableCategory.DIFFERENTIAL,
            ])
        assert aml.value(namespace.objective.expr == pred_obj[2])
        namespace.del_component(namespace.objective)

        nmpc.add_objective_function(
            nmpc.controller,
            control_penalty_type=ControlPenaltyType.ACTION,
            objective_state_categories=[
                VariableCategory.DIFFERENTIAL,
                VariableCategory.ALGEBRAIC,
            ])
        assert aml.value(namespace.objective.expr == pred_obj[3])
        namespace.del_component(namespace.objective)