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
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)
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]")
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')
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)