def test_to_DG0(self): subdomains = (df.CompiledSubDomain('near(x[0], 0.5)'), df.DomainBoundary()) for subd in subdomains: mesh = df.UnitCubeMesh(4, 4, 4) facet_f = df.MeshFunction('size_t', mesh, 2, 0) subd.mark(facet_f, 1) submesh = EmbeddedMesh(facet_f, 1) transfer = SubMeshTransfer(mesh, submesh) V = df.FunctionSpace(mesh, 'Discontinuous Lagrange Trace', 0) Vsub = df.FunctionSpace(submesh, 'DG', 0) to_Vsub = transfer.compute_map(Vsub, V, strict=False) # Set degree 0 to get the quad order right f = df.Expression('x[0] + 2*x[1] - x[2]', degree=0) fV = df.interpolate(f, V) fsub = df.Function(Vsub) to_Vsub(fsub, fV) error = df.inner(fsub - f, fsub - f)*df.dx(domain=submesh) error = df.sqrt(abs(df.assemble(error))) self.assertTrue(error < 1E-13)
def __init__(self, u, boundary_is_streamline=False, degree=1): """ Heavily based on https://github.com/mikaem/fenicstools/blob/master/fenicstools/Streamfunctions.py Stream function for a given general 2D velocity field. The boundary conditions are weakly imposed through the term inner(q, grad(psi)*n)*ds, where grad(psi) = [-v, u] is set on all boundaries. This should work for any collection of boundaries: walls, inlets, outlets etc. """ Vu = u[0].function_space() mesh = Vu.mesh() # Check dimension if not mesh.geometry().dim() == 2: df.error("Stream-function can only be computed in 2D.") # Define the weak form V = df.FunctionSpace(mesh, 'CG', degree) q = df.TestFunction(V) psi = df.TrialFunction(V) n = df.FacetNormal(mesh) a = df.dot(df.grad(q), df.grad(psi)) * df.dx L = df.dot(q, df.curl(u)) * df.dx if boundary_is_streamline: # Strongly set psi = 0 on entire domain boundary self.bcs = [df.DirichletBC(V, df.Constant(0), df.DomainBoundary())] self.normalize = False else: self.bcs = [] self.normalize = True L = L + q * (n[1] * u[0] - n[0] * u[1]) * df.ds # Create preconditioned iterative solver solver = df.PETScKrylovSolver('gmres', 'hypre_amg') solver.parameters['nonzero_initial_guess'] = True solver.parameters['relative_tolerance'] = 1e-10 solver.parameters['absolute_tolerance'] = 1e-10 # Store for later computation self.psi = df.Function(V) self.A = df.assemble(a) self.L = L self.mesh = mesh self.solver = solver self._triangulation = None
def init_with_mesh (self, mesh ): """initialise the boundary condition using the mesh. A mesh function is constructed from the mesh and the boundary region is marked. @param mesh: The mesh on which the boundary condition is to be applied """ mesh_function = dolfin.MeshFunction( 'uint', mesh, mesh.topology().dim()-1) mesh_function.set_all ( 0 ) walls = dolfin.DomainBoundary() walls.mark(mesh_function, 999) self.init_with_meshfunction(mesh_function, 999)
def solve_laplace_inside(self, function, solverparams=None): """Take a functions boundary data as a dirichlet BC and solve a laplace equation""" bc = df.DirichletBC(self.V, function, df.DomainBoundary()) A = self.poisson_matrix.copy() b = self.laplace_zeros # .copy() bc.apply(A, b) if self.bench: bench.solve(A, function.vector(), b, benchmark=True) else: demag_timer.start("2nd linear solve", self.__class__.__name__) self.laplace_iter = self.laplace_solver.solve( A, function.vector(), b) demag_timer.stop("2nd linear solve", self.__class__.__name__) return function
def set_dofs(self, dofs): x_r = np.real(dofs).copy() x_i = np.imag(dofs).copy() self.E_r.vector()[:] = x_r self.E_i.vector()[:] = x_i self.dofs = dofs boundary = dolfin.DomainBoundary() E_r_dirich = dolfin.DirichletBC(self.function_space, self.E_r, boundary) E_i_dirich = dolfin.DirichletBC(self.function_space, self.E_i, boundary) x_r_dirich = as_dolfin_vector(np.zeros(len(x_r))) x_i_dirich = as_dolfin_vector(np.zeros(len(x_r))) E_r_dirich.apply(x_r_dirich) E_i_dirich.apply(x_i_dirich) self.dirich_dofs = x_r_dirich.array() + 1j * x_i_dirich.array() self.functional.set_E_dofs(dofs)
def __init__(self, mesh, boundary_facefun=None, boundary_value=1): """Find and mark the edges that occur on a set of boundary faces @param mesh: A dolfin mesh object @keyword boundary_facefun: a face mesh function that describes the faces to be considered (default: None). @keyword boundary_value: the mesh function value marking the boundary faces (default: 1) """ self.mesh = mesh if boundary_facefun is None: boundary_facefun = dolfin.FaceFunction('uint', mesh) boundary_facefun.set_all(0) domain_boundary = dolfin.DomainBoundary() domain_boundary.mark(boundary_facefun, boundary_value) self.boundary_facefun = boundary_facefun self.boundary_value = boundary_value self.ensure_initialised = EnsureInitialised(self.mesh)
def _compute_magnetic_potential(self): # compute _phi_1 on the whole domain g_1 = self._Ms_times_divergence * self.m.vector() with fk_timed("first linear solve"): self._poisson_solver.solve(self._phi_1.vector(), g_1) # compute _phi_2 on the boundary using the Dirichlet boundary # conditions we get from BEM * _phi_1 on the boundary. with fk_timed("using boundary conditions"): phi_1 = self._phi_1.vector()[self._b2g_map] self._phi_2.vector()[self._b2g_map[:]] = np.dot( self._bem, phi_1.array()) boundary_condition = df.DirichletBC(self.S1, self._phi_2, df.DomainBoundary()) A = self._poisson_matrix.copy() b = self._laplace_zeros boundary_condition.apply(A, b) # compute _phi_2 on the whole domain with fk_timed("second linear solve"): self._laplace_solver.solve(A, self._phi_2.vector(), b) # add _phi_1 and _phi_2 to obtain magnetic potential self._phi.vector()[:] = self._phi_1.vector() + self._phi_2.vector()
def _discretize_fenics(): # assemble system matrices - FEniCS code ######################################## import dolfin as df mesh = df.UnitSquareMesh(GRID_INTERVALS, GRID_INTERVALS, 'crossed') V = df.FunctionSpace(mesh, 'Lagrange', FENICS_ORDER) u = df.TrialFunction(V) v = df.TestFunction(V) diffusion = df.Expression( '(lower0 <= x[0]) * (open0 ? (x[0] < upper0) : (x[0] <= upper0)) *' '(lower1 <= x[1]) * (open1 ? (x[1] < upper1) : (x[1] <= upper1))', lower0=0., upper0=0., open0=0, lower1=0., upper1=0., open1=0, element=df.FunctionSpace(mesh, 'DG', 0).ufl_element()) def assemble_matrix(x, y, nx, ny): diffusion.user_parameters['lower0'] = x / nx diffusion.user_parameters['lower1'] = y / ny diffusion.user_parameters['upper0'] = (x + 1) / nx diffusion.user_parameters['upper1'] = (y + 1) / ny diffusion.user_parameters['open0'] = (x + 1 == nx) diffusion.user_parameters['open1'] = (y + 1 == ny) return df.assemble( df.inner(diffusion * df.nabla_grad(u), df.nabla_grad(v)) * df.dx) mats = [ assemble_matrix(x, y, XBLOCKS, YBLOCKS) for x in range(XBLOCKS) for y in range(YBLOCKS) ] mat0 = mats[0].copy() mat0.zero() h1_mat = df.assemble(df.inner(df.nabla_grad(u), df.nabla_grad(v)) * df.dx) f = df.Constant(1.) * v * df.dx F = df.assemble(f) bc = df.DirichletBC(V, 0., df.DomainBoundary()) for m in mats: bc.zero(m) bc.apply(mat0) bc.apply(h1_mat) bc.apply(F) # wrap everything as a pyMOR model ################################## # FEniCS wrappers from pymor.bindings.fenics import FenicsVectorSpace, FenicsMatrixOperator, FenicsVisualizer # define parameter functionals (same as in pymor.analyticalproblems.thermalblock) parameter_functionals = [ ProjectionParameterFunctional(component_name='diffusion', component_shape=(YBLOCKS, XBLOCKS), index=(YBLOCKS - y - 1, x)) for x in range(XBLOCKS) for y in range(YBLOCKS) ] # wrap operators ops = [FenicsMatrixOperator(mat0, V, V) ] + [FenicsMatrixOperator(m, V, V) for m in mats] op = LincombOperator(ops, [1.] + parameter_functionals) rhs = VectorOperator(FenicsVectorSpace(V).make_array([F])) h1_product = FenicsMatrixOperator(h1_mat, V, V, name='h1_0_semi') # build model visualizer = FenicsVisualizer(FenicsVectorSpace(V)) parameter_space = CubicParameterSpace(op.parameter_type, 0.1, 1.) fom = StationaryModel(op, rhs, products={'h1_0_semi': h1_product}, parameter_space=parameter_space, visualizer=visualizer) return fom
def _discretize_fenics(xblocks, yblocks, grid_num_intervals, element_order): # assemble system matrices - FEniCS code ######################################## import dolfin as df mesh = df.UnitSquareMesh(grid_num_intervals, grid_num_intervals, 'crossed') V = df.FunctionSpace(mesh, 'Lagrange', element_order) u = df.TrialFunction(V) v = df.TestFunction(V) diffusion = df.Expression('(lower0 <= x[0]) * (open0 ? (x[0] < upper0) : (x[0] <= upper0)) *' '(lower1 <= x[1]) * (open1 ? (x[1] < upper1) : (x[1] <= upper1))', lower0=0., upper0=0., open0=0, lower1=0., upper1=0., open1=0, element=df.FunctionSpace(mesh, 'DG', 0).ufl_element()) def assemble_matrix(x, y, nx, ny): diffusion.user_parameters['lower0'] = x/nx diffusion.user_parameters['lower1'] = y/ny diffusion.user_parameters['upper0'] = (x + 1)/nx diffusion.user_parameters['upper1'] = (y + 1)/ny diffusion.user_parameters['open0'] = (x + 1 == nx) diffusion.user_parameters['open1'] = (y + 1 == ny) return df.assemble(df.inner(diffusion * df.nabla_grad(u), df.nabla_grad(v)) * df.dx) mats = [assemble_matrix(x, y, xblocks, yblocks) for x in range(xblocks) for y in range(yblocks)] mat0 = mats[0].copy() mat0.zero() h1_mat = df.assemble(df.inner(df.nabla_grad(u), df.nabla_grad(v)) * df.dx) l2_mat = df.assemble(u * v * df.dx) f = df.Constant(1.) * v * df.dx F = df.assemble(f) bc = df.DirichletBC(V, 0., df.DomainBoundary()) for m in mats: bc.zero(m) bc.apply(mat0) bc.apply(h1_mat) bc.apply(F) # wrap everything as a pyMOR model ################################## # FEniCS wrappers from pymor.bindings.fenics import FenicsVectorSpace, FenicsMatrixOperator, FenicsVisualizer # generic pyMOR classes from pymor.models.basic import StationaryModel from pymor.operators.constructions import LincombOperator, VectorOperator from pymor.parameters.functionals import ProjectionParameterFunctional from pymor.parameters.spaces import CubicParameterSpace # define parameter functionals (same as in pymor.analyticalproblems.thermalblock) def parameter_functional_factory(x, y): return ProjectionParameterFunctional(component_name='diffusion', component_shape=(yblocks, xblocks), index=(yblocks - y - 1, x), name=f'diffusion_{x}_{y}') parameter_functionals = tuple(parameter_functional_factory(x, y) for x in range(xblocks) for y in range(yblocks)) # wrap operators ops = [FenicsMatrixOperator(mat0, V, V)] + [FenicsMatrixOperator(m, V, V) for m in mats] op = LincombOperator(ops, (1.,) + parameter_functionals) rhs = VectorOperator(FenicsVectorSpace(V).make_array([F])) h1_product = FenicsMatrixOperator(h1_mat, V, V, name='h1_0_semi') l2_product = FenicsMatrixOperator(l2_mat, V, V, name='l2') # build model visualizer = FenicsVisualizer(FenicsVectorSpace(V)) parameter_space = CubicParameterSpace(op.parameter_type, 0.1, 1.) fom = StationaryModel(op, rhs, products={'h1_0_semi': h1_product, 'l2': l2_product}, parameter_space=parameter_space, visualizer=visualizer) return fom
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()
v = dolfin.TestFunction(V) u = dolfin.TrialFunction(V) s = dolfin.inner(dolfin.curl(v), dolfin.curl(u))*dolfin.dx t = dolfin.inner(v, u)*dolfin.dx S = dolfin.PETScMatrix() T = dolfin.PETScMatrix() dolfin.assemble(s, tensor=S) dolfin.assemble(t, tensor=T) print(S.size(1)) markers=dolfin.MeshFunction('size_t',mesh,1) markers.set_all(0) dolfin.DomainBoundary().mark(markers,1) electric_wall = dolfin.DirichletBC(V, dolfin.Constant(0.0), markers, 1) electric_wall.apply(S) electric_wall.apply(T) #from scipy.linalg import eig #lambds, vectors=eig(S.array(),T.array()) # Solve the eigensystem esolver = dolfin.SLEPcEigenSolver(S,T) esolver.solve(S.size(1)) res=[esolver.get_eigenpair(i) for i in range(esolver.get_number_converged())]
def setup(self, m, Ms, unit_length=1): self.m = m self.Ms = Ms self.unit_length = unit_length mesh = m.mesh() self.S1 = df.FunctionSpace(mesh, "Lagrange", 1) self.dim = mesh.topology().dim() 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) # we will copy field into this when we need the energy self._H_func = df.Function(self.m.functionspace) 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._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_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']) # 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" # 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 bounday 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() self.mesh = self.m.mesh() self.bmesh = df.BoundaryMesh(self.mesh, 'exterior', False) #self.b2g_map = self.bmesh.vertex_map().array() self._b2g_map = self.bmesh.entity_map(0).array() self.compute_triangle_normal() self.__compute_bsa() fast_sum = FastSum(p=self.p, mac=self.mac, num_limit=self.num_limit, correct_factor=self.correct_factor, type_I=self.type_I) coords = self.bmesh.coordinates() face_nodes = np.array(self.bmesh.cells(), dtype=np.int32) fast_sum.init_mesh(coords, self.t_normals, face_nodes, self.vert_bsa) self.fast_sum = fast_sum self.phi2_b = np.zeros(self.bmesh.num_vertices())