From 014cd9bce5a30968dd11d79a41451a188fb63114 Mon Sep 17 00:00:00 2001 From: Bogdan Enache <enache2@illinois.edu> Date: Thu, 9 Nov 2017 13:03:27 -0600 Subject: [PATCH] Cleaned Maxwell-related code, and added a convergence pytest --- ...wellRectCav3D.mac => maxwellrectcav3d.mac} | 2 + examples/maxwell/cavities.py | 9 +- examples/maxwell/testing.py | 86 +------------------ grudge/execution.py | 18 ---- grudge/models/em.py | 58 +++++++++++++ test/test_grudge.py | 72 ++++++++++++++++ 6 files changed, 139 insertions(+), 106 deletions(-) rename contrib/maxima/{maxwellRectCav3D.mac => maxwellrectcav3d.mac} (99%) diff --git a/contrib/maxima/maxwellRectCav3D.mac b/contrib/maxima/maxwellrectcav3d.mac similarity index 99% rename from contrib/maxima/maxwellRectCav3D.mac rename to contrib/maxima/maxwellrectcav3d.mac index 7a51c157..abda9687 100644 --- a/contrib/maxima/maxwellRectCav3D.mac +++ b/contrib/maxima/maxwellrectcav3d.mac @@ -6,6 +6,8 @@ load("diag"); /* -------------------------------------------------------------------------- */ /* Utilities */ /* -------------------------------------------------------------------------- */ +mu: 1; +epsilon: 1; coords:[x,y,z]; diff --git a/examples/maxwell/cavities.py b/examples/maxwell/cavities.py index fcea20c6..85a7c3de 100644 --- a/examples/maxwell/cavities.py +++ b/examples/maxwell/cavities.py @@ -30,10 +30,7 @@ import pyopencl as cl from grudge.shortcuts import set_up_rk4 from grudge import sym, bind, Discretization -from analytic_solutions import ( - get_rectangular_3D_cavity_mode, - get_rectangular_2D_cavity_mode, - ) +from grudge.models.em import get_rectangular_cavity_mode def main(dims, write_output=True, order=4): @@ -63,10 +60,10 @@ def main(dims, write_output=True, order=4): queue = cl.CommandQueue(discr.cl_context) if dims == 3: - sym_mode = get_rectangular_3D_cavity_mode(1, (1, 2, 2)) + sym_mode = get_rectangular_cavity_mode(1, (1, 2, 2)) fields = bind(discr, sym_mode)(queue, t=0, epsilon=epsilon, mu=mu) else: - sym_mode = get_rectangular_2D_cavity_mode(1, (2, 3)) + sym_mode = get_rectangular_cavity_mode(1, (2, 3)) fields = bind(discr, sym_mode)(queue, t=0) # FIXME diff --git a/examples/maxwell/testing.py b/examples/maxwell/testing.py index b9218443..2ff45a68 100644 --- a/examples/maxwell/testing.py +++ b/examples/maxwell/testing.py @@ -28,80 +28,7 @@ THE SOFTWARE. import numpy as np import pyopencl as cl import sumpy.point_calculus as spy -from grudge.shortcuts import set_up_rk4 -from grudge import sym, bind, Discretization - -from analytic_solutions import ( - get_rectangular_3D_cavity_mode, - get_rectangular_2D_cavity_mode, - ) - - -def analytic_test(dims, n, order, cl_ctx, queue): - - from meshmode.mesh.generation import generate_regular_rect_mesh - mesh = generate_regular_rect_mesh( - a=(0.0,)*dims, - b=(1.0,)*dims, - n=(n,)*dims) - - discr = Discretization(cl_ctx, mesh, order=order) - - if 0: - epsilon0 = 8.8541878176e-12 # C**2 / (N m**2) - mu0 = 4*np.pi*1e-7 # N/A**2. - epsilon = 1*epsilon0 - mu = 1*mu0 - else: - epsilon = 1 - mu = 1 - - if dims == 2: - sym_mode = get_rectangular_2D_cavity_mode(1, (1, 2)) - else: - sym_mode = get_rectangular_3D_cavity_mode(1, (1, 2, 2)) - - analytic_sol = bind(discr, sym_mode) - fields = analytic_sol(queue, t=0, epsilon=epsilon, mu=mu) - - from grudge.models.em import MaxwellOperator - op = MaxwellOperator(epsilon, mu, flux_type=0.5, dimensions=dims) - op.check_bc_coverage(mesh) - bound_op = bind(discr, op.sym_operator()) - - def rhs(t, w): - return bound_op(queue, t=t, w=w) - - dt = 0.002 - final_t = dt * 300 - nsteps = int(final_t/dt) - - dt_stepper = set_up_rk4("w", dt, fields, rhs) - - print("dt=%g nsteps=%d" % (dt, nsteps)) - - norm = bind(discr, sym.norm(2, sym.var("u"))) - - step = 0 - for event in dt_stepper.run(t_end=final_t): - if isinstance(event, dt_stepper.StateComputed): - assert event.component_id == "w" - esc = event.state_component - - step += 1 - - if step % 10 == 0: - print(step) - - if step == 20: - sol = analytic_sol(queue, mu=mu, epsilon=epsilon, t=step * dt) - print(norm(queue, u=(esc[0] - sol[0])) / norm(queue, u=sol[0])) - print(norm(queue, u=(esc[1] - sol[1])) / norm(queue, u=sol[1])) - print(norm(queue, u=(esc[2] - sol[2])) / norm(queue, u=sol[2])) - print(norm(queue, u=(esc[3] - sol[3])) / norm(queue, u=sol[3])) - print(norm(queue, u=(esc[4] - sol[4])) / norm(queue, u=sol[4])) - print(norm(queue, u=(esc[5] - sol[5])) / norm(queue, u=sol[5])) - return +from grudge import bind def sumpy_test_3D(order, cl_ctx, queue): @@ -109,7 +36,7 @@ def sumpy_test_3D(order, cl_ctx, queue): epsilon = 1 mu = 1 - kx, ky, kz = factors = [n*np.pi/a for n, a in zip((1, 2, 2), (1, 1, 1))] + kx, ky, kz = factors = [n*np.pi for n in (1, 2, 2)] k = np.sqrt(sum(f**2 for f in factors)) patch = spy.CalculusPatch((0.4, 0.3, 0.4)) @@ -117,7 +44,8 @@ def sumpy_test_3D(order, cl_ctx, queue): from grudge.discretization import PointsDiscretization pdiscr = PointsDiscretization(cl.array.to_device(queue, patch.points)) - sym_mode = get_rectangular_3D_cavity_mode(1, (1, 2, 2)) + from grudge.models.em import get_rectangular_cavity_mode + sym_mode = get_rectangular_cavity_mode(1, (1, 2, 2)) fields = bind(pdiscr, sym_mode)(queue, t=0, epsilon=epsilon, mu=mu) for i in range(len(fields)): @@ -155,9 +83,3 @@ if __name__ == "__main__": print("Doing Sumpy Test") sumpy_test_3D(4, cl_ctx, queue) - print("Doing 2D") - analytic_test(2, 8, 4, cl_ctx, queue) - analytic_test(2, 16, 4, cl_ctx, queue) - print("Doing 3D") - analytic_test(3, 4, 4, cl_ctx, queue) - analytic_test(3, 8, 4, cl_ctx, queue) diff --git a/grudge/execution.py b/grudge/execution.py index c4f285cd..28735582 100644 --- a/grudge/execution.py +++ b/grudge/execution.py @@ -382,24 +382,6 @@ class ExecutionMapper(mappers.Evaluator, # }}} # {{{ code execution functions - # DEBUG stuff - def get_max(self, arr): - from pymbolic.primitives import Variable - i = Variable("i") - - def knl2(): - knl = lp.make_kernel( - "{[i]: 0<=i<n}", - [ - lp.Assignment(Variable("out")[i], - Variable("abs")(Variable("a")[i])) - ]) - return lp.split_iname(knl, "i", 128, outer_tag="g.0", inner_tag="l.0") - - evt, (out,) = knl2()(self.queue, a=arr) - - return pyopencl.array.max(out) - def map_insn_loopy_kernel(self, insn): kwargs = {} kdescr = insn.kernel_descriptor diff --git a/grudge/models/em.py b/grudge/models/em.py index f50f393a..f0e44f90 100644 --- a/grudge/models/em.py +++ b/grudge/models/em.py @@ -435,3 +435,61 @@ class SourceFree1DMaxwellOperator(MaxwellOperator): + (False, False, True) ) + +def get_rectangular_cavity_mode(E_0, mode_indices): + """A rectangular TM cavity mode for a rectangle / cube + with one corner at the origin and the other at (1,1[,1]).""" + dims = len(mode_indices) + if dims != 2 and dims != 3: + raise ValueError("Improper mode_indices dimensions") + import numpy + + factors = [n*numpy.pi for n in mode_indices] + + kx, ky = factors[0:2] + if dims == 3: + kz = factors[2] + + omega = numpy.sqrt(sum(f**2 for f in factors)) + + + nodes = sym.nodes(dims) + x = nodes[0] + y = nodes[1] + if dims == 3: + z = nodes[2] + + sx = sym.sin(kx*x) + cx = sym.cos(kx*x) + sy = sym.sin(ky*y) + cy = sym.cos(ky*y) + if dims == 3: + sz = sym.sin(kz*z) + cz = sym.cos(kz*z) + + if dims == 2: + tfac = sym.ScalarVariable("t") * omega + + result = sym.join_fields( + 0, + 0, + sym.sin(kx * x) * sym.sin(ky * y) * sym.cos(tfac), # ez + -ky * sym.sin(kx * x) * sym.cos(ky * y) * sym.sin(tfac) / omega, # hx + kx * sym.cos(kx * x) * sym.sin(ky * y) * sym.sin(tfac) / omega, # hy + 0, + ) + else: + tdep = sym.exp(-1j * omega * sym.ScalarVariable("t")) + + gamma_squared = ky**2 + kx**2 + result = sym.join_fields( + -kx * kz * E_0*cx*sy*sz*tdep / gamma_squared, # ex + -ky * kz * E_0*sx*cy*sz*tdep / gamma_squared, # ey + E_0 * sx*sy*cz*tdep, # ez + + -1j * omega * ky*E_0*sx*cy*cz*tdep / gamma_squared, # hx + 1j * omega * kx*E_0*cx*sy*cz*tdep / gamma_squared, + 0, + ) + + return result diff --git a/test/test_grudge.py b/test/test_grudge.py index bd47f823..609de951 100644 --- a/test/test_grudge.py +++ b/test/test_grudge.py @@ -333,6 +333,78 @@ def test_convergence_advec(ctx_factory, mesh_name, mesh_pars, op_type, flux_type assert eoc_rec.order_estimate() > order +@pytest.mark.parametrize("order", [3, 4, 5]) +# test: 'test_convergence_advec(cl._csc, "disk", [0.1, 0.05], "strong", "upwind", 3)' +def test_convergence_maxwell(ctx_factory, order, visualize=False): + """Test whether 3D maxwells actually converges""" + + cl_ctx = cl.create_some_context() + queue = cl.CommandQueue(cl_ctx) + + from pytools.convergence import EOCRecorder + eoc_rec = EOCRecorder() + + dims = 3 + ns = [4, 6, 8] + for n in ns: + from meshmode.mesh.generation import generate_regular_rect_mesh + mesh = generate_regular_rect_mesh( + a=(0.0,)*dims, + b=(1.0,)*dims, + n=(n,)*dims) + + discr = Discretization(cl_ctx, mesh, order=order) + + epsilon = 1 + mu = 1 + + from grudge.models.em import get_rectangular_cavity_mode + sym_mode = get_rectangular_cavity_mode(1, (1, 2, 2)) + + analytic_sol = bind(discr, sym_mode) + fields = analytic_sol(queue, t=0, epsilon=epsilon, mu=mu) + + from grudge.models.em import MaxwellOperator + op = MaxwellOperator(epsilon, mu, flux_type=0.5, dimensions=dims) + op.check_bc_coverage(mesh) + bound_op = bind(discr, op.sym_operator()) + + def rhs(t, w): + return bound_op(queue, t=t, w=w) + + dt = 0.002 + final_t = dt * 5 + nsteps = int(final_t/dt) + + from grudge.shortcuts import set_up_rk4 + dt_stepper = set_up_rk4("w", dt, fields, rhs) + + print("dt=%g nsteps=%d" % (dt, nsteps)) + + norm = bind(discr, sym.norm(2, sym.var("u"))) + + step = 0 + for event in dt_stepper.run(t_end=final_t): + if isinstance(event, dt_stepper.StateComputed): + assert event.component_id == "w" + esc = event.state_component + + step += 1 + print(step) + + sol = analytic_sol(queue, mu=mu, epsilon=epsilon, t=step * dt) + vals = [norm(queue, u=(esc[i] - sol[i])) / norm(queue, u=sol[i]) for i in range(5)] # noqa E501 + total_error = sum(vals) + eoc_rec.add_data_point(1.0/n, total_error) + + + + print(eoc_rec.pretty_print(abscissa_label="h", + error_label="L2 Error")) + + assert eoc_rec.order_estimate() > order + + def test_foreign_points(ctx_factory): pytest.importorskip("sumpy") import sumpy.point_calculus as pc -- GitLab