def errornorm(u, uh, norm_type="L2", degree_rise=3, mesh=None): """Compute the error :math:`e = u - u_h` in the specified norm. :arg u: a :class:`.Function` containing an "exact" solution :arg uh: a :class:`.Function` containing the approximate solution :arg norm_type: the type of norm to compute, see :func:`.norm` for details of supported norm types. :arg degree_rise: increase in polynomial degree to use as the approximation space for computing the error. :arg mesh: an optional mesh on which to compute the error norm (currently ignored). This function works by :func:`.project`\ing ``u`` and ``uh`` into a space of degree ``degree_rise`` higher than the degree of ``uh`` and computing the error there. """ urank = len(u.ufl_shape) uhrank = len(uh.ufl_shape) rank = urank if urank != uhrank: raise RuntimeError("Mismatching rank between u and uh") degree = uh.function_space().ufl_element().degree() if isinstance(degree, tuple): degree = max(degree) + degree_rise else: degree += degree_rise # The exact solution might be an expression, in which case this test is irrelevant. if isinstance(u, function.Function): degree_u = u.function_space().ufl_element().degree() if degree > degree_u: warning("Degree of exact solution less than approximation degree") mesh = uh.function_space().mesh() if rank == 0: V = functionspace.FunctionSpace(mesh, 'DG', degree) elif rank == 1: V = functionspace.VectorFunctionSpace(mesh, 'DG', degree, dim=u.ufl_shape[0]) else: raise RuntimeError( "Don't know how to compute error norm for tensor valued functions") u_ = projection.project(u, V) uh_ = projection.project(uh, V) uh_ -= u_ return norm(uh_, norm_type=norm_type, mesh=mesh)
def errornorm(u, uh, norm_type="L2", degree_rise=3, mesh=None): """Compute the error :math:`e = u - u_h` in the specified norm. :arg u: a :class:`.Function` containing an "exact" solution :arg uh: a :class:`.Function` containing the approximate solution :arg norm_type: the type of norm to compute, see :func:`.norm` for details of supported norm types. :arg degree_rise: increase in polynomial degree to use as the approximation space for computing the error. :arg mesh: an optional mesh on which to compute the error norm (currently ignored). This function works by :func:`.project`\ing ``u`` and ``uh`` into a space of degree ``degree_rise`` higher than the degree of ``uh`` and computing the error there. """ urank = len(u.ufl_shape) uhrank = len(uh.ufl_shape) rank = urank if urank != uhrank: raise RuntimeError("Mismatching rank between u and uh") degree = uh.function_space().ufl_element().degree() if isinstance(degree, tuple): degree = max(degree) + degree_rise else: degree += degree_rise # The exact solution might be an expression, in which case this test is irrelevant. if isinstance(u, function.Function): degree_u = u.function_space().ufl_element().degree() if degree > degree_u: warning("Degree of exact solution less than approximation degree") mesh = uh.function_space().mesh() if rank == 0: V = functionspace.FunctionSpace(mesh, 'DG', degree) elif rank == 1: V = functionspace.VectorFunctionSpace(mesh, 'DG', degree, dim=u.ufl_shape[0]) else: raise RuntimeError("Don't know how to compute error norm for tensor valued functions") u_ = projection.project(u, V) uh_ = projection.project(uh, V) uh_ -= u_ return norm(uh_, norm_type=norm_type, mesh=mesh)
def function_arg(self, g): '''Set the value of this boundary condition.''' if isinstance(g, function.Function) and g.function_space() != self._function_space: raise RuntimeError("%r is defined on incompatible FunctionSpace!" % g) if not isinstance(g, expression.Expression): try: # Bare constant? as_ufl(g) except UFLException: try: # List of bare constants? Convert to UFL expression g = as_ufl(as_tensor(g)) if g.ufl_shape != self._function_space.shape: raise ValueError("%r doesn't match the shape of the function space." % (g,)) except UFLException: raise ValueError("%r is not a valid DirichletBC expression" % (g,)) if isinstance(g, expression.Expression) or has_type(as_ufl(g), SpatialCoordinate): if isinstance(g, expression.Expression): self._expression_state = g._state try: g = function.Function(self._function_space).interpolate(g) # Not a point evaluation space, need to project onto V except NotImplementedError: g = projection.project(g, self._function_space) self._function_arg = g self._currently_zeroed = False
def project(self, b, *args, **kwargs): """Project ``b`` onto ``self``. ``b`` must be a :class:`Function` or an :class:`.Expression`. This is equivalent to ``project(b, self)``. Any of the additional arguments to :func:`~firedrake.projection.project` may also be passed, and they will have their usual effect. """ from firedrake import projection return projection.project(b, self, *args, **kwargs)
def initialize(self, obj): if complex_mode: raise NotImplementedError( "HypreAMS preconditioner not yet implemented in complex mode") Citations().register("Kolev2009") A, P = obj.getOperators() prefix = obj.getOptionsPrefix() V = get_function_space(obj.getDM()) mesh = V.mesh() family = str(V.ufl_element().family()) degree = V.ufl_element().degree() if family != 'Nedelec 1st kind H(curl)' or degree != 1: raise ValueError( "Hypre AMS requires lowest order Nedelec elements! (not %s of degree %d)" % (family, degree)) P1 = FunctionSpace(mesh, "Lagrange", 1) G = Interpolator(grad(TestFunction(P1)), V).callable().handle pc = PETSc.PC().create(comm=obj.comm) pc.incrementTabLevel(1, parent=obj) pc.setOptionsPrefix(prefix + "hypre_ams_") pc.setOperators(A, P) pc.setType('hypre') pc.setHYPREType('ams') pc.setHYPREDiscreteGradient(G) zero_beta = PETSc.Options(prefix).getBool( "pc_hypre_ams_zero_beta_poisson", default=False) if zero_beta: pc.setHYPRESetBetaPoissonMatrix(None) # Build constants basis for the Nedelec space cvecs = [] for i in range(mesh.cell_dimension()): direction = [ 1.0 if i == j else 0.0 for j in range(mesh.cell_dimension()) ] c = project(Constant(direction), V) with c.vector().dat.vec_ro as cvec: cvecs.append(cvec) pc.setHYPRESetEdgeConstantVectors(*cvecs) pc.setUp() self.pc = pc
def SubDomainData(geometric_expr): """Creates a subdomain data object from a boolean-valued UFL expression. The result can be attached as the subdomain_data field of a :class:`ufl.Measure`. For example: x = mesh.coordinates sd = SubDomainData(x[0] < 0.5) assemble(f*dx(subdomain_data=sd)) """ import firedrake.functionspace as functionspace import firedrake.projection as projection # Find domain from expression m = geometric_expr.ufl_domain() # Find selected cells fs = functionspace.FunctionSpace(m, 'DG', 0) f = projection.project(ufl.conditional(geometric_expr, 1, 0), fs) # Create cell subset indices, = np.nonzero(f.dat.data_ro_with_halos > 0.5) return op2.Subset(m.cell_set, indices)
def __lshift__(self, data): """It allows file << function syntax for writing data out to disk. In the case of parallel, it would also accept (function, timestep) tuple as an argument. If only function is given, then the timestep will be automatically generated.""" # If parallel, it needs to keep track of its timestep. if MPI.parallel: # if statements to keep the consistency of how to update the # timestep. if isinstance(data, tuple): if self._time_step == -1 or not self._generate_time: function = data[0] self._time_step = data[1] else: raise TypeError("Expected function, got tuple.") else: if self._time_step != -1 and not self._generate_time: raise TypeError("Expected tuple, got function.") function = data self._time_step += 1 self._generate_time = True else: function = data def is_family1(e, family): import ufl.finiteelement.hdivcurl as hc if isinstance(e, (hc.HDiv, hc.HCurl)): return False if e.family() == 'OuterProductElement': if e.degree() == (1, 1): if e._A.family() == family \ and e._B.family() == family: return True elif e.family() == family and e.degree() == 1: return True return False def is_cgN(e): import ufl.finiteelement.hdivcurl as hc if isinstance(e, (hc.HDiv, hc.HCurl)): return False if e.family() == 'OuterProductElement': if e._A.family() in ('Lagrange', 'Q') \ and e._B.family() == 'Lagrange': return True elif e.family() in ('Lagrange', 'Q'): return True return False mesh = function.function_space().mesh() e = function.function_space().ufl_element() if len(e.value_shape()) > 1: raise RuntimeError("Can't output tensor valued functions") ce = mesh.coordinates.function_space().ufl_element() coords_p1 = is_family1(ce, 'Lagrange') or is_family1(ce, 'Q') coords_p1dg = is_family1(ce, 'Discontinuous Lagrange') or is_family1(ce, 'DQ') coords_cgN = is_cgN(ce) function_p1 = is_family1(e, 'Lagrange') or is_family1(e, 'Q') function_p1dg = is_family1(e, 'Discontinuous Lagrange') or is_family1(e, 'DQ') function_cgN = is_cgN(e) project_coords = False project_function = False discontinuous = False # We either output in P1 or P1dg. if coords_cgN and function_cgN: family = 'CG' project_coords = not coords_p1 project_function = not function_p1 else: family = 'DG' project_coords = not coords_p1dg project_function = not function_p1dg discontinuous = True if project_function: if len(e.value_shape()) == 0: Vo = fs.FunctionSpace(mesh, family, 1) elif len(e.value_shape()) == 1: Vo = fs.VectorFunctionSpace(mesh, family, 1, dim=e.value_shape()[0]) else: # Never reached Vo = None if not self._warnings[0]: warning(RED % "*** Projecting output function to %s1", family) self._warnings[0] = True output = projection.project(function, Vo, name=function.name()) else: output = function Vo = output.function_space() if project_coords: Vc = fs.VectorFunctionSpace(mesh, family, 1, dim=mesh._coordinate_fs.dim) if not self._warnings[1]: warning(RED % "*** Projecting coordinates to %s1", family) self._warnings[1] = True coordinates = projection.project(mesh.coordinates, Vc, name=mesh.coordinates.name()) else: coordinates = mesh.coordinates Vc = coordinates.function_space() num_points = Vo.node_count layers = mesh.layers - 1 if isinstance(e.cell(), OuterProductCell) else 1 num_cells = mesh.num_cells() * layers if not isinstance(e.cell(), OuterProductCell) and e.cell().cellname() != "quadrilateral": connectivity = Vc.cell_node_map().values_with_halo.flatten() else: # Connectivity of bottom cell in extruded mesh base = Vc.cell_node_map().values_with_halo if _cells[mesh.ufl_cell()] == hl.VtkQuad: # Quad is # # 1--3 # | | # 0--2 # # needs to be # # 3--2 # | | # 0--1 base = base[:, [0, 2, 3, 1]] points_per_cell = 4 elif _cells[mesh.ufl_cell()] == hl.VtkWedge: # Wedge is # # 5 # /|\ # / | \ # 1----3 # | 4 | # | /\ | # |/ \| # 0----2 # # needs to be # # 5 # /|\ # / | \ # 3----4 # | 2 | # | /\ | # |/ \| # 0----1 # base = base[:, [0, 2, 4, 1, 3, 5]] points_per_cell = 6 elif _cells[mesh.ufl_cell()] == hl.VtkHexahedron: # Hexahedron is # # 5----7 # /| /| # 4----6 | # | 1--|-3 # |/ |/ # 0----2 # # needs to be # # 7----6 # /| /| # 4----5 | # | 3--|-2 # |/ |/ # 0----1 # base = base[:, [0, 2, 3, 1, 4, 6, 7, 5]] points_per_cell = 8 # Repeat up the column connectivity_temp = np.repeat(base, layers, axis=0) if discontinuous: scale = points_per_cell else: scale = 1 offsets = np.arange(layers) * scale # Add offsets going up the column connectivity_temp += np.tile(offsets.reshape(-1, 1), (mesh.num_cells(), 1)) connectivity = connectivity_temp.flatten() if isinstance(output.function_space(), fs.VectorFunctionSpace): tmp = output.dat.data_ro_with_halos vdata = [None]*3 if output.dat.dim[0] == 1: vdata[0] = tmp.flatten() else: for i in range(output.dat.dim[0]): vdata[i] = tmp[:, i].flatten() for i in range(output.dat.dim[0], 3): vdata[i] = np.zeros_like(vdata[0]) data = tuple(vdata) # only for checking large file size flat_data = {function.name(): tmp.flatten()} else: data = output.dat.data_ro_with_halos.flatten() flat_data = {function.name(): data} coordinates = self._fd_to_evtk_coord(coordinates.dat.data_ro_with_halos) cell_types = np.empty(num_cells, dtype="uint8") # Assume that all cells are of same shape. cell_types[:] = _cells[mesh.ufl_cell()].tid p_c = _points_per_cell[mesh.ufl_cell()] # This tells which are the last nodes of each cell. offsets = np.arange(start=p_c, stop=p_c * (num_cells + 1), step=p_c, dtype='int32') large_file_flag = _requiresLargeVTKFileSize("VtkUnstructuredGrid", numPoints=num_points, numCells=num_cells, pointData=flat_data, cellData=None) new_name = self._filename # When vtu file makes part of a parallel process, aggregated by a # pvtu file, the output is : filename_timestep_rank.vtu if MPI.parallel: new_name += "_" + str(self._time_step) + "_" + str(MPI.comm.rank) self._writer = hl.VtkFile( new_name, hl.VtkUnstructuredGrid, large_file_flag) self._writer.openGrid() self._writer.openPiece(ncells=num_cells, npoints=num_points) # openElement allows the stuff in side of the tag <arg></arg> # to be editted. self._writer.openElement("Points") # addData adds the DataArray in the tag <arg1> self._writer.addData("Points", coordinates) self._writer.closeElement("Points") self._writer.openElement("Cells") self._writer.addData("connectivity", connectivity) self._writer.addData("offsets", offsets) self._writer.addData("types", cell_types) self._writer.closeElement("Cells") self._writer.openData("Point", scalars=function.name()) self._writer.addData(function.name(), data) self._writer.closeData("Point") self._writer.closePiece() self._writer.closeGrid() # Create the AppendedData self._writer.appendData(coordinates) self._writer.appendData(connectivity) self._writer.appendData(offsets) self._writer.appendData(cell_types) self._writer.appendData(data) self._writer.save()
def __lshift__(self, data): """It allows file << function syntax for writing data out to disk. In the case of parallel, it would also accept (function, timestep) tuple as an argument. If only function is given, then the timestep will be automatically generated.""" # If parallel, it needs to keep track of its timestep. if MPI.parallel: # if statements to keep the consistency of how to update the # timestep. if isinstance(data, tuple): if self._time_step == -1 or not self._generate_time: function = data[0] self._time_step = data[1] else: raise TypeError("Expected function, got tuple.") else: if self._time_step != -1 and not self._generate_time: raise TypeError("Expected tuple, got function.") function = data self._time_step += 1 self._generate_time = True else: function = data def is_family1(e, family): import ufl.finiteelement.hdivcurl as hc if isinstance(e, (hc.HDivElement, hc.HCurlElement)): return False if e.family() == 'OuterProductElement': if e.degree() == (1, 1): if e._A.family() == family \ and e._B.family() == family: return True elif e.family() == family and e.degree() == 1: return True return False def is_cgN(e): import ufl.finiteelement.hdivcurl as hc if isinstance(e, (hc.HDivElement, hc.HCurlElement)): return False if e.family() == 'OuterProductElement': if e._A.family() in ('Lagrange', 'Q') \ and e._B.family() == 'Lagrange': return True elif e.family() in ('Lagrange', 'Q'): return True return False mesh = function.function_space().mesh() e = function.function_space().ufl_element() if len(e.value_shape()) > 1: raise RuntimeError("Can't output tensor valued functions") ce = mesh.coordinates.function_space().ufl_element() coords_p1 = is_family1(ce, 'Lagrange') or is_family1(ce, 'Q') coords_p1dg = is_family1(ce, 'Discontinuous Lagrange') or is_family1(ce, 'DQ') coords_cgN = is_cgN(ce) function_p1 = is_family1(e, 'Lagrange') or is_family1(e, 'Q') function_p1dg = is_family1(e, 'Discontinuous Lagrange') or is_family1(e, 'DQ') function_cgN = is_cgN(e) project_coords = False project_function = False discontinuous = False # We either output in P1 or P1dg. if coords_cgN and function_cgN: family = 'CG' project_coords = not coords_p1 project_function = not function_p1 else: family = 'DG' project_coords = not coords_p1dg project_function = not function_p1dg discontinuous = True if project_function: if len(e.value_shape()) == 0: Vo = fs.FunctionSpace(mesh, family, 1) elif len(e.value_shape()) == 1: Vo = fs.VectorFunctionSpace(mesh, family, 1, dim=e.value_shape()[0]) else: # Never reached Vo = None if not self._warnings[0]: warning(RED % "*** Projecting output function to %s1", family) self._warnings[0] = True output = projection.project(function, Vo, name=function.name()) else: output = function Vo = output.function_space() if project_coords: Vc = fs.VectorFunctionSpace(mesh, family, 1, dim=mesh._coordinate_fs.dim) if not self._warnings[1]: warning(RED % "*** Projecting coordinates to %s1", family) self._warnings[1] = True coordinates = projection.project(mesh.coordinates, Vc, name=mesh.coordinates.name()) else: coordinates = mesh.coordinates Vc = coordinates.function_space() num_points = Vo.node_count layers = mesh.layers - 1 if isinstance(e.cell(), OuterProductCell) else 1 num_cells = mesh.num_cells() * layers if not isinstance(e.cell(), OuterProductCell) and e.cell().cellname() != "quadrilateral": connectivity = Vc.cell_node_map().values_with_halo.flatten() else: # Connectivity of bottom cell in extruded mesh base = Vc.cell_node_map().values_with_halo if _cells[mesh.ufl_cell()] == hl.VtkQuad: # Quad is # # 1--3 # | | # 0--2 # # needs to be # # 3--2 # | | # 0--1 base = base[:, [0, 2, 3, 1]] points_per_cell = 4 elif _cells[mesh.ufl_cell()] == hl.VtkWedge: # Wedge is # # 5 # /|\ # / | \ # 1----3 # | 4 | # | /\ | # |/ \| # 0----2 # # needs to be # # 5 # /|\ # / | \ # 3----4 # | 2 | # | /\ | # |/ \| # 0----1 # base = base[:, [0, 2, 4, 1, 3, 5]] points_per_cell = 6 elif _cells[mesh.ufl_cell()] == hl.VtkHexahedron: # Hexahedron is # # 5----7 # /| /| # 4----6 | # | 1--|-3 # |/ |/ # 0----2 # # needs to be # # 7----6 # /| /| # 4----5 | # | 3--|-2 # |/ |/ # 0----1 # base = base[:, [0, 2, 3, 1, 4, 6, 7, 5]] points_per_cell = 8 # Repeat up the column connectivity_temp = np.repeat(base, layers, axis=0) if discontinuous: scale = points_per_cell else: scale = 1 offsets = np.arange(layers) * scale # Add offsets going up the column connectivity_temp += np.tile(offsets.reshape(-1, 1), (mesh.num_cells(), 1)) connectivity = connectivity_temp.flatten() if isinstance(output.function_space(), fs.VectorFunctionSpace): tmp = output.dat.data_ro_with_halos vdata = [None]*3 if output.dat.dim[0] == 1: vdata[0] = tmp.flatten() else: for i in range(output.dat.dim[0]): vdata[i] = tmp[:, i].flatten() for i in range(output.dat.dim[0], 3): vdata[i] = np.zeros_like(vdata[0]) data = tuple(vdata) # only for checking large file size flat_data = {function.name(): tmp.flatten()} else: data = output.dat.data_ro_with_halos.flatten() flat_data = {function.name(): data} coordinates = self._fd_to_evtk_coord(coordinates.dat.data_ro_with_halos) cell_types = np.empty(num_cells, dtype="uint8") # Assume that all cells are of same shape. cell_types[:] = _cells[mesh.ufl_cell()].tid p_c = _points_per_cell[mesh.ufl_cell()] # This tells which are the last nodes of each cell. offsets = np.arange(start=p_c, stop=p_c * (num_cells + 1), step=p_c, dtype='int32') large_file_flag = _requiresLargeVTKFileSize("VtkUnstructuredGrid", numPoints=num_points, numCells=num_cells, pointData=flat_data, cellData=None) new_name = self._filename # When vtu file makes part of a parallel process, aggregated by a # pvtu file, the output is : filename_timestep_rank.vtu if MPI.parallel: new_name += "_" + str(self._time_step) + "_" + str(MPI.comm.rank) self._writer = hl.VtkFile( new_name, hl.VtkUnstructuredGrid, large_file_flag) self._writer.openGrid() self._writer.openPiece(ncells=num_cells, npoints=num_points) # openElement allows the stuff in side of the tag <arg></arg> # to be editted. self._writer.openElement("Points") # addData adds the DataArray in the tag <arg1> self._writer.addData("Points", coordinates) self._writer.closeElement("Points") self._writer.openElement("Cells") self._writer.addData("connectivity", connectivity) self._writer.addData("offsets", offsets) self._writer.addData("types", cell_types) self._writer.closeElement("Cells") self._writer.openData("Point", scalars=function.name()) self._writer.addData(function.name(), data) self._writer.closeData("Point") self._writer.closePiece() self._writer.closeGrid() # Create the AppendedData self._writer.appendData(coordinates) self._writer.appendData(connectivity) self._writer.appendData(offsets) self._writer.appendData(cell_types) self._writer.appendData(data) self._writer.save()