diff --git a/examples/wave/wave-eager-var-velocity.py b/examples/wave/wave-eager-var-velocity.py new file mode 100644 index 0000000000000000000000000000000000000000..721211314dfd5931374f0347e90435c624baf129 --- /dev/null +++ b/examples/wave/wave-eager-var-velocity.py @@ -0,0 +1,211 @@ +from __future__ import division, print_function + +__copyright__ = "Copyright (C) 2020 Andreas Kloeckner" + +__license__ = """ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +import numpy as np +import numpy.linalg as la # noqa +import pyopencl as cl + +from pytools.obj_array import flat_obj_array, make_obj_array + +from meshmode.array_context import PyOpenCLArrayContext +from meshmode.dof_array import thaw + +from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa + +from grudge.eager import EagerDGDiscretization, interior_trace_pair +from grudge.shortcuts import make_visualizer +from grudge.symbolic.primitives import TracePair, QTAG_NONE, DOFDesc + + +# {{{ wave equation bits + +def scalar(arg): + return make_obj_array([arg]) + + +def wave_flux(discr, c, w_tpair): + dd = w_tpair.dd + dd_quad = dd.with_qtag("vel_prod") + + u = w_tpair[0] + v = w_tpair[1:] + + normal = thaw(u.int.array_context, discr.normal(dd)) + + flux_weak = flat_obj_array( + np.dot(v.avg, normal), + normal*scalar(u.avg), + ) + + # upwind + v_jump = np.dot(normal, v.int-v.ext) + flux_weak -= flat_obj_array( + 0.5*(u.int-u.ext), + 0.5*normal*scalar(v_jump), + ) + + # FIMXE this flux is only correct for continuous c + dd_allfaces_quad = dd_quad.with_dtag("all_faces") + c_quad = discr.project("vol", dd_quad, c) + flux_quad = discr.project(dd, dd_quad, flux_weak) + + return discr.project(dd_quad, dd_allfaces_quad, scalar(c_quad)*flux_quad) + + +def wave_operator(discr, c, w): + u = w[0] + v = w[1:] + + dir_u = discr.project("vol", BTAG_ALL, u) + dir_v = discr.project("vol", BTAG_ALL, v) + dir_bval = flat_obj_array(dir_u, dir_v) + dir_bc = flat_obj_array(-dir_u, dir_v) + + dd_quad = DOFDesc("vol", "vel_prod") + c_quad = discr.project("vol", dd_quad, c) + w_quad = discr.project("vol", dd_quad, w) + u_quad = w_quad[0] + v_quad = w_quad[1:] + + dd_allfaces_quad = DOFDesc("all_faces", "vel_prod") + + # FIXME Fix sign issue + return ( + discr.inverse_mass( + flat_obj_array( + discr.weak_div(dd_quad, scalar(c_quad)*v_quad), + discr.weak_grad(dd_quad, c_quad*u_quad) + ) + - # noqa: W504 + discr.face_mass( + dd_allfaces_quad, + wave_flux(discr, c=c, w_tpair=interior_trace_pair(discr, w)) + + wave_flux(discr, c=c, w_tpair=TracePair( + BTAG_ALL, dir_bval, dir_bc)) + )) + ) + +# }}} + + +def rk4_step(y, t, h, f): + k1 = f(t, y) + k2 = f(t+h/2, y + h/2*k1) + k3 = f(t+h/2, y + h/2*k2) + k4 = f(t+h, y + h*k3) + return y + h/6*(k1 + 2*k2 + 2*k3 + k4) + + +def bump(actx, discr, t=0, width=0.05, center=None): + if center is None: + center = np.array([0.2, 0.35, 0.1]) + + center = center[:discr.dim] + source_omega = 3 + + nodes = thaw(actx, discr.nodes()) + center_dist = flat_obj_array([ + nodes[i] - center[i] + for i in range(discr.dim) + ]) + + return ( + np.cos(source_omega*t) + * actx.np.exp( + -np.dot(center_dist, center_dist) + / width**2)) + + +def main(): + cl_ctx = cl.create_some_context() + queue = cl.CommandQueue(cl_ctx) + actx = PyOpenCLArrayContext(queue) + + dim = 2 + nel_1d = 16 + from meshmode.mesh.generation import generate_regular_rect_mesh + mesh = generate_regular_rect_mesh( + a=(-0.5,)*dim, + b=(0.5,)*dim, + n=(nel_1d,)*dim) + + order = 3 + + if dim == 2: + # no deep meaning here, just a fudge factor + dt = 0.75/(nel_1d*order**2) + elif dim == 3: + # no deep meaning here, just a fudge factor + dt = 0.45/(nel_1d*order**2) + else: + raise ValueError("don't have a stable time step guesstimate") + + print("%d elements" % mesh.nelements) + + from meshmode.discretization.poly_element import \ + QuadratureSimplexGroupFactory, \ + PolynomialWarpAndBlendGroupFactory + discr = EagerDGDiscretization(actx, mesh, + quad_tag_to_group_factory={ + QTAG_NONE: PolynomialWarpAndBlendGroupFactory(order), + "vel_prod": QuadratureSimplexGroupFactory(3*order), + }) + + # bounded above by 1 + c = 0.2 + 0.8*bump(actx, discr, center=np.zeros(3), width=0.5) + + fields = flat_obj_array( + bump(actx, discr, ), + [discr.zeros(actx) for i in range(discr.dim)] + ) + + vis = make_visualizer(discr, order+3 if dim == 2 else order) + + def rhs(t, w): + return wave_operator(discr, c=c, w=w) + + t = 0 + t_final = 3 + istep = 0 + while t < t_final: + fields = rk4_step(fields, t, dt, rhs) + + if istep % 10 == 0: + print(istep, t, discr.norm(fields[0])) + vis.write_vtk_file("fld-wave-eager-var-velocity-%04d.vtu" % istep, + [ + ("c", c), + ("u", fields[0]), + ("v", fields[1:]), + ]) + + t += dt + istep += 1 + + +if __name__ == "__main__": + main() + +# vim: foldmethod=marker