def test_to_fd_consistency(ctx_factory, mm_mesh, fspace_degree): fspace_degree += mm_mesh.groups[0].order cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) factory = InterpolatoryQuadratureSimplexGroupFactory(fspace_degree) discr = Discretization(actx, mm_mesh, factory) fdrake_connection = build_connection_to_firedrake(discr) fdrake_fspace = fdrake_connection.firedrake_fspace() # Check consistency check_consistency(fdrake_fspace, discr)
def test_to_fd_idempotency(ctx_factory, mm_mesh, fspace_degree): """ Make sure mm->fd->mm and (mm->)->fd->mm->fd are identity """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # make sure degree is higher order than mesh fspace_degree += mm_mesh.groups[0].order # Make a function space and a function with unique values at each node factory = InterpolatoryQuadratureSimplexGroupFactory(fspace_degree) discr = Discretization(actx, mm_mesh, factory) fdrake_connection = build_connection_to_firedrake(discr) fdrake_mesh = fdrake_connection.firedrake_fspace().mesh() dtype = fdrake_mesh.coordinates.dat.data.dtype mm_unique = discr.zeros(actx, dtype=dtype) unique_vals = np.arange(np.size(mm_unique[0]), dtype=dtype) mm_unique[0].set(unique_vals.reshape(mm_unique[0].shape)) mm_unique_copy = DOFArray(actx, (mm_unique[0].copy(), )) # Test for idempotency mm->fd->mm fdrake_unique = fdrake_connection.from_meshmode(mm_unique) fdrake_connection.from_firedrake(fdrake_unique, out=mm_unique_copy) np.testing.assert_allclose(actx.to_numpy(mm_unique_copy[0]), actx.to_numpy(mm_unique[0]), atol=CLOSE_ATOL) # Test for idempotency (mm->)fd->mm->fd fdrake_unique_copy = fdrake_connection.from_meshmode(mm_unique_copy) np.testing.assert_allclose(fdrake_unique_copy.dat.data, fdrake_unique.dat.data, atol=CLOSE_ATOL)
def test_to_fd_transfer(ctx_factory, fspace_degree, mesh_name, mesh_pars, dim): """ Make sure creating a function which projects onto one dimension then transports it is the same (up to resampling error) as projecting to one dimension on the transported mesh """ # build estimate-of-convergence recorder from pytools.convergence import EOCRecorder # dimension projecting onto -> EOCRecorder eoc_recorders = {d: EOCRecorder() for d in range(dim)} # make a computing context cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # Get each of the refinements of the meshmeshes and record # conversions errors for mesh_par in mesh_pars: if mesh_name in ("blob2d-order1", "blob2d-order4"): assert dim == 2 from meshmode.mesh.io import read_gmsh mm_mesh = read_gmsh(f"{mesh_name}-h{mesh_par}.msh", force_ambient_dim=dim) h = float(mesh_par) elif mesh_name == "warp": from meshmode.mesh.generation import generate_warped_rect_mesh mm_mesh = generate_warped_rect_mesh(dim, order=4, n=mesh_par) h = 1 / mesh_par else: raise ValueError("mesh_name not recognized") # Make discr and connect it to firedrake factory = InterpolatoryQuadratureSimplexGroupFactory(fspace_degree) discr = Discretization(actx, mm_mesh, factory) fdrake_connection = build_connection_to_firedrake(discr) fdrake_fspace = fdrake_connection.firedrake_fspace() spatial_coord = SpatialCoordinate(fdrake_fspace.mesh()) # get the group's nodes in a numpy array nodes = discr.nodes() group_nodes = np.array( [actx.to_numpy(dof_arr[0]) for dof_arr in nodes]) for d in range(dim): meshmode_f = discr.zeros(actx) meshmode_f[0][:] = group_nodes[d, :, :] # connect to firedrake and evaluate expr in firedrake fdrake_f = Function(fdrake_fspace).interpolate(spatial_coord[d]) # transport to firedrake and record error mm2fd_f = fdrake_connection.from_meshmode(meshmode_f) err = np.max(np.abs(fdrake_f.dat.data - mm2fd_f.dat.data)) eoc_recorders[d].add_data_point(h, err) # assert that order is correct or error is "low enough" for d, eoc_rec in eoc_recorders.items(): print("\nvector *x* -> *x[%s]*\n" % d, eoc_rec) assert (eoc_rec.order_estimate() >= fspace_degree or eoc_rec.max_error() < 2e-14)
def main(): # If can't import firedrake, do nothing # # filename MUST include "firedrake" (i.e. match *firedrake*.py) in order # to be run during CI try: import firedrake # noqa : F401 except ImportError: return 0 # For this example, imagine we wish to solve the Laplace equation # on a meshmode mesh with some given Dirichlet boundary conditions, # and decide to use firedrake. # # To verify this is working, we use a solution to the wave equation # to get our boundary conditions # {{{ First we make a discretization in meshmode and get our bcs cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.array_context import PyOpenCLArrayContext actx = PyOpenCLArrayContext(queue) nel_1d = 16 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, -0.5), b=(0.5, 0.5), n=(nel_1d, nel_1d)) order = 3 from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory group_factory = InterpolatoryQuadratureSimplexGroupFactory(order=order) discr = Discretization(actx, mesh, group_factory) # Get our solution: we will use # Real(e^z) = Real(e^{x+iy}) # = e^x Real(e^{iy}) # = e^x cos(y) nodes = discr.nodes() from meshmode.dof_array import thaw for i in range(len(nodes)): nodes[i] = thaw(actx, nodes[i]) # First index is dimension candidate_sol = actx.np.exp(nodes[0]) * actx.np.cos(nodes[1]) # }}} # {{{ Now send candidate_sol into firedrake and use it for boundary conditions from meshmode.interop.firedrake import build_connection_to_firedrake fd_connection = build_connection_to_firedrake(discr, group_nr=0) # convert candidate_sol to firedrake fd_candidate_sol = fd_connection.from_meshmode(candidate_sol) # get the firedrake function space fd_fspace = fd_connection.firedrake_fspace() # set up dirichlet laplace problem in fd and solve from firedrake import (FunctionSpace, TrialFunction, TestFunction, Function, inner, grad, dx, Constant, project, DirichletBC, solve) # because it's easier to write down the variational problem, # we're going to project from our "DG" space # into a continuous one. cfd_fspace = FunctionSpace(fd_fspace.mesh(), "CG", order) u = TrialFunction(cfd_fspace) v = TestFunction(cfd_fspace) sol = Function(cfd_fspace) a = inner(grad(u), grad(v)) * dx rhs = Constant(0.0) * v * dx bc_value = project(fd_candidate_sol, cfd_fspace) bc = DirichletBC(cfd_fspace, bc_value, "on_boundary") params = {"ksp_monitor": None} solve(a == rhs, sol, bcs=[bc], solver_parameters=params) # project back into our "DG" space sol = project(sol, fd_fspace) # }}} # {{{ Take the solution from firedrake and compare it to candidate_sol true_sol = fd_connection.from_firedrake(sol, actx=actx) # pull back into numpy true_sol = actx.to_numpy(true_sol[0]) candidate_sol = actx.to_numpy(candidate_sol[0]) print("l^2 difference between candidate solution and firedrake solution=", np.linalg.norm(true_sol - candidate_sol))