def test_bem_perf(self): mesh = df.UnitCubeMesh(15, 15, 15) boundary_mesh = df.BoundaryMesh(mesh, 'exterior', False) c = time_counter.counter() while c.next(): df.BoundaryMesh(mesh, 'exterior', False) print "Boundary mesh computation for %s: %s" % (mesh, c) c = time_counter.counter() while c.next(): bem, _ = compute_bem_fk(boundary_mesh) n = bem.shape[0] print "FK BEM computation for %dx%d (%.2f Mnodes/sec): %s" % ( n, n, c.calls_per_sec(n * n / 1e6), c) c = time_counter.counter() while c.next(): bem, _ = compute_bem_gcr(boundary_mesh) print "GCR BEM computation for %dx%d (%.2f Mnodes/sec): %s" % ( n, n, c.calls_per_sec(n * n / 1e6), c)
def run_measurements(m, mesh, unit_length, tol, repetitions=10, H_expected=None, name="", skip=[]): S3 = df.VectorFunctionSpace(mesh, "CG", 1) m = vector_valued_function(m, S3) Ms = 1 bem, boundary_to_global = compute_bem_fk(df.BoundaryMesh(mesh, 'exterior', False)) if H_expected is not None: H = vector_valued_function(H_expected, S3) H_expected = H.vector().array() else: # use default/default as reference then. demag = fk.FKDemag() demag.precomputed_bem(bem, boundary_to_global) demag.setup(S3, m, Ms, unit_length) H_expected = demag.compute_field() del(demag) if name == "": pass else: name = name + "_" runner = create_measurement_runner(S3, m, Ms, unit_length, H_expected, tol, repetitions, bem, boundary_to_global) solvers = [s[0] for s in df.krylov_solver_methods()] preconditioners = [p[0] for p in df.krylov_solver_preconditioners()] results_1, failed_1 = runner("first linear solve", "phi_1_solver", solvers, "phi_1_preconditioner", preconditioners, skip, "{}timings_log_1.txt".format(name), "{}results_1.pickled".format(name)) results_2, failed_2 = runner("second linear solve", "phi_2_solver", solvers, "phi_2_preconditioner", preconditioners, skip, "{}timings_log_2.txt".format(name), "{}results_2.pickled".format(name)) return solvers, preconditioners, results_1, failed_1, results_2, failed_2
def run_demag_benchmark(m, mesh, unit_length, tol, repetitions=10, name="bench", H_expected=None): S3 = df.VectorFunctionSpace(mesh, "CG", 1) m = vector_valued_function(m, S3) Ms = 1 # pre-compute BEM to save time bem, boundary_to_global = compute_bem_fk( df.BoundaryMesh(mesh, 'exterior', False)) if H_expected is not None: H = vector_valued_function(H_expected, S3) H_expected = H.vector().array() else: # if no H_expected was passed, use default/default as reference demag = fk.FKDemag() demag.precomputed_bem(bem, boundary_to_global) demag.setup(S3, m, Ms, unit_length) H_expected = demag.compute_field() del (demag) # gather all solvers and preconditioners solvers = [s[0] for s in df.krylov_solver_methods()] preconditioners = [p[0] for p in df.krylov_solver_preconditioners()] benchmark = prepare_benchmark(S3, m, Ms, unit_length, H_expected, tol, repetitions, bem, boundary_to_global) results_1 = benchmark("first linear solve", "phi_1_solver", solvers, "phi_1_preconditioner", preconditioners, name=name + "_1") results_2 = benchmark("second linear solve", "phi_2_solver", solvers, "phi_2_preconditioner", preconditioners, name=name + "_2") return solvers, preconditioners, results_1, results_2
def run_bem_computation_test(self, mesh): S3 = df.VectorFunctionSpace(mesh, "Lagrange", 1, dim=3) m = df.interpolate(df.Constant((1, 0, 0)), S3) Ms = 1.0 bem_magpar, g2finmag = belement.BEM_matrix(mesh) bem_finmag = np.zeros(bem_magpar.shape) bem, b2g = compute_bem_fk(df.BoundaryMesh(mesh, 'exterior', False)) for i_dolfin in xrange(bem.shape[0]): i_finmag = g2finmag[b2g[i_dolfin]] for j_dolfin in xrange(bem.shape[0]): j_finmag = g2finmag[b2g[j_dolfin]] bem_finmag[i_finmag, j_finmag] = bem[i_dolfin, j_dolfin] if np.max(np.abs(bem_finmag - bem_magpar)) > 1e-12: print "Finmag:", np.round(bem_finmag, 4) print "Magpar:", np.round(bem_magpar, 4) print "Difference:", np.round(bem_magpar - bem_finmag, 4) self.fail("Finmag and magpar computation of BEM differ, mesh: " + str(mesh))
def setup(self, m, Ms, unit_length=1): """ Setup the FKDemag instance. Usually called automatically by the Simulation object. *Arguments* m: finmag.Field The unit magnetisation on a finite element space. Ms: float The saturation magnetisation in A/m. unit_length: float The length (in m) represented by one unit on the mesh. Default 1. """ assert isinstance(m, Field) assert isinstance(Ms, Field) self.m = m self.Ms = Ms self.unit_length = unit_length self.S1 = df.FunctionSpace(self.m.mesh(), "Lagrange", 1) self._test1 = df.TestFunction(self.S1) self._trial1 = df.TrialFunction(self.S1) self._test3 = df.TestFunction(self.m.functionspace) self._trial3 = df.TrialFunction(self.m.functionspace) # for computation of energy self._nodal_volumes = nodal_volume(self.S1, unit_length) self._H_func = df.Function(m.functionspace) # we will copy field into # this when we need the # energy self._E_integrand = -0.5 * mu0 * \ df.dot(self._H_func, self.m.f * self.Ms.f) self._E = self._E_integrand * df.dx self._nodal_E = df.dot(self._E_integrand, self._test1) * df.dx self._nodal_E_func = df.Function(self.S1) # for computation of field and scalar magnetic potential self._poisson_matrix = self._poisson_matrix() self._laplace_zeros = df.Function(self.S1).vector() # determine the solver type to be used (Krylov or LU); if the kwarg # 'solver_type' is not provided, try to read the setting from the # .finmagrc file; use 'Krylov' if this fails. solver_type = self.solver_type if solver_type is None: solver_type = configuration.get_config_option( 'demag', 'solver_type', 'Krylov') if solver_type == 'None': # if the user set 'solver_type = None' in # the .finmagrc file, solver_type will be a # string so we need to catch this here. solver_type = 'Krylov' logger.debug("Using {} solver for demag.".format(solver_type)) if solver_type == 'Krylov': self._poisson_solver = df.KrylovSolver( self._poisson_matrix.copy(), self.parameters['phi_1_solver'], self.parameters['phi_1_preconditioner']) self._poisson_solver.parameters.update(self.parameters['phi_1']) self._laplace_solver = df.KrylovSolver( self.parameters['phi_2_solver'], self.parameters['phi_2_preconditioner']) self._laplace_solver.parameters.update(self.parameters['phi_2']) # We're setting 'same_nonzero_pattern=True' to enforce the # same matrix sparsity pattern across different demag solves, # which should speed up things. #self._laplace_solver.parameters["preconditioner"][ # "structure"] = "same_nonzero_pattern" elif solver_type == 'LU': self._poisson_solver = df.LUSolver(self._poisson_matrix.copy()) self._laplace_solver = df.LUSolver() self._poisson_solver.parameters["reuse_factorization"] = True self._laplace_solver.parameters["reuse_factorization"] = True else: raise ValueError( "Argument 'solver_type' must be either 'Krylov' or 'LU'. " "Got: '{}'".format(solver_type)) with fk_timer('compute BEM'): if not hasattr(self, "_bem"): if self.macrogeometry is not None: Ts = self.macrogeometry.compute_Ts(self.m.mesh()) pbc = BMatrixPBC(self.m.mesh(), Ts) self._b2g_map = np.array(pbc.b2g_map, dtype=np.int) self._bem = pbc.bm else: self._bem, self._b2g_map = compute_bem_fk( df.BoundaryMesh(self.m.mesh(), 'exterior', False)) logger.debug( "Boundary element matrix uses {:.2f} MB of memory.".format( self._bem.nbytes / 1024.**2)) # solution of inhomogeneous Neumann problem self._phi_1 = df.Function(self.S1) # solution of Laplace equation inside domain self._phi_2 = df.Function(self.S1) self._phi = df.Function(self.S1) # magnetic potential phi_1 + phi_2 # To be applied to the vector field m as first step of computation of # _phi_1. This gives us div(M), which is equal to Laplace(_phi_1), # equation which is then solved using _poisson_solver. self._Ms_times_divergence = df.assemble( self.Ms.f * df.inner(self._trial3, df.grad(self._test1)) * df.dx) # we move the boundary condition here to avoid create a instance each # time when compute the magnetic potential self.boundary_condition = df.DirichletBC(self.S1, self._phi_2, df.DomainBoundary()) self.boundary_condition.apply(self._poisson_matrix) self._setup_gradient_computation()
def setup(self, DG3, m, Ms, unit_length=1): """ Setup the FKDemag instance. Usually called automatically by the Simulation object. *Arguments* S3: dolfin.VectorFunctionSpace The finite element space the magnetisation is defined on. m: dolfin.Function on S3 The unit magnetisation. Ms: float The saturation magnetisation in A/m. unit_length: float The length (in m) represented by one unit on the mesh. Default 1. """ self.m = m self.Ms = Ms self.unit_length = unit_length mesh = DG3.mesh() self.S1 = df.FunctionSpace(mesh, "Lagrange", 1) self.S3 = df.VectorFunctionSpace(mesh, "Lagrange", 1) self.dim = mesh.topology().dim() self.n = df.FacetNormal(mesh) self.DG3 = DG3 self._test1 = df.TestFunction(self.S1) self._trial1 = df.TrialFunction(self.S1) self._test3 = df.TestFunction(self.S3) self._trial3 = df.TrialFunction(self.S3) self._test_dg3 = df.TestFunction(self.DG3) self._trial_dg3 = df.TrialFunction(self.DG3) # for computation of energy self._nodal_volumes = nodal_volume(self.S1, unit_length) self._H_func = df.Function( DG3) # we will copy field into this when we need the energy self._E_integrand = -0.5 * mu0 * df.dot(self._H_func, self.m * self.Ms) self._E = self._E_integrand * df.dx self._nodal_E = df.dot(self._E_integrand, self._test1) * df.dx self._nodal_E_func = df.Function(self.S1) # for computation of field and scalar magnetic potential self._poisson_matrix = self._poisson_matrix() self._poisson_solver = df.KrylovSolver( self._poisson_matrix, self.parameters['phi_1_solver'], self.parameters['phi_1_preconditioner']) self._poisson_solver.parameters.update(self.parameters['phi_1']) self._laplace_zeros = df.Function(self.S1).vector() self._laplace_solver = df.KrylovSolver( self.parameters['phi_2_solver'], self.parameters['phi_2_preconditioner']) self._laplace_solver.parameters.update(self.parameters['phi_2']) self._laplace_solver.parameters["preconditioner"][ "same_nonzero_pattern"] = True with fk_timed('compute BEM'): if not hasattr(self, "_bem"): self._bem, self._b2g_map = compute_bem_fk( df.BoundaryMesh(mesh, 'exterior', False)) self._phi_1 = df.Function( self.S1) # solution of inhomogeneous Neumann problem self._phi_2 = df.Function( self.S1) # solution of Laplace equation inside domain self._phi = df.Function(self.S1) # magnetic potential phi_1 + phi_2 # To be applied to the vector field m as first step of computation of _phi_1. # This gives us div(M), which is equal to Laplace(_phi_1), equation # which is then solved using _poisson_solver. self._Ms_times_divergence = df.assemble( self.Ms * df.inner(self._trial_dg3, df.grad(self._test1)) * df.dx) self._setup_gradient_computation()
def test_bem_netgen(self): module_dir = os.path.dirname(os.path.abspath(__file__)) netgen_mesh = df.Mesh( os.path.join(module_dir, "bem_netgen_test_mesh.xml.gz")) bem, b2g_map = compute_bem_fk( df.BoundaryMesh(netgen_mesh, 'exterior', False))
return H, runtime try: results = np.loadtxt(results_file) except IOError: results = np.zeros((len(maxhs), 4)) for i, maxh in enumerate(maxhs): print "Mesh {}/{} with maxh = {:.3}.".format(i + 1, len(maxhs), maxh) mesh = create_mesh(maxh) S3 = df.VectorFunctionSpace(mesh, "Lagrange", 1) m_function = df.Function(S3) m_function.assign(df.Constant(m_0)) m = Field(S3, m_function) # Pre-compute BEM to save time. bem, b2g_map = compute_bem_fk(df.BoundaryMesh(mesh, 'exterior', False)) print "Computing demagnetising field with default solver parameters..." H_default, runtime_default = run_demag( repetitions, default_params, m, Ms, unit_length, bem, b2g_map) print "Computing demagnetising field with optimised solver parameters..." H_opt, runtime_opt = run_demag( repetitions, opt_params, m, Ms, unit_length, bem, b2g_map) results[i, 0] = mesh.num_vertices() results[i, 1] = runtime_default results[i, 2] = runtime_opt results[i, 3] = np.max(np.abs(H_default - H_opt)) np.savetxt(results_file, results) # Save results after every step.