def test_average(geometry, mesh): cell = mesh.ufl_cell().cellname() DG1_elt = FiniteElement("DG", cell, 1, variant="equispaced") vec_DG1 = VectorFunctionSpace(mesh, DG1_elt) vec_DG0 = VectorFunctionSpace(mesh, "DG", 0) vec_CG1 = VectorFunctionSpace(mesh, "CG", 1) # We will fill DG1_field with values, and average them to CG_field # First need to put the values into DG0 and then interpolate DG0_field = Function(vec_DG0) DG1_field = Function(vec_DG1) CG_field = Function(vec_CG1) weights = Function(vec_CG1) DG0_field, weights, true_values, CG_index = setup_values( geometry, DG0_field, weights) DG1_field.interpolate(DG0_field) kernel = kernels.Average(vec_CG1) kernel.apply(CG_field, weights, DG1_field) tolerance = 1e-12 if geometry == "1D": assert abs(CG_field.dat.data[CG_index] - true_values) < tolerance elif geometry == "2D": assert abs(CG_field.dat.data[CG_index][0] - true_values[0]) < tolerance assert abs(CG_field.dat.data[CG_index][1] - true_values[1]) < tolerance
def setup_2d_recovery(dirname): L = 100. W = 100. deltax = L / 5. deltay = W / 5. ncolumnsx = int(L / deltax) ncolumnsy = int(W / deltay) mesh = PeriodicRectangleMesh(ncolumnsx, ncolumnsy, L, W, direction='y', quadrilateral=True) x, y = SpatialCoordinate(mesh) # spaces VDG0 = FunctionSpace(mesh, "DG", 0) VCG1 = FunctionSpace(mesh, "CG", 1) VDG1 = FunctionSpace(mesh, "DG", 1) Vu = FunctionSpace(mesh, "RTCF", 1) VuCG1 = VectorFunctionSpace(mesh, "CG", 1) VuDG1 = VectorFunctionSpace(mesh, "DG", 1) # set up initial conditions np.random.seed(0) expr = np.random.randn() + np.random.randn() * x # our actual theta and rho and v rho_CG1_true = Function(VCG1).interpolate(expr) v_CG1_true = Function(VuCG1).interpolate(as_vector([expr, expr])) # make the initial fields by projecting expressions into the lowest order spaces rho_DG0 = Function(VDG0).interpolate(expr) rho_CG1 = Function(VCG1) v_Vu = Function(Vu).project(as_vector([expr, expr])) v_CG1 = Function(VuCG1) # make the recoverers and do the recovery rho_recoverer = Recoverer(rho_DG0, rho_CG1, VDG=VDG1, boundary_method=Boundary_Method.dynamics) v_recoverer = Recoverer(v_Vu, v_CG1, VDG=VuDG1, boundary_method=Boundary_Method.dynamics) rho_recoverer.project() v_recoverer.project() rho_diff = errornorm(rho_CG1, rho_CG1_true) / norm(rho_CG1_true) v_diff = errornorm(v_CG1, v_CG1_true) / norm(v_CG1_true) return (rho_diff, v_diff)
def test_2D_cartesian_recovery(geometry, element, mesh, expr): family = "RTCF" if element == "quadrilateral" else "BDM" # horizontal base spaces cell = mesh.ufl_cell().cellname() # DG1 DG1_elt = FiniteElement("DG", cell, 1, variant="equispaced") DG1 = FunctionSpace(mesh, DG1_elt) vec_DG1 = VectorFunctionSpace(mesh, DG1_elt) # spaces DG0 = FunctionSpace(mesh, "DG", 0) CG1 = FunctionSpace(mesh, "CG", 1) Vu = FunctionSpace(mesh, family, 1) vec_CG1 = VectorFunctionSpace(mesh, "CG", 1) # our actual theta and rho and v rho_CG1_true = Function(CG1).interpolate(expr) v_CG1_true = Function(vec_CG1).interpolate(as_vector([expr, expr])) # make the initial fields by projecting expressions into the lowest order spaces rho_DG0 = Function(DG0).interpolate(expr) rho_CG1 = Function(CG1) v_Vu = Function(Vu).project(as_vector([expr, expr])) v_CG1 = Function(vec_CG1) # make the recoverers and do the recovery rho_recoverer = Recoverer(rho_DG0, rho_CG1, VDG=DG1, boundary_method=Boundary_Method.dynamics) v_recoverer = Recoverer(v_Vu, v_CG1, VDG=vec_DG1, boundary_method=Boundary_Method.dynamics) rho_recoverer.project() v_recoverer.project() rho_diff = errornorm(rho_CG1, rho_CG1_true) / norm(rho_CG1_true) v_diff = errornorm(v_CG1, v_CG1_true) / norm(v_CG1_true) tolerance = 1e-7 error_message = (""" Incorrect recovery for {variable} with {boundary} boundary method on {geometry} 2D Cartesian plane with {element} elements """) assert rho_diff < tolerance, error_message.format(variable='rho', boundary='dynamics', geometry=geometry, element=element) assert v_diff < tolerance, error_message.format(variable='v', boundary='dynamics', geometry=geometry, element=element)
def PeriodicIntervalMesh(ncells, length): """Generate a periodic mesh of an interval. :arg ncells: The number of cells over the interval. :arg length: The length the interval.""" if ncells < 3: raise ValueError("1D periodic meshes with fewer than 3 \ cells are not currently supported") m = CircleManifoldMesh(ncells) coord_fs = VectorFunctionSpace(m, 'DG', 1, dim=1) old_coordinates = m.coordinates new_coordinates = Function(coord_fs) periodic_kernel = """double Y,pi; Y = 0.5*(old_coords[0][1]-old_coords[1][1]); pi=3.141592653589793; for(int i=0;i<2;i++){ new_coords[i][0] = atan2(old_coords[i][1],old_coords[i][0])/pi/2; if(new_coords[i][0]<0.) new_coords[i][0] += 1; if(new_coords[i][0]==0 && Y<0.) new_coords[i][0] = 1.0; new_coords[i][0] *= L[0]; }""" cL = Constant(length) par_loop(periodic_kernel, dx, {"new_coords": (new_coordinates, WRITE), "old_coords": (old_coordinates, READ), "L": (cL, READ)}) return mesh.Mesh(new_coordinates)
def __init__(self, mesh, nu, rho, dt=0.001, verbose=False): self.verbose = verbose self.mesh = mesh self.dt = dt self.nu = nu self.rho = rho self.mu = self.nu * self.rho self.has_nullspace = False self.forcing = Constant((0.0, 0.0, 0.0)) self.V = VectorFunctionSpace(self.mesh, "CG", 2) self.Q = FunctionSpace(self.mesh, "CG", 1) self.W = self.V * self.Q self.solver_parameters = { "mat_type": "aij", "snes_type": "ksponly", "ksp_type": "fgmres", "pc_type": "asm", "pc_asm_type": "restrict", "pc_asm_overlap": 2, "sub_ksp_type": "preonly", "sub_pc_type": "ilu", "sub_pc_factor_levels": 1, } if self.verbose: self.solver_parameters["snes_monitor"] = True self.solver_parameters["ksp_converged_reason"] = True
def test_dg_transport_vector(tmpdir, geometry, equation_form, tracer_setup): setup = tracer_setup(tmpdir, geometry) state = setup.state gdim = state.mesh.geometric_dimension() f_init = as_vector([setup.f_init] * gdim) V = VectorFunctionSpace(state.mesh, "DG", 1) if equation_form == "advective": eqn = AdvectionEquation(state, V, "f", ufamily=setup.family, udegree=setup.degree) else: eqn = ContinuityEquation(state, V, "f", ufamily=setup.family, udegree=setup.degree) state.fields("f").interpolate(f_init) state.fields("u").project(setup.uexpr) transport_schemes = [(eqn, SSPRK3(state))] f_end = as_vector([setup.f_end] * gdim) error = run(state, transport_schemes, setup.tmax, f_end) assert error < setup.tol, \ 'The transport error is greater than the permitted tolerance'
def PeriodicIntervalMesh(ncells, length): """Generate a periodic mesh of an interval. :arg ncells: The number of cells over the interval. :arg length: The length the interval.""" m = CircleManifoldMesh(ncells) coord_fs = VectorFunctionSpace(m, 'DG', 1, dim=1) old_coordinates = Function(m.coordinates) new_coordinates = Function(coord_fs) periodic_kernel = """double Y,pi; Y = 0.5*(old_coords[0][1]-old_coords[1][1]); pi=3.141592653589793; for(int i=0;i<2;i++){ new_coords[i][0] = atan2(old_coords[i][1],old_coords[i][0])/pi/2; if(new_coords[i][0]<0.) new_coords[i][0] += 1; if(new_coords[i][0]==0 && Y<0.) new_coords[i][0] = 1.0; new_coords[i][0] *= L; }""" periodic_kernel = periodic_kernel.replace('L', str(length)) par_loop( periodic_kernel, dx, { "new_coords": (new_coordinates, WRITE), "old_coords": (old_coordinates, READ) }) m.coordinates = new_coordinates return m
def setup(self, state): if not self._initialised: # check geometric dimension is 3D if state.mesh.geometric_dimension() != 3: raise ValueError( 'Spherical components only work when the geometric dimension is 3!' ) space = FunctionSpace(state.mesh, "CG", 1) super().setup(state, space=space) V = VectorFunctionSpace(state.mesh, "CG", 1) self.x, self.y, self.z = SpatialCoordinate(state.mesh) self.x_hat = Function(V).interpolate( Constant(as_vector([1.0, 0.0, 0.0]))) self.y_hat = Function(V).interpolate( Constant(as_vector([0.0, 1.0, 0.0]))) self.z_hat = Function(V).interpolate( Constant(as_vector([0.0, 0.0, 1.0]))) self.R = sqrt(self.x**2 + self.y**2) # distance from z axis self.r = sqrt(self.x**2 + self.y**2 + self.z**2) # distance from origin self.f = state.fields(self.fname) if np.prod(self.f.ufl_shape) != 3: raise ValueError( 'Components can only be found of a vector function space in 3D.' )
def test_gaussian_elimination(geometry, mesh): cell = mesh.ufl_cell().cellname() DG1_elt = FiniteElement("DG", cell, 1, variant="equispaced") DG1 = FunctionSpace(mesh, DG1_elt) vec_DG1 = VectorFunctionSpace(mesh, DG1_elt) act_coords = Function(vec_DG1) eff_coords = Function(vec_DG1) field_init = Function(DG1) field_true = Function(DG1) field_final = Function(DG1) # We now include things for the num of exterior values, which may be removed DG0 = FunctionSpace(mesh, "DG", 0) num_ext = Function(DG0) num_ext.dat.data[0] = 1.0 # Get initial and true conditions field_init, field_true, act_coords, eff_coords = setup_values( geometry, field_init, field_true, act_coords, eff_coords) kernel = kernels.GaussianElimination(DG1) kernel.apply(field_init, field_final, act_coords, eff_coords, num_ext) tolerance = 1e-12 assert abs(field_true.dat.data[0] - field_final.dat.data[0]) < tolerance assert abs(field_true.dat.data[1] - field_final.dat.data[1]) < tolerance if geometry == "2D": assert abs(field_true.dat.data[2] - field_final.dat.data[2]) < tolerance assert abs(field_true.dat.data[3] - field_final.dat.data[3]) < tolerance
def fdrake_mesh(request): mesh_name = request.param if mesh_name == "FiredrakeUnitIntervalMesh": return UnitIntervalMesh(100) elif mesh_name == "FiredrakeUnitSquareMesh": return UnitSquareMesh(10, 10) elif mesh_name == "FiredrakeUnitSquareMesh-order2": m = UnitSquareMesh(10, 10) fspace = VectorFunctionSpace(m, "CG", 2) coords = Function(fspace).interpolate(SpatialCoordinate(m)) from firedrake.mesh import Mesh return Mesh(coords) elif mesh_name == "FiredrakeUnitCubeMesh": return UnitCubeMesh(5, 5, 5) elif mesh_name not in ("annulus.msh", "blob2d-order1-h4e-2.msh", "blob2d-order1-h6e-2.msh", "blob2d-order1-h8e-2.msh"): raise ValueError("Unexpected value for request.param") # Firedrake can't read in higher order meshes from gmsh, # so we can only use the order1 blobs from firedrake import Mesh fd_mesh = Mesh(mesh_name) fd_mesh.init() return fd_mesh
def __init__(self, mesh, conditions, timestepping, params, output, solver_params): self.timestepping = timestepping self.timestep = timestepping.timestep self.timescale = timestepping.timescale self.params = params if output is None: raise RuntimeError("You must provide a directory name for dumping results") else: self.output = output self.outfile = File(output.dirname) self.dump_count = 0 self.dump_freq = output.dumpfreq self.solver_params = solver_params self.mesh = mesh self.conditions = conditions if conditions.steady_state == True: self.ind = 1 else: self.ind = 1 family = conditions.family self.x, self.y = SpatialCoordinate(mesh) self.n = FacetNormal(mesh) self.V = VectorFunctionSpace(mesh, family, conditions.order + 1) self.U = FunctionSpace(mesh, family, conditions.order + 1) self.U1 = FunctionSpace(mesh, 'DG', conditions.order) self.S = TensorFunctionSpace(mesh, 'DG', conditions.order) self.D = FunctionSpace(mesh, 'DG', 0) self.W1 = MixedFunctionSpace([self.V, self.S]) self.W2 = MixedFunctionSpace([self.V, self.U1, self.U1]) self.W3 = MixedFunctionSpace([self.V, self.S, self.U1, self.U1])
def test_average(geometry, mesh): vec_CG1 = VectorFunctionSpace(mesh, "CG", 1) # We will fill DG_field with values, and average them to CG_field weights = Function(vec_CG1) true_values = Function(vec_CG1) true_values = setup_values(geometry, true_values) kernel = kernels.AverageWeightings(vec_CG1) kernel.apply(weights) tolerance = 1e-12 if geometry == "1D": for i, (weight, true) in enumerate( zip(weights.dat.data[:], true_values.dat.data[:])): assert abs(weight - true ) < tolerance, "Weight not correct at position %i" % i elif geometry == "2D": for i, (weight, true) in enumerate( zip(weights.dat.data[:], true_values.dat.data[:])): for weight_j, true_j in zip(weight, true): assert abs( weight_j - true_j ) < tolerance, "Weight not correct at position %i" % i
def to_2nd_order(mesh, circle_bdy_id=None, rad=1.0): # make new coordinates function V = VectorFunctionSpace(mesh, 'CG', 2) new_coordinates = project(mesh.coordinates, V) # If we have a circle, move any nodes on the circle bdy # onto the circle. Note circle MUST be centered at origin if circle_bdy_id is not None: nodes_on_circle = V.boundary_nodes(circle_bdy_id, 'geometric') #Force all cell nodes to have given radius :arg:`rad` for node in nodes_on_circle: scale = rad / la.norm(new_coordinates.dat.data[node]) new_coordinates.dat.data[node] *= scale # Make a new mesh with given coordinates return Mesh(new_coordinates)
def meshcoords(mesh, fs): "shared routine for creating fem coordinates" W = VectorFunctionSpace(mesh, fs.ufl_element()) X = interpolate(mesh.coordinates, W) meshcoords = X.vector().gather() return meshcoords
def PeriodicIntervalMesh(ncells, length, comm=COMM_WORLD): """Generate a periodic mesh of an interval. :arg ncells: The number of cells over the interval. :arg length: The length the interval. :kwarg comm: Optional communicator to build the mesh on (defaults to COMM_WORLD). """ if ncells < 3: raise ValueError("1D periodic meshes with fewer than 3 \ cells are not currently supported") m = CircleManifoldMesh(ncells, comm=comm) coord_fs = VectorFunctionSpace(m, 'DG', 1, dim=1) old_coordinates = m.coordinates new_coordinates = Function(coord_fs) periodic_kernel = """ const double pi = 3.141592653589793; const double eps = 1e-12; double a = atan2(old_coords[0][1], old_coords[0][0]) / (2*pi); double b = atan2(old_coords[1][1], old_coords[1][0]) / (2*pi); int swap = 0; if ( a >= b ) { const double tmp = b; b = a; a = tmp; swap = 1; } if ( fabs(b) < eps && a < -eps ) { b = 1.0; } if ( a < -eps ) { a += 1; } if ( b < -eps ) { b += 1; } if ( swap ) { const double tmp = b; b = a; a = tmp; } new_coords[0][0] = a * L[0]; new_coords[1][0] = b * L[0]; """ cL = Constant(length) par_loop( periodic_kernel, dx, { "new_coords": (new_coordinates, WRITE), "old_coords": (old_coordinates, READ), "L": (cL, READ) }) return mesh.Mesh(new_coordinates)
def get_latlon_mesh(mesh): """Build 2D projected mesh of spherical mesh""" crds_orig = mesh.coordinates mesh_dg_fs = VectorFunctionSpace(mesh, "DG", 1) crds_dg = Function(mesh_dg_fs) crds_latlon = Function(mesh_dg_fs) par_loop( """ for (int i=0; i<3; i++) { for (int j=0; j<3; j++) { dg[i][j] = cg[i][j]; } } """, dx, { 'dg': (crds_dg, WRITE), 'cg': (crds_orig, READ) }) # lat-lon 'x' = atan2(y, x) crds_latlon.dat.data[:, 0] = arctan2(crds_dg.dat.data[:, 1], crds_dg.dat.data[:, 0]) # lat-lon 'y' = asin(z/sqrt(x^2 + y^2 + z^2)) crds_latlon.dat.data[:, 1] = (arcsin( crds_dg.dat.data[:, 2] / np_sqrt(crds_dg.dat.data[:, 0]**2 + crds_dg.dat.data[:, 1]**2 + crds_dg.dat.data[:, 2]**2))) crds_latlon.dat.data[:, 2] = 0.0 kernel = op2.Kernel( """ #define PI 3.141592653589793 #define TWO_PI 6.283185307179586 void splat_coords(double **coords) { double diff0 = (coords[0][0] - coords[1][0]); double diff1 = (coords[0][0] - coords[2][0]); double diff2 = (coords[1][0] - coords[2][0]); if (fabs(diff0) > PI || fabs(diff1) > PI || fabs(diff2) > PI) { const int sign0 = coords[0][0] < 0 ? -1 : 1; const int sign1 = coords[1][0] < 0 ? -1 : 1; const int sign2 = coords[2][0] < 0 ? -1 : 1; if (sign0 < 0) { coords[0][0] += TWO_PI; } if (sign1 < 0) { coords[1][0] += TWO_PI; } if (sign2 < 0) { coords[2][0] += TWO_PI; } } } """, "splat_coords") op2.par_loop(kernel, crds_latlon.cell_set, crds_latlon.dat(op2.RW, crds_latlon.cell_node_map())) return Mesh(crds_latlon)
def _prepare_output(self, function, cg): from firedrake import FunctionSpace, VectorFunctionSpace, \ TensorFunctionSpace, Function, Projector, Interpolator name = function.name() # Need to project/interpolate? # If space is linear and continuity of output space matches # continuity of current space, then we can just use the # input function. if is_linear(function.function_space()) and \ is_dg(function.function_space()) == (not cg) and \ is_cg(function.function_space()) == cg: return OFunction(array=get_array(function), name=name, function=function) # OK, let's go and do it. if cg: family = "Lagrange" else: family = "Discontinuous Lagrange" output = self._output_functions.get(function) if output is None: # Build appropriate space for output function. shape = function.ufl_shape if len(shape) == 0: V = FunctionSpace(function.ufl_domain(), family, 1) elif len(shape) == 1: if numpy.prod(shape) > 3: raise ValueError("Can't write vectors with more than 3 components") V = VectorFunctionSpace(function.ufl_domain(), family, 1, dim=shape[0]) elif len(shape) == 2: if numpy.prod(shape) > 9: raise ValueError("Can't write tensors with more than 9 components") V = TensorFunctionSpace(function.ufl_domain(), family, 1, shape=shape) else: raise ValueError("Unsupported shape %s" % (shape, )) output = Function(V) self._output_functions[function] = output if self.project: projector = self._mappers.get(function) if projector is None: projector = Projector(function, output) self._mappers[function] = projector projector.project() else: interpolator = self._mappers.get(function) if interpolator is None: interpolator = Interpolator(function, output) self._mappers[function] = interpolator interpolator.interpolate() return OFunction(array=get_array(output), name=name, function=output)
def elasticity(mesh, degree): V = VectorFunctionSpace(mesh, 'CG', degree) u = TrialFunction(V) v = TestFunction(V) def eps(u): return (grad(u) + grad(u).T) / 2 return inner(eps(v), eps(u)) * dx return inner(grad(u), grad(v)) * dx
def _get_coordinates(mesh): r"""Return the coordinates of a mesh if the mesh is piecewise linear, or interpolate them to piecewise linear if the mesh is curved""" coordinates = mesh.coordinates element = coordinates.function_space().ufl_element() if element.degree() != 1: from firedrake import VectorFunctionSpace, interpolate V = VectorFunctionSpace(mesh, element.family(), 1) coordinates = interpolate(coordinates, V) return coordinates
def test_vector_recovered_space_setup(tmpdir, geometry, tracer_setup): # Make mesh and state using routine from conftest setup = tracer_setup(tmpdir, geometry, degree=0) state = setup.state mesh = state.mesh gdim = state.mesh.geometric_dimension() # Spaces for recovery Vu = state.spaces("HDiv", family=setup.family, degree=setup.degree) if geometry == "slice": VDG1 = state.spaces("DG1_equispaced") Vec_DG1 = VectorFunctionSpace(mesh, VDG1.ufl_element(), name='Vec_DG1') Vec_CG1 = VectorFunctionSpace(mesh, "CG", 1, name='Vec_CG1') Vu_brok = FunctionSpace(mesh, BrokenElement(Vu.ufl_element())) rec_opts = RecoveredOptions(embedding_space=Vec_DG1, recovered_space=Vec_CG1, broken_space=Vu_brok, boundary_method=Boundary_Method.dynamics) else: raise NotImplementedError( f'Recovered spaces for geometry {geometry} have not been implemented' ) # Make equation eqn = AdvectionEquation(state, Vu, "f", ufamily=setup.family, udegree=1) # Initialise fields f_init = as_vector([setup.f_init] * gdim) state.fields("f").project(f_init) state.fields("u").project(setup.uexpr) transport_scheme = [(eqn, SSPRK3(state, options=rec_opts))] f_end = as_vector([setup.f_end] * gdim) # Run and check error error = run(state, transport_scheme, setup.tmax, f_end) assert error < setup.tol, \ 'The transport error is greater than the permitted tolerance'
def correct_eff_coords(eff_coords): """ Correct the effective coordinates calculated by simply averaging which will not be correct at periodic boundaries. :arg eff_coords: the effective coordinates in vec_DG1 space. """ mesh = eff_coords.function_space().mesh() vec_CG1 = VectorFunctionSpace(mesh, "CG", 1) if vec_CG1.extruded: cell = mesh._base_mesh.ufl_cell().cellname() DG1_hori_elt = FiniteElement("DG", cell, 1, variant="equispaced") DG1_vert_elt = FiniteElement("DG", interval, 1, variant="equispaced") DG1_element = TensorProductElement(DG1_hori_elt, DG1_vert_elt) else: cell = mesh.ufl_cell().cellname() DG1_element = FiniteElement("DG", cell, 1, variant="equispaced") vec_DG1 = VectorFunctionSpace(mesh, DG1_element) x = SpatialCoordinate(mesh) if eff_coords.function_space() != vec_DG1: raise ValueError('eff_coords needs to be in the vector DG1 space') # obtain different coords in DG1 DG1_coords = Function(vec_DG1).interpolate(x) CG1_coords_from_DG1 = Function(vec_CG1) averager = Averager(DG1_coords, CG1_coords_from_DG1) averager.project() DG1_coords_from_averaged_CG1 = Function(vec_DG1).interpolate( CG1_coords_from_DG1) DG1_coords_diff = Function(vec_DG1).interpolate( DG1_coords - DG1_coords_from_averaged_CG1) # interpolate coordinates, adjusting those different coordinates adjusted_coords = Function(vec_DG1) adjusted_coords.interpolate(eff_coords + DG1_coords_diff) return adjusted_coords
def setup_IPdiffusion(dirname, vector, DG): dt = 0.01 L = 10. m = PeriodicIntervalMesh(50, L) mesh = ExtrudedMesh(m, layers=50, layer_height=0.2) fieldlist = ['u', 'D'] timestepping = TimesteppingParameters(dt=dt) parameters = CompressibleParameters() output = OutputParameters(dirname=dirname) state = State(mesh, vertical_degree=1, horizontal_degree=1, family="CG", timestepping=timestepping, parameters=parameters, output=output, fieldlist=fieldlist) x = SpatialCoordinate(mesh) if vector: kappa = Constant([[0.05, 0.], [0., 0.05]]) if DG: Space = VectorFunctionSpace(mesh, "DG", 1) else: Space = state.spaces("HDiv") fexpr = as_vector([exp(-(L / 2. - x[0])**2 - (L / 2. - x[1])**2), 0.]) else: kappa = 0.05 if DG: Space = state.spaces("DG") else: Space = state.spaces("HDiv_v") fexpr = exp(-(L / 2. - x[0])**2 - (L / 2. - x[1])**2) f = state.fields("f", Space) try: f.interpolate(fexpr) except NotImplementedError: # finat elements raise NotImplementedError if they don't # advertise a dual for interpolation. f.project(fexpr) mu = 5. f_diffusion = InteriorPenalty(state, f.function_space(), kappa=kappa, mu=mu) diffused_fields = [("f", f_diffusion)] stepper = AdvectionDiffusion(state, diffused_fields=diffused_fields) return stepper
def run_advection_diffusion(tmpdir): # Mesh, state and equation L = 10 mesh = PeriodicIntervalMesh(20, L) dt = 0.02 tmax = 1.0 diffusion_params = DiffusionParameters(kappa=0.75, mu=5) output = OutputParameters(dirname=str(tmpdir), dumpfreq=25) state = State(mesh, dt=dt, output=output) V = state.spaces("DG", "DG", 1) Vu = VectorFunctionSpace(mesh, "CG", 1) equation = AdvectionDiffusionEquation( state, V, "f", Vu=Vu, diffusion_parameters=diffusion_params) problem = [(equation, ((SSPRK3(state), transport), (BackwardEuler(state), diffusion)))] # Initial conditions x = SpatialCoordinate(mesh) xc_init = 0.25 * L xc_end = 0.75 * L umax = 0.5 * L / tmax # Get minimum distance on periodic interval to xc x_init = conditional( sqrt((x[0] - xc_init)**2) < 0.5 * L, x[0] - xc_init, L + x[0] - xc_init) x_end = conditional( sqrt((x[0] - xc_end)**2) < 0.5 * L, x[0] - xc_end, L + x[0] - xc_end) f_init = 5.0 f_end = f_init / 2.0 f_width_init = L / 10.0 f_width_end = f_width_init * 2.0 f_init_expr = f_init * exp(-(x_init / f_width_init)**2) f_end_expr = f_end * exp(-(x_end / f_width_end)**2) state.fields('f').interpolate(f_init_expr) state.fields('u').interpolate(as_vector([Constant(umax)])) f_end = state.fields('f_end', V).interpolate(f_end_expr) # Time stepper timestepper = PrescribedTransport(state, problem) timestepper.run(0, tmax=tmax) error = norm(state.fields('f') - f_end) / norm(f_end) return error
def _prepare_output(self, function, max_elem): from firedrake import FunctionSpace, VectorFunctionSpace, \ TensorFunctionSpace, Function, Projector, Interpolator name = function.name() # Need to project/interpolate? # If space is not the max element, we can do so. if function.ufl_element == max_elem: return OFunction(array=get_array(function), name=name, function=function) # OK, let's go and do it. shape = function.ufl_shape output = self._output_functions.get(function) if output is None: # Build appropriate space for output function. shape = function.ufl_shape if len(shape) == 0: V = FunctionSpace(function.ufl_domain(), max_elem) elif len(shape) == 1: if numpy.prod(shape) > 3: raise ValueError( "Can't write vectors with more than 3 components") V = VectorFunctionSpace(function.ufl_domain(), max_elem, dim=shape[0]) elif len(shape) == 2: if numpy.prod(shape) > 9: raise ValueError( "Can't write tensors with more than 9 components") V = TensorFunctionSpace(function.ufl_domain(), max_elem, shape=shape) else: raise ValueError("Unsupported shape %s" % (shape, )) output = Function(V) self._output_functions[function] = output if self.project: projector = self._mappers.get(function) if projector is None: projector = Projector(function, output) self._mappers[function] = projector projector.project() else: interpolator = self._mappers.get(function) if interpolator is None: interpolator = Interpolator(function, output) self._mappers[function] = interpolator interpolator.interpolate() return OFunction(array=get_array(output), name=name, function=output)
def FunctionSpaceDegreeRaise(V, degree_raise): element = V._ufl_element degree = element.degree(0) space_type = repr(element)[0] element_type = element.family() mesh = V.mesh() if space_type == 'V': V = VectorFunctionSpace(mesh, element_type, degree + degree_raise) elif space_type == 'F': V = FunctionSpace(mesh, element_type, degree + degree_raise) return V
def test_average(geometry, mesh): cell = mesh.ufl_cell().cellname() DG1_elt = FiniteElement("DG", cell, 1, variant="equispaced") vec_DG1 = VectorFunctionSpace(mesh, DG1_elt) vec_CG1 = VectorFunctionSpace(mesh, "CG", 1) # We will fill DG_field with values, and average them to CG_field DG_field = Function(vec_DG1) CG_field = Function(vec_CG1) weights = Function(vec_CG1) DG_field, weights, true_values = setup_values(geometry, DG_field, weights) kernel = kernels.Average(vec_CG1) kernel.apply(CG_field, weights, DG_field) tolerance = 1e-12 if geometry == "1D": assert abs(CG_field.dat.data[1] - true_values) < tolerance elif geometry == "2D": assert abs(CG_field.dat.data[2][0] - true_values[0]) < tolerance assert abs(CG_field.dat.data[2][1] - true_values[1]) < tolerance
def __init__(self): N = 5 self.mesh = UnitSquareMesh(N, N) self.T0 = self.mesh.coordinates.copy(deepcopy=True) # random perturmabion h = 1 / N self.X = SpatialCoordinate(self.mesh) W = VectorFunctionSpace(self.mesh, "CG", 1) self.w = Function(W) vec = self.w.vector() np.random.seed(1) vec.set_local( np.random.uniform(-h / 3., h / 3., size=vec.get_local().shape)) self.name = "missing name" self.bc = None
def set_bdy_as_target(self, bdy_id, method): """ :arg bdy_id: An iterable of subdomain ids as could be accepted as the :arg:`subdomain` in a :class:`DirichletBC` from :mod:`firedrake`. :arg method: A method for determining bdy nodes as in :class:`DirichletBC', either 'geometric' or 'topological' """ mesh = self._function_space.mesh() # if just passed an int, convert to an iterable of ints # so that just one case to deal with if isinstance(bdy_id, int): bdy_id = [bdy_id] target_markers = set(bdy_id) # Check that bdy ids are valid if not target_markers <= set(mesh.exterior_facets.unique_markers): warn("The following bdy ids are not exterior facet ids: %s" % (target_markers - set(mesh.exterior_facets.unique_markers))) if not target_markers & set(mesh.exterior_facets.unique_markers): raise ValueError("No bdy ids are exterior facet ids") self._target_indices = set() for marker in target_markers: self._target_indices |= set( self._function_space.boundary_nodes(marker, method)) self._target_indices = np.array(list(self._target_indices), dtype=np.int32) # Get coordinates of nodes coords = SpatialCoordinate(mesh) function_space_dim = VectorFunctionSpace( mesh, self._function_space.ufl_element().family(), degree=self._function_space.ufl_element().degree()) coords = Function(function_space_dim).interpolate(coords) coords = np.real(coords.dat.data) target_pts = coords[self._target_indices] # change from [nnodes][ambient_dim] to [ambient_dim][nnodes] target_pts = np.transpose(target_pts).copy() self._target = PointsTarget(target_pts)
def prepare_trial(trial, true_sol_name, cl_ctx, queue): tuple_trial = trial_to_tuple(trial) if tuple_trial not in prepared_trials: mesh = trial['mesh'] degree = trial['degree'] kappa = trial['kappa'] function_space = FunctionSpace(mesh, 'CG', degree) vect_function_space = VectorFunctionSpace(mesh, 'CG', degree) true_sol = get_true_sol(function_space, kappa, cl_ctx, queue) true_sol = Function(function_space).interpolate(true_sol) prepared_trials[tuple_trial] = (mesh, function_space, vect_function_space, true_sol, grad(true_sol)) return prepared_trials[tuple_trial]
def get_target_points_and_indices(fspace, boundary_ids): """ Get the points from the function space which lie on the given boundary id as a pytential PointsTarget, and their indices into the firedrake function :return: (target_indices, target_points) """ # if just passed an int, convert to an iterable of ints # so that just one case to deal with if isinstance(boundary_ids, int): boundary_ids = [boundary_ids] target_markers = set(boundary_ids) # Check that bdy ids are valid if not target_markers <= set(fspace.mesh().exterior_facets.unique_markers): raise ValueError( "The following bdy ids are not exterior facet ids: %s" % (target_markers - set(fspace.mesh().exterior_facets.unique_markers))) if not target_markers & set(fspace.mesh().exterior_facets.unique_markers): raise ValueError("No bdy ids are exterior facet ids") target_indices = set() for marker in target_markers: target_indices |= set(fspace.boundary_nodes(marker, 'topological')) target_indices = np.array(list(target_indices), dtype=np.int32) target_indices = np.array(target_indices, dtype=np.int32) # Get coordinates of nodes coords = SpatialCoordinate(fspace.mesh()) function_space_dim = VectorFunctionSpace( fspace.mesh(), fspace.ufl_element().family(), degree=fspace.ufl_element().degree()) coords = Function(function_space_dim).interpolate(coords) coords = np.real(coords.dat.data) target_pts = coords[target_indices] # change from [nnodes][ambient_dim] to [ambient_dim][nnodes] target_pts = np.transpose(target_pts).copy() return (target_indices, PointsTarget(target_pts))