Beispiel #1
0
def _gmres_block_op_imp(
    A,
    b,
    tol=1e-5,
    restart=None,
    maxiter=None,
    use_strong_form=False,
    return_residuals=False,
    return_iteration_count=False,
):
    """Implementation for blocked operators."""
    import scipy.sparse.linalg

    import bempp.api
    import time
    from bempp.api.assembly.blocked_operator import (
        coefficients_from_grid_functions_list,
        projections_from_grid_functions_list,
        grid_function_list_from_coefficients,
    )

    # Assemble weak form before the logging messages

    if use_strong_form:
        b_vec = coefficients_from_grid_functions_list(b)
        A_op = A.strong_form()
    else:
        A_op = A.weak_form()
        b_vec = projections_from_grid_functions_list(b, A.dual_to_range_spaces)

    callback = IterationCounter(return_residuals)

    bempp.api.log("Starting GMRES iteration")
    start_time = time.time()
    x, info = scipy.sparse.linalg.gmres(A_op,
                                        b_vec,
                                        tol=tol,
                                        restart=restart,
                                        maxiter=maxiter,
                                        callback=callback)
    end_time = time.time()
    bempp.api.log("GMRES finished in %i iterations and took %.2E sec." %
                  (callback.count, end_time - start_time))

    res_fun = grid_function_list_from_coefficients(x.ravel(), A.domain_spaces)

    if return_residuals and return_iteration_count:
        return res_fun, info, callback.residuals, callback.count

    if return_residuals:
        return res_fun, info, callback.residuals

    if return_iteration_count:
        return res_fun, info, callback.count

    return res_fun, info
Beispiel #2
0
def lu(A, b, lu_factor=None):
    """Simple direct solver interface.

    This function takes an operator and a grid function,
    converts the operator into a dense matrix and solves
    the system via LU decomposition. The result is again
    returned as a grid function.

    Parameters
    ----------
    A : bempp.api.BoundaryOperator
         The left-hand side boundary operator
    b : bempp.api.GridFunction
         The right-hand side grid function
    lu_decomp : tuple
         Optionally pass the tuple (lu, piv)
         obtained by the scipy method scipy.linalg.lu_factor

    """
    from bempp.api import GridFunction, as_matrix
    from scipy.linalg import solve, lu_solve
    from bempp.api.assembly.blocked_operator import BlockedOperatorBase
    from bempp.api.assembly.blocked_operator import projections_from_grid_functions_list
    from bempp.api.assembly.blocked_operator import grid_function_list_from_coefficients

    if isinstance(A, BlockedOperatorBase):
        blocked = True
        vec = projections_from_grid_functions_list(b, A.dual_to_range_spaces)
        if lu_factor is not None:
            sol = lu_solve(lu_factor, vec)
        else:
            mat = A.weak_form().A
            sol = solve(mat, vec)
        return grid_function_list_from_coefficients(sol, A.domain_spaces)
    else:
        vec = b.projections(A.dual_to_range)
        if lu_factor is not None:
            sol = lu_solve(lu_factor, vec)
        else:
            mat = A.weak_form().A
            sol = solve(mat, vec)
        return GridFunction(A.domain, coefficients=sol)
Beispiel #3
0
def gmres(A_full, dual_to_range_sub, domain_sub, rhs_fun, Z,
            tol=1e-5,restart=None,maxiter=None):
    
    A_toe = get_weak_toe_form(A_full,Z)
    
    if isinstance(A_full, bempp.api.assembly.blocked_operator.BlockedOperatorBase):
        blocked = True
        b_vec = projections_from_grid_functions_list(rhs_fun, dual_to_range_sub)
    else:
        blocked = False
        b_vec = rhs_fun.projections(dual_to_range_sub)
    
    # use scipy's gmres to get the coefficients
    x, info = sp_gmres(
    A_toe, b_vec, tol=tol, restart=restart, maxiter=maxiter
    )
    
    if blocked:
        res_fun = grid_function_list_from_coefficients(x.ravel(), domain_sub)
    else:
        res_fun = GridFunction(domain_sub, coefficients=x.ravel())

    return res_fun, info
start = time.time()
sol_vec, info = gmres(A_weak_form,
                      rhs_vec,
                      M=precond,
                      callback=callback,
                      tol=PARAMS.tol,
                      restart=PARAMS.restart)
stop = time.time()

if PARAMS.save_solution:
    np.save('solution', sol_vec)
print(f"gmres wall time: {stop-start}")
print(f"The linear system was solved in {callback.count} iterations")

# compute solvation energy
ep = PARAMS.ep_ex / PARAMS.ep_in
from bempp.api.assembly.blocked_operator import grid_function_list_from_coefficients
sol = grid_function_list_from_coefficients(sol_vec.ravel(), A.domain_spaces)
solution_dirichl, solution_neumann = sol
slp_q = bempp.api.operators.potential.laplace.single_layer(neumann_space,
                                                           x_q.transpose(),
                                                           assembler=assembler)
dlp_q = bempp.api.operators.potential.laplace.double_layer(dirichl_space,
                                                           x_q.transpose(),
                                                           assembler=assembler)
phi_q = slp_q * solution_neumann * ep - dlp_q * solution_dirichl

# total dissolution energy applying constant to get units [kcal/mol]
total_energy = 2 * np.pi * 332.064 * np.sum(q * phi_q).real
print(f"Total solvation energy: {total_energy:.8f} [kcal/Mol]")
sol_vec, info = gmres(A_weak_form,
                      rhs_vec,
                      M=precond,
                      callback=callback,
                      tol=PARAMS.tol,
                      restart=PARAMS.restart)
stop = time.time()

if PARAMS.save_solution:
    np.save('solution', sol_vec)
print(f"gmres wall time: {stop-start}")
print(f"The linear system was solved in {callback.count} iterations")

# compute solvation energy
from bempp.api.assembly.blocked_operator import grid_function_list_from_coefficients
sol = grid_function_list_from_coefficients(
    sol_vec.ravel(),
    A.domain_spaces)  # convert solution vector to grid_function
solution_dirichl, solution_neumann = sol
slp_q = bempp.api.operators.potential.laplace.single_layer(neumann_space,
                                                           x_q.transpose(),
                                                           assembler=assembler)
dlp_q = bempp.api.operators.potential.laplace.double_layer(dirichl_space,
                                                           x_q.transpose(),
                                                           assembler=assembler)
phi_q = slp_q * solution_neumann - dlp_q * solution_dirichl

# total dissolution energy applying constant to get units [kcal/mol]
total_energy = 2 * np.pi * 332.064 * np.sum(q * phi_q).real
print(f"Total solvation energy: {total_energy:.8f} [kcal/Mol]")
Beispiel #6
0
    def calculate_potential(self):
        ## Start the overall timing for the whole process
        start_time = time.time()

        ## Setup Dirichlet and Neumann spaces to use, save these as object vars ##
        dirichl_space = bempp.api.function_space(self.mesh, "P", 1)
        neumann_space = bempp.api.function_space(self.mesh, "P", 1)
        self.dirichl_space = dirichl_space
        self.neumann_space = neumann_space

        ## Construct matrices and rhs based on the desired formulation ##
        setup_start_time = time.time(
        )  ## Start the timing for the matrix and rhs construction##
        if self.pb_formulation == "juffer":
            A, rhs_1, rhs_2 = pb_formulation.juffer(dirichl_space,
                                                    neumann_space, self.q,
                                                    self.x_q, self.ep_in,
                                                    self.ep_ex, self.kappa)
        elif self.pb_formulation == "direct":
            A, rhs_1, rhs_2 = pb_formulation.direct(dirichl_space,
                                                    neumann_space, self.q,
                                                    self.x_q, self.ep_in,
                                                    self.ep_ex, self.kappa)
        elif self.pb_formulation == "alpha_beta":
            A, rhs_1, rhs_2, A_in, A_ex, interior_projector, scaled_exterior_projector = pb_formulation.alpha_beta(
                dirichl_space, neumann_space, self.q, self.x_q, self.ep_in,
                self.ep_ex, self.kappa, self.pb_formulation_alpha,
                self.pb_formulation_beta)
        self.time_matrix_and_rhs_construction = time.time() - setup_start_time

        ## Check to see if preconditioning is to be applied ##
        preconditioning_start_time = time.time()
        if self.pb_formulation_preconditioning and self.pb_formulation == "alpha_beta":
            if self.pb_formulation_preconditioning_type == "interior":
                A_conditioner = A_in
            elif self.pb_formulation_preconditioning_type == "exterior":
                A_conditioner = A_ex
            elif self.pb_formulation_preconditioning_type == "scaled_exterior_projector":
                A_conditioner = scaled_exterior_projector
            elif self.pb_formulation_preconditioning_type == "interior_projector":
                A_conditioner = interior_projector
            elif self.pb_formulation_preconditioning_type == "squared":
                A_conditioner = A
            else:
                raise ValueError('Unrecognised preconditioning type')

            A_final = A_conditioner * A
            rhs = A_conditioner * [rhs_1, rhs_2]

        ## Set variables for system of equations if no preconditioning is to applied ##
        else:
            A_final = A
            rhs = [rhs_1, rhs_2]
        self.time_preconditioning = time.time() - preconditioning_start_time

        ## Pass matrix A to discrete form (either strong or weak) ##
        matrix_discrete_start_time = time.time()
        A_discrete = matrix_to_discrete_form(A_final, self.discrete_form_type)
        rhs_discrete = rhs_to_discrete_form(rhs, self.discrete_form_type, A)
        self.time_matrix_to_discrete = time.time() - matrix_discrete_start_time

        ## Use GMRES to solve the system of equations ##
        gmres_start_time = time.time()
        x, info, it_count = utils.solver(A_discrete, rhs_discrete,
                                         self.gmres_tolerance,
                                         self.gmres_max_iterations)
        self.time_gmres = time.time() - gmres_start_time

        ## Split solution and generate corresponding grid functions
        from bempp.api.assembly.blocked_operator import grid_function_list_from_coefficients
        (dirichlet_solution,
         neumann_solution) = grid_function_list_from_coefficients(
             x.ravel(), A.domain_spaces)

        ## Save number of iterations taken and the solution of the system ##
        self.solver_iteration_count = it_count
        self.phi = dirichlet_solution
        self.d_phi = neumann_solution

        ## Finished computing surface potential, register total time taken ##
        self.time_compue_potential = time.time() - start_time

        ## Print times, if this is desiered ##
        if self.print_times:
            print('It took ', self.time_matrix_and_rhs_construction,
                  ' seconds to construct the matrices and rhs vectores')
            print(
                'It took ', self.time_matrix_to_discrete,
                ' seconds to pass the main matrix to discrete form (' +
                self.discrete_form_type + ')')
            print(
                'It took ', self.time_preconditioning,
                ' seconds to compute and apply the preconditioning (' +
                str(self.pb_formulation_preconditioning) + ')(' +
                self.pb_formulation_preconditioning_type + ')')
            print('It took ', self.time_gmres,
                  ' seconds to resolve the system using GMRES')
            print('It took ', self.time_compue_potential,
                  ' seconds in total to compute the surface potential')
Beispiel #7
0
    def calculate_potential(self, rerun_all=False):
        # Start the overall timing for the whole process
        start_time = time.time()

        if rerun_all:
            self.initialise_matrices()
            self.assemble_matrices()
            self.initialise_rhs()
            self.apply_preconditioning()
            #self.pass_to_discrete_form()

        else:
            if "A" not in self.matrices:
                # If matrix A doesn't exist, it must first be created
                self.initialise_matrices()
            if not self.matrices["A"]._cached:
                self.assemble_matrices()
            if "rhs_1" not in self.rhs:
                # If rhs_1 doesn't exist, it must first be created
                self.initialise_rhs()
            if "A_discrete" not in self.matrices or "rhs_discrete" not in self.rhs:
                # See if preconditioning needs to be applied if this hasn't been done
                self.apply_preconditioning()
            # if "A_discrete" not in self.matrices or "rhs_discrete" not in self.rhs:
            #   # See if discrete form has been called
            #  self.pass_to_discrete_form()

        # Use GMRES to solve the system of equations
        gmres_start_time = time.time()
        if self.pb_formulation_preconditioning and (
                self.pb_formulation_preconditioning_type == "block_diagonal"
                or self.pb_formulation_preconditioning_type
                == "block_diagonal_test"):
            x, info, it_count = utils.solver(
                self.matrices["A_discrete"],
                self.rhs["rhs_discrete"],
                self.gmres_tolerance,
                self.gmres_restart,
                self.gmres_max_iterations,
                precond=self.matrices["preconditioning_matrix"])
        else:
            x, info, it_count = utils.solver(self.matrices["A_discrete"],
                                             self.rhs["rhs_discrete"],
                                             self.gmres_tolerance,
                                             self.gmres_restart,
                                             self.gmres_max_iterations)
        self.timings["time_gmres"] = time.time() - gmres_start_time

        # Split solution and generate corresponding grid functions
        from bempp.api.assembly.blocked_operator import grid_function_list_from_coefficients
        (dirichlet_solution,
         neumann_solution) = grid_function_list_from_coefficients(
             x.ravel(), self.matrices["A"].domain_spaces)

        # Save number of iterations taken and the solution of the system
        self.results["solver_iteration_count"] = it_count
        self.results["phi"] = dirichlet_solution
        if self.pb_formulation == "alpha_beta_external_potential" or self.pb_formulation == "lu" \
                or self.pb_formulation == "muller_external" or self.pb_formulation == "first_kind_external"\
                or self.pb_formulation == "direct_external" or self.pb_formulation == "direct_external_permuted":
            self.results["d_phi"] = (self.ep_ex /
                                     self.ep_in) * neumann_solution
        else:
            self.results["d_phi"] = neumann_solution
        # self.solver_iteration_count = it_count
        # self.phi = dirichlet_solution
        # self.d_phi = neumann_solution

        # Finished computing surface potential, register total time taken
        self.timings["time_compute_potential"] = time.time() - start_time
        # self.time_compute_potential = time.time()-start_time

        # Print times, if this is desired
        if self.print_times:
            show_potential_calculation_times(self)