Esempio n. 1
0
    def test_exception(self):
        model = make_gas_expansion_model()
        igraph = IncidenceGraphInterface(model)

        with self.assertRaises(ValueError) as exc:
            variables = [model.P]
            constraints = [model.ideal_gas]
            igraph.maximum_matching(variables, constraints)
        self.assertIn('must be unindexed', str(exc.exception))

        with self.assertRaises(ValueError) as exc:
            variables = [model.P]
            constraints = [model.ideal_gas]
            igraph.block_triangularize(variables, constraints)
        self.assertIn('must be unindexed', str(exc.exception))
Esempio n. 2
0
    def test_perfect_matching(self):
        model = make_gas_expansion_model()
        igraph = IncidenceGraphInterface()

        # These are the variables and constraints of the square,
        # nonsingular subsystem
        variables = []
        variables.extend(model.P.values())
        variables.extend(model.T[i] for i in model.streams
                         if i != model.streams.first())
        variables.extend(model.rho[i] for i in model.streams
                         if i != model.streams.first())
        variables.extend(model.F[i] for i in model.streams
                         if i != model.streams.first())

        constraints = list(model.component_data_objects(pyo.Constraint))

        n_var = len(variables)
        matching = igraph.maximum_matching(variables, constraints)
        values = ComponentSet(matching.values())
        self.assertEqual(len(matching), n_var)
        self.assertEqual(len(values), n_var)

        # The subset of variables and equations we have identified
        # do not have a unique perfect matching. But we at least know
        # this much.
        self.assertIs(matching[model.ideal_gas[0]], model.P[0])
Esempio n. 3
0
    def test_imperfect_matching(self):
        model = make_gas_expansion_model()
        igraph = IncidenceGraphInterface(model)

        n_eqn = len(list(model.component_data_objects(pyo.Constraint)))
        matching = igraph.maximum_matching()
        values = ComponentSet(matching.values())
        self.assertEqual(len(matching), n_eqn)
        self.assertEqual(len(values), n_eqn)
Esempio n. 4
0
    def test_remove(self):
        model = make_gas_expansion_model()
        igraph = IncidenceGraphInterface(model)

        n_eqn = len(list(model.component_data_objects(pyo.Constraint)))
        matching = igraph.maximum_matching()
        values = ComponentSet(matching.values())
        self.assertEqual(len(matching), n_eqn)
        self.assertEqual(len(values), n_eqn)

        variable_set = ComponentSet(igraph.variables)
        self.assertIn(model.F[0], variable_set)
        self.assertIn(model.F[2], variable_set)
        var_dmp, con_dmp = igraph.dulmage_mendelsohn()
        underconstrained_set = ComponentSet(var_dmp.unmatched +
                                            var_dmp.underconstrained)
        self.assertIn(model.F[0], underconstrained_set)
        self.assertIn(model.F[2], underconstrained_set)

        N, M = igraph.incidence_matrix.shape

        # Say we know that these variables and constraints should
        # be matched...
        vars_to_remove = [model.F[0], model.F[2]]
        cons_to_remove = (model.mbal[1], model.mbal[2])
        igraph.remove_nodes(vars_to_remove, cons_to_remove)
        variable_set = ComponentSet(igraph.variables)
        self.assertNotIn(model.F[0], variable_set)
        self.assertNotIn(model.F[2], variable_set)
        var_dmp, con_dmp = igraph.dulmage_mendelsohn()
        underconstrained_set = ComponentSet(var_dmp.unmatched +
                                            var_dmp.underconstrained)
        self.assertNotIn(model.F[0], underconstrained_set)
        self.assertNotIn(model.F[2], underconstrained_set)

        N_new, M_new = igraph.incidence_matrix.shape
        self.assertEqual(N_new, N - len(cons_to_remove))
        self.assertEqual(M_new, M - len(vars_to_remove))
Esempio n. 5
0
def main():
    horizon = 600.0
    ntfe = 40
    #horizon = 30.0
    #ntfe = 2
    t1 = 0.0
    ch4_cuid = "fs.MB.gas_inlet.mole_frac_comp[*,CH4]"
    co2_cuid = "fs.MB.gas_inlet.mole_frac_comp[*,CO2]"
    h2o_cuid = "fs.MB.gas_inlet.mole_frac_comp[*,H2O]"
    input_dict = {
        ch4_cuid: {
            (t1, horizon): 0.5
        },
        co2_cuid: {
            (t1, horizon): 0.5
        },
        h2o_cuid: {
            (t1, horizon): 0.0
        },
    }

    m, var_cat, con_cat = get_model_for_simulation(horizon, ntfe)
    time = m.fs.time
    load_inputs_into_model(m, time, input_dict)

    solver = pyo.SolverFactory("ipopt")
    solve_kwds = {"tee": True}
    res_list = initialize_by_time_element(m,
                                          time,
                                          solver=solver,
                                          solve_kwds=solve_kwds)
    res = solver.solve(m, **solve_kwds)
    msg = res if type(res) is str else res.solver.termination_condition
    print(horizon, ntfe, msg)

    m._obj = pyo.Objective(expr=0.0)
    nlp = PyomoNLP(m)
    igraph = IncidenceGraphInterface()

    # TODO: I should be able to do categorization in the pre-time-discretized
    # model. This is somewhat nicer as the time points are all independent
    # in that case.
    solid_enth_conds = []
    gas_enth_conds = []
    solid_dens_conds = []
    gas_dens_conds = []
    for t in time:
        var_set = ComponentSet(var[t] for var in var_cat[VC.ALGEBRAIC])
        constraints = [con[t] for con in con_cat[CC.ALGEBRAIC] if t in con]
        variables = [
            var for var in _generate_variables_in_constraints(constraints)
            if var in var_set
        ]

        assert len(variables) == len(constraints)

        alg_jac = nlp.extract_submatrix_jacobian(variables, constraints)
        N, M = alg_jac.shape
        assert N == M
        matching = igraph.maximum_matching(variables, constraints)
        assert len(matching) == N
        try_factorization(alg_jac)

        # Condition number of the entire algebraic Jacobian seems
        # inconsistent, so I don't calculate it.
        #cond = np.linalg.cond(alg_jac.toarray())
        #cond = get_condition_number(alg_jac)

        var_blocks, con_blocks = igraph.get_diagonal_blocks(
            variables, constraints)
        block_matrices = [
            nlp.extract_submatrix_jacobian(vars, cons)
            for vars, cons in zip(var_blocks, con_blocks)
        ]
        gas_enth_blocks = [
            i for i, (vars, cons) in enumerate(zip(var_blocks, con_blocks))
            if any("gas_phase" in var.name and "temperature" in var.name
                   for var in vars)
        ]
        solid_enth_blocks = [
            i for i, (vars, cons) in enumerate(zip(var_blocks, con_blocks))
            if any("solid_phase" in var.name and "temperature" in var.name
                   for var in vars)
        ]
        gas_dens_blocks = [
            i for i, (vars, cons) in enumerate(zip(var_blocks, con_blocks))
            if any("gas_phase" in con.name and "sum_component_eqn" in con.name
                   for con in cons)
        ]
        solid_dens_blocks = [
            i for i, (vars, cons) in enumerate(zip(var_blocks, con_blocks))
            if any(
                "solid_phase" in con.name and "sum_component_eqn" in con.name
                for con in cons)
        ]
        gas_enth_cond = [
            np.linalg.cond(block_matrices[i].toarray())
            for i in gas_enth_blocks
        ]
        solid_enth_cond = [
            np.linalg.cond(block_matrices[i].toarray())
            for i in solid_enth_blocks
        ]
        gas_dens_cond = [
            np.linalg.cond(block_matrices[i].toarray())
            for i in gas_dens_blocks
        ]
        solid_dens_cond = [
            np.linalg.cond(block_matrices[i].toarray())
            for i in solid_dens_blocks
        ]
        max_gas_enth_cond = max(gas_enth_cond)
        max_solid_enth_cond = max(solid_enth_cond)
        max_gas_dens_cond = max(gas_dens_cond)
        max_solid_dens_cond = max(solid_dens_cond)
        gas_enth_conds.append(max_gas_enth_cond)
        solid_enth_conds.append(max_solid_enth_cond)
        gas_dens_conds.append(max_gas_dens_cond)
        solid_dens_conds.append(max_solid_dens_cond)

    # Plot condition numbers over time
    plt.rcParams.update({"font.size": 16})
    fig = plt.figure()
    ax = fig.add_subplot()
    t_list = list(time)
    ax.plot(t_list,
            gas_enth_conds,
            label="Gas enth.",
            linewidth=3,
            linestyle="solid")
    ax.plot(t_list,
            solid_enth_conds,
            label="Solid enth.",
            linewidth=3,
            linestyle="dotted")
    ax.plot(t_list,
            gas_dens_conds,
            label="Gas dens.",
            linewidth=3,
            linestyle="dashed")
    ax.plot(t_list,
            solid_dens_conds,
            label="Solid dens.",
            linewidth=3,
            linestyle="dashdot")
    ax.set_yscale("log")
    ax.set_ylim(bottom=1.0, top=1e7)
    ax.set_xlabel("Time (s)")
    ax.set_ylabel("Condition number")
    fig.legend(loc="center right", bbox_to_anchor=(1.0, 0.65))
    fig.tight_layout()
    fig.show()
    fig.savefig("condition_over_time.png", transparent=True)

    # Generate some structural results with the incidence matrix at a single
    # point in time.
    t = time.at(2)
    var_set = ComponentSet(var[t] for var in var_cat[VC.ALGEBRAIC])
    constraints = [con[t] for con in con_cat[CC.ALGEBRAIC] if t in con]
    variables = [
        var for var in _generate_variables_in_constraints(constraints)
        if var in var_set
    ]
    alg_jac = nlp.extract_submatrix_jacobian(variables, constraints)

    var_blocks, con_blocks = igraph.get_diagonal_blocks(variables, constraints)
    dim = len(constraints)
    n_blocks = len(var_blocks)
    print("Number of variables/constraints: %s" % dim)
    print("Number of diagonal blocks: %s" % n_blocks)
    block_polynomial_degrees = [
        get_polynomial_degree_wrt(cons, vars)
        for cons, vars in zip(con_blocks, var_blocks)
    ]
    nonlinear_blocks = [
        i for i, d in enumerate(block_polynomial_degrees) if d is None or d > 1
    ]
    print("Number of nonlinear blocks: %s" % len(nonlinear_blocks))

    print("\nNonlinear blocks:")
    for i in nonlinear_blocks:
        vars = var_blocks[i]
        cons = con_blocks[i]
        dim = len(vars)
        print("  Block %s, dim = %s" % (i, dim))
        print("    Variables:")
        for var in vars:
            print("      %s" % var.name)
        print("    Constraints:")
        for con in cons:
            print("      %s" % con.name)

    ordered_variables = [var for vars in var_blocks for var in vars]
    ordered_constraints = [con for cons in con_blocks for con in cons]
    ordered_jacobian = nlp.extract_submatrix_jacobian(ordered_variables,
                                                      ordered_constraints)
    plt.rcParams.update({"font.size": 18})
    fig, ax = plot_spy(
        ordered_jacobian,
        markersize=3,
    )
    ax.xaxis.set_tick_params(bottom=False)
    ax.xaxis.set_label_position("top")
    ax.set_xticks([0, 200, 400, 600])
    ax.set_yticks([0, 200, 400, 600])
    ax.set_xlabel("Column (variable) coordinates")
    ax.set_ylabel("Row (equation) coordinates")
    fig.tight_layout()
    fig.savefig("block_triangular_alg_jac.png", transparent=True)
    fig.show()