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 _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 _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 _prepare_output(self, function, max_elem): from firedrake import FunctionSpace, VectorFunctionSpace, \ TensorFunctionSpace, Function from tsfc.finatinterface import create_element as create_finat_element name = function.name() # Need to project/interpolate? # If space is not the max element, we must do so. finat_elem = function.function_space().finat_element if finat_elem == create_finat_element(max_elem): return OFunction(array=get_array(function), name=name, function=function) # OK, let's go and do it. # 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) if self.project: output.project(function) else: output.interpolate(function) return OFunction(array=get_array(output), name=name, function=output)
def setup(self, state): if not self._initialised: mesh_dim = state.mesh.geometric_dimension() try: field_dim = state.fields(self.fname).ufl_shape[0] except IndexError: field_dim = 1 shape = (mesh_dim, ) * field_dim space = TensorFunctionSpace(state.mesh, "CG", 1, shape=shape) super().setup(state, space=space) f = state.fields(self.fname) test = TestFunction(space) trial = TrialFunction(space) n = FacetNormal(state.mesh) a = inner(test, trial)*dx L = -inner(div(test), f)*dx if space.extruded: L += dot(dot(test, n), f)*(ds_t + ds_b) prob = LinearVariationalProblem(a, L, self.field) self.solver = LinearVariationalSolver(prob)
def firedrake_fspace(self, shape=None): """ Return a firedrake function space that *self.discr.groups[self.group_nr]* is connected to of the appropriate vector dimension :arg shape: Either *None*, in which case a function space which maps to scalar values is returned, a positive integer *n*, in which case a function space which maps into *\\R^n* is returned, or a tuple of integers defining the shape of values in a tensor function space, in which case a tensor function space is returned :return: A :class:`firedrake.functionspaceimpl.WithGeometry` which corresponds to *self.discr.groups[self.group_nr]* of the appropriate vector dimension :raises TypeError: If *shape* is of the wrong type """ if shape is None: from firedrake import FunctionSpace return FunctionSpace(self._mesh_geometry, self._ufl_element.family(), degree=self._ufl_element.degree()) elif isinstance(shape, int): from firedrake import VectorFunctionSpace return VectorFunctionSpace(self._mesh_geometry, self._ufl_element.family(), degree=self._ufl_element.degree(), dim=shape) elif isinstance(shape, tuple): from firedrake import TensorFunctionSpace return TensorFunctionSpace(self._mesh_geometry, self._ufl_element.family(), degree=self._ufl_element.degree(), shape=shape) else: raise TypeError("'shape' must be *None*, an integer, " " or a tuple of integers, not of type '%s'." % type(shape))
def test_from_fd_idempotency(ctx_factory, fdrake_mesh, fspace_degree, fspace_type, only_convert_bdy): """ Make sure fd->mm->fd and (fd->)->mm->fd->mm are identity """ # Make a function space and a function with unique values at each node if fspace_type == "scalar": fdrake_fspace = FunctionSpace(fdrake_mesh, "DG", fspace_degree) # Just use the node nr fdrake_unique = Function(fdrake_fspace) fdrake_unique.dat.data[:] = np.arange(fdrake_unique.dat.data.shape[0]) elif fspace_type == "vector": fdrake_fspace = VectorFunctionSpace(fdrake_mesh, "DG", fspace_degree) # use the coordinates xx = SpatialCoordinate(fdrake_fspace.mesh()) fdrake_unique = Function(fdrake_fspace).interpolate(xx) elif fspace_type == "tensor": fdrake_fspace = TensorFunctionSpace(fdrake_mesh, "DG", fspace_degree) # use the coordinates, duplicated into the right tensor shape xx = SpatialCoordinate(fdrake_fspace.mesh()) dim = fdrake_fspace.mesh().geometric_dimension() unique_expr = as_tensor([xx for _ in range(dim)]) fdrake_unique = Function(fdrake_fspace).interpolate(unique_expr) # Make connection cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # If only converting boundary, first go ahead and do one round of # fd->mm->fd. This will zero out any degrees of freedom absent in # the meshmode mesh (because they are not associated to cells # with >= 1 node on the boundary) # # Otherwise, just continue as normal if only_convert_bdy: fdrake_connection = \ build_connection_from_firedrake(actx, fdrake_fspace, restrict_to_boundary="on_boundary") temp = fdrake_connection.from_firedrake(fdrake_unique, actx=actx) fdrake_unique = fdrake_connection.from_meshmode(temp) else: fdrake_connection = build_connection_from_firedrake( actx, fdrake_fspace) # Test for idempotency fd->mm->fd mm_field = fdrake_connection.from_firedrake(fdrake_unique, actx=actx) fdrake_unique_copy = Function(fdrake_fspace) fdrake_connection.from_meshmode(mm_field, out=fdrake_unique_copy) np.testing.assert_allclose(fdrake_unique_copy.dat.data, fdrake_unique.dat.data, atol=CLOSE_ATOL) # Test for idempotency (fd->)mm->fd->mm mm_field_copy = fdrake_connection.from_firedrake(fdrake_unique_copy, actx=actx) if fspace_type == "scalar": np.testing.assert_allclose(actx.to_numpy(mm_field_copy[0]), actx.to_numpy(mm_field[0]), atol=CLOSE_ATOL) else: for dof_arr_cp, dof_arr in zip(mm_field_copy.flatten(), mm_field.flatten()): np.testing.assert_allclose(actx.to_numpy(dof_arr_cp[0]), actx.to_numpy(dof_arr[0]), atol=CLOSE_ATOL)
def run_method(trial, method, cl_ctx=None, queue=None, clear_memoized_objects=False, true_sol_name="True Solution", comp_sol_name="Computed Solution", **kwargs): """ Returns (true solution, computed solution, snes_or_ksp) :arg clear_memoized_objects: Destroy memoized objects if true. :arg trial: A dict mapping each trial option to a valid value :arg method: A valid method (see the keys of *method_options*) :arg cl_ctx: the computing context :arg queue: the computing queue for the context kwargs should include the boundary id of the scatterer as 'scatterer_bdy_id' and the boundary id of the outer boundary as 'outer_bdy_id' kwargs should include the method options for :arg:`trial['method']`. for the given method. """ if clear_memoized_objects: global memoized_objects memoized_objects = {} if cl_ctx is None: raise ValueError("Missing cl_ctx") if queue is None: raise ValueError("Missing queue") # Get boundary ids scatterer_bdy_id = kwargs['scatterer_bdy_id'] outer_bdy_id = kwargs['outer_bdy_id'] # Get degree and wave number degree = trial['degree'] wave_number = trial['kappa'] # Get options prefix and solver parameters, if any options_prefix = kwargs.get('options_prefix', None) solver_parameters = dict(kwargs.get('solver_parameters', None)) # Get prepared trial args in kwargs prepared_trial = prepare_trial(trial, true_sol_name, cl_ctx, queue) mesh, fspace, vfspace, true_sol, true_sol_grad_expr = prepared_trial # Create a place to memoize any objects if necessary tuple_trial = trial_to_tuple(trial) memo_key = tuple_trial[:2] if memo_key not in memoized_objects: memoized_objects[memo_key] = {} comp_sol = None # Handle any special kwargs and get computed solution if method == 'pml': # Get required objects pml_max = kwargs['pml_max'] pml_min = kwargs['pml_min'] # Get optional argumetns pml_type = kwargs.get('pml_type', None) quad_const = kwargs.get('quad_const', None) speed = kwargs.get('speed', None) # Make tensor function space if 'tfspace' not in memoized_objects[memo_key]: memoized_objects[memo_key]['tfspace'] = \ TensorFunctionSpace(mesh, 'CG', degree) tfspace = memoized_objects[memo_key]['tfspace'] snes, comp_sol = pml( mesh, scatterer_bdy_id, outer_bdy_id, wave_number, options_prefix=options_prefix, solver_parameters=solver_parameters, fspace=fspace, tfspace=tfspace, true_sol_grad_expr=true_sol_grad_expr, pml_type=pml_type, quad_const=quad_const, speed=speed, pml_min=pml_min, pml_max=pml_max, ) snes_or_ksp = snes elif method == 'nonlocal': # Build DG spaces if not already built if 'dgfspace' not in memoized_objects[memo_key]: memoized_objects[memo_key]['dgfspace'] = \ FunctionSpace(mesh, 'DG', degree) if 'dgvfspace' not in memoized_objects[memo_key]: memoized_objects[memo_key]['dgvfspace'] = \ VectorFunctionSpace(mesh, 'DG', degree) dgfspace = memoized_objects[memo_key]['dgfspace'] dgvfspace = memoized_objects[memo_key]['dgvfspace'] # Get opencl array context from meshmode.array_context import PyOpenCLArrayContext actx = PyOpenCLArrayContext(queue) # Build connection fd -> meshmode if not already built if 'meshmode_src_connection' not in memoized_objects[memo_key]: from meshmode.interop.firedrake import build_connection_from_firedrake memoized_objects[memo_key]['meshmode_src_connection'] = \ build_connection_from_firedrake( actx, dgfspace, grp_factory=None, restrict_to_boundary=scatterer_bdy_id) meshmode_src_connection = memoized_objects[memo_key][ 'meshmode_src_connection'] # Set defaults for qbx kwargs qbx_order = kwargs.get('qbx_order', degree + 2) fine_order = kwargs.get('fine_order', 4 * degree) fmm_order = kwargs.get('FMM Order', None) fmm_tol = kwargs.get('FMM Tol', None) # make sure got either fmm_order xor fmm_tol if fmm_order is None and fmm_tol is None: raise ValueError("At least one of 'fmm_order', 'fmm_tol' must not " "be *None*") if fmm_order is not None and fmm_tol is not None: raise ValueError("At most one of 'fmm_order', 'fmm_tol' must not " "be *None*") # if got fmm_tol, make a level-to-order fmm_level_to_order = None if fmm_tol is not None: if not isinstance(fmm_tol, float): raise TypeError("fmm_tol of type '%s' is not of type float" % type(fmm_tol)) if fmm_tol <= 0.0: raise ValueError( "fmm_tol of '%s' is less than or equal to 0.0" % fmm_tol) from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder fmm_level_to_order = SimpleExpansionOrderFinder(fmm_tol) # Otherwise, make sure we got a valid fmm_order else: if not isinstance(fmm_order, int): if fmm_order != False: raise TypeError( "fmm_order of type '%s' is not of type int" % type(fmm_order)) if fmm_order != False and fmm_order < 1: raise ValueError("fmm_order of '%s' is less than 1" % fmm_order) qbx_kwargs = { 'qbx_order': qbx_order, 'fine_order': fine_order, 'fmm_order': fmm_order, 'fmm_level_to_order': fmm_level_to_order, 'fmm_backend': 'fmmlib', } # }}} ksp, comp_sol = nonlocal_integral_eq( mesh, scatterer_bdy_id, outer_bdy_id, wave_number, options_prefix=options_prefix, solver_parameters=solver_parameters, fspace=fspace, vfspace=vfspace, true_sol_grad_expr=true_sol_grad_expr, actx=actx, dgfspace=dgfspace, dgvfspace=dgvfspace, meshmode_src_connection=meshmode_src_connection, qbx_kwargs=qbx_kwargs, ) snes_or_ksp = ksp elif method == 'transmission': snes, comp_sol = transmission( mesh, scatterer_bdy_id, outer_bdy_id, wave_number, options_prefix=options_prefix, solver_parameters=solver_parameters, fspace=fspace, true_sol_grad_expr=true_sol_grad_expr, ) snes_or_ksp = snes else: raise ValueError("Invalid method") comp_sol.rename(name=comp_sol_name) return true_sol, comp_sol, snes_or_ksp
def run_method(trial, method, wave_number, true_sol_name="True Solution", comp_sol_name="Computed Solution", **kwargs): """ Returns (true solution, computed solution, snes_or_ksp) :arg trial: A dict mapping each trial option to a valid value :arg method: A valid method (see the keys of *method_options*) :arg wave_number: The wave number kwargs should include the boundary id of the scatterer as 'scatterer_bdy_id' and the boundary id of the outer boundary as 'outer_bdy_id' kwargs should include the method options for :arg:`trial['method']`. for the given method. """ # Get boundary ids scatterer_bdy_id = kwargs['scatterer_bdy_id'] outer_bdy_id = kwargs['outer_bdy_id'] # Get degree degree = trial['degree'] # Get options prefix and solver parameters, if any options_prefix = kwargs.get('options_prefix', None) solver_parameters = dict(kwargs.get('solver_parameters', None)) # Get prepared trial args in kwargs prepared_trial = prepare_trial(trial, true_sol_name) mesh, fspace, vfspace, true_sol, true_sol_grad = prepared_trial # Create a place to memoize any objects if necessary tuple_trial = trial_to_tuple(trial) memo_key = tuple_trial[:2] if memo_key not in memoized_objects: memoized_objects[memo_key] = {} comp_sol = None # Handle any special kwargs and get computed solution if method == 'pml': # Get required objects inner_region = kwargs['inner_region'] pml_max = kwargs['pml_max'] pml_min = kwargs['pml_min'] # Get optional argumetns pml_type = kwargs.get('pml_type', None) delta = kwargs.get('delta', None) quad_const = kwargs.get('quad_const', None) speed = kwargs.get('speed', None) # Make tensor function space if 'tfspace' not in memoized_objects[memo_key]: memoized_objects[memo_key]['tfspace'] = \ TensorFunctionSpace(mesh, 'CG', degree) tfspace = memoized_objects[memo_key]['tfspace'] snes, comp_sol = pml(mesh, scatterer_bdy_id, outer_bdy_id, wave_number, options_prefix=options_prefix, solver_parameters=solver_parameters, inner_region=inner_region, fspace=fspace, tfspace=tfspace, true_sol_grad=true_sol_grad, pml_type=pml_type, delta=delta, quad_const=quad_const, speed=speed, pml_min=pml_min, pml_max=pml_max, ) snes_or_ksp = snes elif method == 'nonlocal': # Get required arguments queue = kwargs['queue'] cl_ctx = queue.context # Set defaults for qbx kwargs qbx_order = kwargs.get('qbx_order', degree+2) fine_order = kwargs.get('fine_order', 4 * degree) fmm_order = kwargs.get('FMM Order', 6) qbx_kwargs = {'qbx_order': qbx_order, 'fine_order': fine_order, 'fmm_order': fmm_order, 'fmm_backend': 'fmmlib', } # }}} # Make function converter if not already built if 'fspace_analog' not in memoized_objects[memo_key]: mesh_analog = fd2mm.MeshAnalog(mesh, near_bdy=scatterer_bdy_id) fspace_analog = fd2mm.FunctionSpaceAnalog(cl_ctx, mesh_analog, fspace) memoized_objects[memo_key]['fspace_analog'] = fspace_analog fspace_analog = memoized_objects[memo_key]['fspace_analog'] ksp, comp_sol = nonlocal_integral_eq( mesh, scatterer_bdy_id, outer_bdy_id, wave_number, options_prefix=options_prefix, solver_parameters=solver_parameters, fspace=fspace, vfspace=vfspace, true_sol_grad=true_sol_grad, queue=queue, fspace_analog=fspace_analog, qbx_kwargs=qbx_kwargs, ) snes_or_ksp = ksp elif method == 'transmission': snes, comp_sol = transmission(mesh, scatterer_bdy_id, outer_bdy_id, wave_number, options_prefix=options_prefix, solver_parameters=solver_parameters, fspace=fspace, true_sol_grad=true_sol_grad, ) snes_or_ksp = snes else: raise ValueError("Invalid method") comp_sol.rename(name=comp_sol_name) return true_sol, comp_sol, snes_or_ksp