def get_coarse_level_extensions(self, M_fine): if self.verbosity >= 3: print0(pid+" calculating coarse matrices extensions") timer = Timer("Coarse matrices extensions") Mx_fun = Function(self.problem.V_fine) Mx_vec = Mx_fun.vector() M_fine.mult(self.vec_fine, Mx_vec) # M11 xtMx = MPI_sum0( numpy.dot(self.vec_fine.get_local(), Mx_vec.get_local()) ) # Mi1 PtMx_fun = interpolate(Mx_fun, self.problem.V_coarse) PtMx = PtMx_fun.vector().get_local() # M1j if self.problem.sym: PtMtx = PtMx else: self.A_fine.transpmult(self.vec_fine, Mx_vec) PtMx_fun = interpolate(Mx_fun, self.problem.V_coarse) PtMtx = PtMx_fun.vector().get_local() return xtMx, PtMtx, PtMx
def compute_interpolation_error(mesh_resolution=20): # Define domain and mesh a, b = 0, 1 mesh = IntervalMesh(mesh_resolution, a, b) # Define finite element function space p_order = 1 V = FunctionSpace(mesh, "CG", p_order) # Extract vertices of the mesh x = V.tabulate_dof_coordinates() # Note: Not the same as x = mesh.coordinates() (apparently has been re-ordered) # Express the analytical function u = Expression("1 + x[0] * sin(10 * x[0])", degree=5) # Interpolate u onto V and extract the values in the mesh nodes Iu = interpolate(u, V) Iua = Iu.vector().array() # Evaluate u at the mesh vertices Eua = np.empty(len(x)) for i in range(len(x)): Eua[i] = 1 + x[i] * math.sin(10 * x[i]) # Compute max interpolation error in the nodes e = Eua - Iua e_abs = np.absolute(e) error = np.amax(e_abs) return error
def compare_errors(p_order=1): # Express the analytical function u = Expression("1 + sin(10*x[0])", degree=5) mesh_resolutions = [10, 50, 100, 200] projection_errors = [] interpolation_errors = [] for mesh_resolution in mesh_resolutions: # Define mesh mesh = UnitIntervalMesh(mesh_resolution) # Define finite element function space V = FunctionSpace(mesh, "CG", p_order) # Compute projection up = project(u, V) # Compute interpolation ui = interpolate(u, V) # Compute errors projection_errors.append(compute_error(u, up)) interpolation_errors.append(compute_error(u, ui)) print(projection_errors) print(interpolation_errors)
def compute_error(u1, u2): # Reference mesh mesh_resolution_ref = 500 mesh_ref = UnitIntervalMesh(mesh_resolution_ref) # Reference function space V_ref = FunctionSpace(mesh_ref, "CG", 1) # Evaluate the input functions on the reference mesh Iu1 = interpolate(u1, V_ref) Iu2 = interpolate(u2, V_ref) # Compute the error e = Iu1 - Iu2 error = sqrt(assemble(e * e * dx)) return error
def computeSamples4Level(self, level, numSamples): if numSamples <= 0: return samples = self.y4Level[level] if len(samples) == 0: print("\tSampling {samples} initial samples for level {level}"\ .format(samples = numSamples, level = level)) else: print("\tSampling {samples} additional samples for level {level}"\ .format(samples = numSamples, level = level)) if level == 0: V = self.space4Level[level] for curSample in range(numSamples): if self.adaptiveKL == True: self.problem.sample(nModes = 1 / V.mesh().hmax()) else: self.problem.sample() solution = self.problem.solve(V) samples.append(solution.vector().array()) else: V_fine = self.space4Level[level] V_coarse = self.space4Level[level - 1] for curSample in range(numSamples): if self.adaptiveKL == True: self.problem.sample(nModes = 1 / V_fine.mesh().hmax()) else: self.problem.sample() solutionFine = self.problem.solve(V_fine) solutionCoarse = self.problem.solve(V_coarse) y = solutionFine.vector().array() - interpolate(solutionCoarse, V_fine).vector().array() samples.append(y)
def updateStatistics(self): for curLevel in range(len(self.space4Level)): samples = self.y4Level[curLevel] self.variance4level[curLevel] = np.var(samples, 0) compCost = self.space4Level[curLevel].dim() ** 2 / 1000. # Simple for uniform meshes # optSamples = self.constCompCost * np.sqrt( # np.sqrt(np.sqrt(np.mean(np.abs(self.variance4level[curLevel]))) / compCost)) # Same but for general meshes space = self.space4Level[curLevel] domainArea = assemble(interpolate(Constant(1), space) * dx) varianceMean = Function(space) varianceMean.vector().set_local(np.abs(self.variance4level[curLevel])) varianceIntMean = np.sqrt(assemble(varianceMean * dx) / domainArea) optSamples = self.constCompCost * np.sqrt(np.sqrt( varianceIntMean / compCost)) # Alernate from ??? # l = curLevel + 2 # maxL = len(self.space4Level) + 1 # epsOptSamples = 0.1 # optSamples = l ** (2 + 2 * epsOptSamples) * 2 ** (2 * (maxL - l)) self.optNumSamples4Level[curLevel] = np.rint(optSamples).astype(int) self.compCost4lvl[-1] = sum(list(len(samples) * (space.dim() ** 2) for (space, samples) in zip(self.space4Level, self.y4Level)))
def computeError4level(self, meanApprox4lvl, lastSpace, meanExact = None): if meanExact == None: solMesh = lastSpace.mesh() solFamily = lastSpace.ufl_element().family() solDegree = lastSpace.ufl_element().degree() refSpace = FunctionSpace(refine(refine(solMesh)), solFamily, solDegree) meanExact = self.solveMean(refSpace) refSpace = meanExact.function_space() error4lvl = list( np.sqrt(assemble( (project(meanApprox, refSpace) - interpolate(meanExact, refSpace)) ** 2 * dx )) for meanApprox in meanApprox4lvl) return error4lvl
def prolongate(self): if self.verbosity >= 2: print0(pid+" Prolongating") timer = Timer("Prolongating") if comm.rank == 0: self.v_coarse_with_all_dofs[self.indofs] = self.v_coarse[1:] # 0 Dirichlet BC are automatic by the initial setting in the constructor x_coarse = self.vec_coarse.get_local() comm.Scatterv([self.v_coarse_with_all_dofs, (self.local_ndof_all_proc, None), MPI_type(self.v_coarse_with_all_dofs)], [x_coarse, MPI_type(x_coarse)]) self.vec_coarse.set_local(x_coarse) self.vec_coarse.apply("insert") self.vec_coarse.update_ghost_values() self.sln_fine = interpolate(self.sln_coarse, self.problem.V_fine) v1 = comm.bcast(self.v_coarse[0], root=0) self.vec_fine.axpy(v1, self.vec_fine)
def errornorm(u, uh, norm_type="l2", degree_rise=3, mesh=None): """ Compute and return the error :math:`e = u - u_h` in the given norm. *Arguments* u, uh :py:class:`Functions <dolfin.functions.function.Function>` norm_type Type of norm. The :math:`L^2` -norm is default. For other norms, see :py:func:`norm <dolfin.fem.norms.norm>`. degree_rise The number of degrees above that of u_h used in the interpolation; i.e. the degree of piecewise polynomials used to approximate :math:`u` and :math:`u_h` will be the degree of :math:`u_h` + degree_raise. mesh Optional :py:class:`Mesh <dolfin.cpp.Mesh>` on which to compute the error norm. In simple cases, one may just define .. code-block:: python e = u - uh and evalute for example the square of the error in the :math:`L^2` -norm by .. code-block:: python assemble(e*e*dx(), mesh) However, this is not stable w.r.t. round-off errors considering that the form compiler may expand the expression above to:: e*e*dx() = u*u*dx() - 2*u*uh*dx() + uh*uh*dx() and this might get further expanded into thousands of terms for higher order elements. Thus, the error will be evaluated by adding a large number of terms which should sum up to something close to zero (if the error is small). This module computes the error by first interpolating both :math:`u` and :math:`u_h` to a common space (of high accuracy), then subtracting the two fields (which is easy since they are expressed in the same basis) and then evaluating the integral. """ # Check argument if not isinstance(u, cpp.GenericFunction): cpp.dolfin_error("norms.py", "compute error norm", "Expecting a Function or Expression for u") if not isinstance(uh, cpp.Function): cpp.dolfin_error("norms.py", "compute error norm", "Expecting a Function for uh") # Get mesh if isinstance(u, Function) and mesh is None: mesh = u.function_space().mesh() if isinstance(uh, Function) and mesh is None: mesh = uh.function_space().mesh() if mesh is None: cpp.dolfin_error("norms.py", "compute error norm", "Missing mesh") # Get rank if not u.value_rank() == uh.value_rank(): cpp.dolfin_error("norms.py", "compute error norm", "Value ranks don't match") rank = u.value_rank() # Check that uh is associated with a finite element if uh.ufl_element().degree() is None: cpp.dolfin_error("norms.py", "compute error norm", "Function uh must have a finite element") # Degree for interpolation space. Raise degree with respect to uh. degree = uh.ufl_element().degree() + degree_rise # Check degree of 'exact' solution u degree_u = u.ufl_element().degree() if degree_u is not None and degree_u < degree: cpp.warning("Degree of exact solution may be inadequate for accurate result in errornorm.") # Create function space if rank == 0: V = FunctionSpace(mesh, "Discontinuous Lagrange", degree) elif rank == 1: V = VectorFunctionSpace(mesh, "Discontinuous Lagrange", degree) else: cpp.dolfin_error("norms.py", "compute error norm", "Can't handle elements of rank %d" % rank) # Interpolate functions into finite element space pi_u = interpolate(u, V) pi_uh = interpolate(uh, V) # Compute the difference e = Function(V) e.assign(pi_u) e.vector().axpy(-1.0, pi_uh.vector()) # Compute norm return norm(e, norm_type=norm_type, mesh=mesh)
def errornorm(u, uh, norm_type="l2", degree_rise=3, mesh=None): """ Compute and return the error :math:`e = u - u_h` in the given norm. *Arguments* u, uh :py:class:`Functions <dolfin.functions.function.Function>` norm_type Type of norm. The :math:`L^2` -norm is default. For other norms, see :py:func:`norm <dolfin.fem.norms.norm>`. degree_rise The number of degrees above that of u_h used in the interpolation; i.e. the degree of piecewise polynomials used to approximate :math:`u` and :math:`u_h` will be the degree of :math:`u_h` + degree_raise. mesh Optional :py:class:`Mesh <dolfin.cpp.Mesh>` on which to compute the error norm. In simple cases, one may just define .. code-block:: python e = u - uh and evalute for example the square of the error in the :math:`L^2` -norm by .. code-block:: python assemble(e**2*dx(mesh)) However, this is not stable w.r.t. round-off errors considering that the form compiler may expand(#) the expression above to:: e**2*dx = u**2*dx - 2*u*uh*dx + uh**2*dx and this might get further expanded into thousands of terms for higher order elements. Thus, the error will be evaluated by adding a large number of terms which should sum up to something close to zero (if the error is small). This module computes the error by first interpolating both :math:`u` and :math:`u_h` to a common space (of high accuracy), then subtracting the two fields (which is easy since they are expressed in the same basis) and then evaluating the integral. (#) If using the tensor representation optimizations. The quadrature represenation does not suffer from this problem. """ # Check argument # if not isinstance(u, cpp.function.GenericFunction): # cpp.dolfin_error("norms.py", # "compute error norm", # "Expecting a Function or Expression for u") # if not isinstance(uh, cpp.function.Function): # cpp.dolfin_error("norms.py", # "compute error norm", # "Expecting a Function for uh") # Get mesh if isinstance(u, cpp.function.Function) and mesh is None: mesh = u.function_space().mesh() if isinstance(uh, cpp.function.Function) and mesh is None: mesh = uh.function_space().mesh() if hasattr(uh, "_cpp_object") and mesh is None: mesh = uh._cpp_object.function_space().mesh() if hasattr(u, "_cpp_object") and mesh is None: mesh = u._cpp_object.function_space().mesh() if mesh is None: cpp.dolfin_error("norms.py", "compute error norm", "Missing mesh") # Get rank if not u.ufl_shape == uh.ufl_shape: cpp.dolfin_error("norms.py", "compute error norm", "Value shapes don't match") shape = u.ufl_shape rank = len(shape) # Check that uh is associated with a finite element if uh.ufl_element().degree() is None: cpp.dolfin_error("norms.py", "compute error norm", "Function uh must have a finite element") # Degree for interpolation space. Raise degree with respect to uh. degree = uh.ufl_element().degree() + degree_rise # Check degree of 'exact' solution u degree_u = u.ufl_element().degree() if degree_u is not None and degree_u < degree: cpp.warning("Degree of exact solution may be inadequate for accurate result in errornorm.") # Create function space if rank == 0: V = FunctionSpace(mesh, "Discontinuous Lagrange", degree) elif rank == 1: V = VectorFunctionSpace(mesh, "Discontinuous Lagrange", degree, dim=shape[0]) elif rank > 1: V = TensorFunctionSpace(mesh, "Discontinuous Lagrange", degree, shape=shape) # Interpolate functions into finite element space pi_u = interpolate(u, V) pi_uh = interpolate(uh, V) # Compute the difference e = Function(V) e.assign(pi_u) e.vector().axpy(-1.0, pi_uh.vector()) # Compute norm return norm(e, norm_type=norm_type, mesh=mesh)
def r2_errornorm(u, uh, norm_type="l2", degree_rise=3, mesh=None ): """ This function is a modification of FEniCS's built-in errornorm function that adopts the :math:`r^2dr` measure as opposed to the standard Cartesian :math:`dx` measure. For documentation and usage, see the original module <https://bitbucket.org/fenics-project/dolfin/src/master/python/dolfin/fem/norms.py>_. """ # Get mesh if isinstance(u, cpp.function.Function) and mesh is None: mesh = u.function_space().mesh() if isinstance(uh, cpp.function.Function) and mesh is None: mesh = uh.function_space().mesh() # if isinstance(uh, MultiMeshFunction) and mesh is None: # mesh = uh.function_space().multimesh() if hasattr(uh, "_cpp_object") and mesh is None: mesh = uh._cpp_object.function_space().mesh() if hasattr(u, "_cpp_object") and mesh is None: mesh = u._cpp_object.function_space().mesh() if mesh is None: raise RuntimeError("Cannot compute error norm. Missing mesh.") # Get rank if not u.ufl_shape == uh.ufl_shape: raise RuntimeError("Cannot compute error norm. Value shapes do not match.") shape = u.ufl_shape rank = len(shape) # Check that uh is associated with a finite element if uh.ufl_element().degree() is None: raise RuntimeError("Cannot compute error norm. Function uh must have a finite element.") # Degree for interpolation space. Raise degree with respect to uh. degree = uh.ufl_element().degree() + degree_rise # Check degree of 'exact' solution u degree_u = u.ufl_element().degree() if degree_u is not None and degree_u < degree: cpp.warning("Degree of exact solution may be inadequate for accurate result in errornorm.") # Create function space if rank == 0: V = FunctionSpace(mesh, "Discontinuous Lagrange", degree) elif rank == 1: V = VectorFunctionSpace(mesh, "Discontinuous Lagrange", degree, dim=shape[0]) elif rank > 1: V = TensorFunctionSpace(mesh, "Discontinuous Lagrange", degree, shape=shape) # Interpolate functions into finite element space pi_u = interpolate(u, V) pi_uh = interpolate(uh, V) # Compute the difference e = Function(V) e.assign(pi_u) e.vector().axpy(-1.0, pi_uh.vector()) # Compute norm return r2_norm(e, func_degree=degree, norm_type=norm_type, mesh=mesh )
def rD_errornorm(u, uh, D=None, func_degree=None, norm_type="l2", degree_rise=3, mesh=None): r""" This function is a modification of FEniCS's built-in errornorm function to adopt the :math:`r^2dr` measure as opposed to the standard Cartesian :math:`dx` one. For documentation and usage, see the `standard module <https://github.com/FEniCS/dolfin/blob/master/site-packages/dolfin/fem/norms.py>`_. Also see :func:`rD_norm`. """ # Check argument if not isinstance(u, cpp.GenericFunction): cpp.dolfin_error("norms.py", "compute error norm", "Expecting a Function or Expression for u") if not isinstance(uh, cpp.Function): cpp.dolfin_error("norms.py", "compute error norm", "Expecting a Function for uh") # Get mesh if isinstance(u, Function) and mesh is None: mesh = u.function_space().mesh() if isinstance(uh, Function) and mesh is None: mesh = uh.function_space().mesh() if mesh is None: cpp.dolfin_error("norms.py", "compute error norm", "Missing mesh") # Get rank if not u.ufl_shape == uh.ufl_shape: cpp.dolfin_error("norms.py", "compute error norm", "Value shapes don't match") shape = u.ufl_shape rank = len(shape) # Check that uh is associated with a finite element if uh.ufl_element().degree() is None: cpp.dolfin_error("norms.py", "compute error norm", "Function uh must have a finite element") # Degree for interpolation space. Raise degree with respect to uh. degree = uh.ufl_element().degree() + degree_rise # Check degree of 'exact' solution u degree_u = u.ufl_element().degree() if degree_u is not None and degree_u < degree: cpp.warning( "Degree of exact solution may be inadequate for accurate result in errornorm." ) # Create function space if rank == 0: V = FunctionSpace(mesh, "Discontinuous Lagrange", degree) elif rank == 1: V = VectorFunctionSpace(mesh, "Discontinuous Lagrange", degree, dim=shape[0]) elif rank > 1: V = TensorFunctionSpace(mesh, "Discontinuous Lagrange", degree, shape=shape) # Interpolate functions into finite element space pi_u = interpolate(u, V) pi_uh = interpolate(uh, V) # Compute the difference e = Function(V) e.assign(pi_u) e.vector().axpy(-1.0, pi_uh.vector()) # Compute norm return rD_norm(e, D, func_degree=func_degree, norm_type=norm_type, mesh=mesh)
def errornorm(u, uh, norm_type="l2", degree_rise=3, mesh=None): """ Compute and return the error :math:`e = u - u_h` in the given norm. *Arguments* u, uh :py:class:`Functions <dolfin.functions.function.Function>` norm_type Type of norm. The :math:`L^2` -norm is default. For other norms, see :py:func:`norm <dolfin.fem.norms.norm>`. degree_rise The number of degrees above that of u_h used in the interpolation; i.e. the degree of piecewise polynomials used to approximate :math:`u` and :math:`u_h` will be the degree of :math:`u_h` + degree_raise. mesh Optional :py:class:`Mesh <dolfin.cpp.Mesh>` on which to compute the error norm. In simple cases, one may just define .. code-block:: python e = u - uh and evalute for example the square of the error in the :math:`L^2` -norm by .. code-block:: python assemble(e**2*dx(mesh)) However, this is not stable w.r.t. round-off errors considering that the form compiler may expand(#) the expression above to:: e**2*dx = u**2*dx - 2*u*uh*dx + uh**2*dx and this might get further expanded into thousands of terms for higher order elements. Thus, the error will be evaluated by adding a large number of terms which should sum up to something close to zero (if the error is small). This module computes the error by first interpolating both :math:`u` and :math:`u_h` to a common space (of high accuracy), then subtracting the two fields (which is easy since they are expressed in the same basis) and then evaluating the integral. (#) If using the tensor representation optimizations. The quadrature represenation does not suffer from this problem. """ # Check argument # if not isinstance(u, cpp.function.GenericFunction): # cpp.dolfin_error("norms.py", # "compute error norm", # "Expecting a Function or Expression for u") # if not isinstance(uh, cpp.function.Function): # cpp.dolfin_error("norms.py", # "compute error norm", # "Expecting a Function for uh") # Get mesh if isinstance(u, cpp.function.Function) and mesh is None: mesh = u.function_space().mesh() if isinstance(uh, cpp.function.Function) and mesh is None: mesh = uh.function_space().mesh() if isinstance(uh, MultiMeshFunction) and mesh is None: mesh = uh.function_space().multimesh() if hasattr(uh, "_cpp_object") and mesh is None: mesh = uh._cpp_object.function_space().mesh() if hasattr(u, "_cpp_object") and mesh is None: mesh = u._cpp_object.function_space().mesh() if mesh is None: raise RuntimeError("Cannot compute error norm. Missing mesh.") # Get rank if not u.ufl_shape == uh.ufl_shape: raise RuntimeError("Cannot compute error norm. Value shapes do not match.") shape = u.ufl_shape rank = len(shape) # Check that uh is associated with a finite element if uh.ufl_element().degree() is None: raise RuntimeError("Cannot compute error norm. Function uh must have a finite element.") # Degree for interpolation space. Raise degree with respect to uh. degree = uh.ufl_element().degree() + degree_rise # Check degree of 'exact' solution u degree_u = u.ufl_element().degree() if degree_u is not None and degree_u < degree: cpp.warning("Degree of exact solution may be inadequate for accurate result in errornorm.") # Create function space if isinstance(uh, MultiMeshFunction): function_space = MultiMeshFunctionSpace vector_space = MultiMeshVectorFunctionSpace tensor_space = MultiMeshTensorFunctionSpace func = MultiMeshFunction else: function_space = FunctionSpace vector_space = VectorFunctionSpace tensor_space = TensorFunctionSpace func = Function if rank == 0: V = function_space(mesh, "Discontinuous Lagrange", degree) elif rank == 1: V = vector_space(mesh, "Discontinuous Lagrange", degree, dim=shape[0]) elif rank > 1: V = tensor_space(mesh, "Discontinuous Lagrange", degree, shape=shape) # Interpolate functions into finite element space pi_u = interpolate(u, V) pi_uh = interpolate(uh, V) # Compute the difference e = func(V) e.assign(pi_u) e.vector().axpy(-1.0, pi_uh.vector()) # Compute norm return norm(e, norm_type=norm_type, mesh=mesh)
from dolfin import IntervalMesh from dolfin.fem.interpolation import interpolate from dolfin.functions import FunctionSpace, TestFunction, Function, Expression # Define domain and mesh a, b = 0, 1 mesh_resolution = 20 mesh = IntervalMesh(mesh_resolution, a, b) # Define finite element function space p_order = 1 V = FunctionSpace(mesh, "CG", p_order) # Interpolate function u = Expression("1 + 4.0 * x[0] * x[0] - 5.0 * x[0] * x[0] * x[0]", degree=5) Iu = interpolate(u, V) Iua = Iu.vector().array() print(Iua.max())