Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tensor product differentiation operators #313

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
b1be58a
Update _reference_derivative_matrices to recognize TensorProductEleme…
a-alveyblanc Aug 1, 2023
8fa3321
Stub in tensor product gradient computation in _gradient_kernel
a-alveyblanc Aug 1, 2023
3778edf
First version of grad routine
a-alveyblanc Aug 1, 2023
45e859e
Initial working version of tensor product gradient operator application
a-alveyblanc Aug 1, 2023
22ffacd
Add 3 dimensional test and order 3 test for 2D and 3D
a-alveyblanc Aug 1, 2023
d0bd17e
Add arg names to geometric factor application, refine some comments
a-alveyblanc Aug 1, 2023
ef667bb
Divergence operator version 0.0
a-alveyblanc Aug 2, 2023
eed2516
Prototype of divergence kernel. Needs work, but it passes currently i…
a-alveyblanc Aug 4, 2023
1e40a11
Remove random import included by CoC autocomplete
a-alveyblanc Aug 4, 2023
f2b0275
Generate einsum specification dynamically instead of using if-else
a-alveyblanc Aug 5, 2023
036681c
Rename vandermonde and vandermonde derivative matrices
a-alveyblanc Aug 5, 2023
7ad9017
Give einsums a single source of truth. Still only valid for dim <= 3
a-alveyblanc Aug 7, 2023
c645dbe
Move TP array context to array_context.py, other minor changes
a-alveyblanc Aug 10, 2023
dcd7ca0
Update tensor product grad test to match the other grad test case
a-alveyblanc Aug 10, 2023
683cdd8
Update tensor product divergence test to match original test case.
a-alveyblanc Aug 10, 2023
1563950
Divergence kernel functioning again
a-alveyblanc Aug 14, 2023
e1380fe
Update some comments, begin weak form matrices work
a-alveyblanc Aug 21, 2023
33a54e4
TMP: Use outside actx in TP grad
inducer Sep 6, 2023
e446bb7
Add TP transform cartoon
inducer Sep 6, 2023
264192c
Temporary changes to get tensor product gradient working again
a-alveyblanc Sep 12, 2023
ba03b3f
Tensor product array context related changes
a-alveyblanc Sep 13, 2023
8263333
Update example
a-alveyblanc Sep 14, 2023
6b50028
Add code for printing generated differentiation code
a-alveyblanc Sep 14, 2023
5d36bfb
Update strong tp diff example
a-alveyblanc Sep 18, 2023
92991a3
Version 0.1 of weak gradient computation
a-alveyblanc Sep 30, 2023
49116ab
Weak form divergence version 0.1
a-alveyblanc Sep 30, 2023
d87c19f
Move TP array contexts. Add acoustic pulse TP example
a-alveyblanc Oct 1, 2023
aec8bdb
Merge branch 'inducer:main' into tensor-product-differentiation-opera…
a-alveyblanc Oct 8, 2023
c14f08d
Merge branch 'inducer:main' into tensor-product-differentiation-opera…
a-alveyblanc Oct 17, 2023
b8e24c4
Start simplifying einsum
a-alveyblanc Oct 8, 2023
645a504
Remove unnecessary code
a-alveyblanc Nov 3, 2023
9b70d0b
Correct arg names in weak form gradient
a-alveyblanc Nov 3, 2023
ed8aacf
Correct arg names in weak form operator application
a-alveyblanc Nov 3, 2023
b1c312d
Same as last commit
a-alveyblanc Nov 3, 2023
0cb1830
Offload simplicial grad/div to their own function. Slight refactors.
a-alveyblanc Dec 7, 2023
984a984
More refactoring. Add FIXMEs for future changes (another PR probably)
a-alveyblanc Dec 7, 2023
77d6470
Chain geometric factors for strong form. Move tp metadata processing …
a-alveyblanc Dec 10, 2023
c3f7543
Add chained einsums to grad and div. Uncover some new bugs
a-alveyblanc Dec 11, 2023
06f5738
Small adjustment to buggy code
a-alveyblanc Dec 11, 2023
e31a8c4
Add math explanation and some other small changes
a-alveyblanc Dec 11, 2023
e293bd0
Update comment
a-alveyblanc Dec 11, 2023
0792c0b
Update requirements.txt to accurately reflect requirements
a-alveyblanc Dec 11, 2023
58c39bd
Run test_inverse_metric for tensor product meshes
inducer Dec 11, 2023
b8b239c
test_inverse_metric: Rotate mesh in non-affine case
inducer Dec 11, 2023
be8a26b
Rotate mesh in test_gradient
inducer Dec 11, 2023
3f8a886
Add TP divergence thm test. Make diff. op. einsums more general
a-alveyblanc Dec 12, 2023
e136538
Fixed tensor product operators, needs major refactor but it works for…
a-alveyblanc Dec 16, 2023
82b2c09
Update weak form div
a-alveyblanc Dec 16, 2023
2bb9228
Update pulse example. Update grudge tensor product gradient
a-alveyblanc Jan 4, 2024
7e389a7
Start updating div to be a single einsum
a-alveyblanc Jan 8, 2024
9951d65
start move to single axis operator application
a-alveyblanc Jan 16, 2024
f722b27
Update div
a-alveyblanc Jan 22, 2024
4b1e0b6
temp changes
a-alveyblanc Jan 27, 2024
47d6674
Working div recast as series of single axis operator applications
a-alveyblanc Jan 27, 2024
201c018
Update _apply_inverse_mass_operator for TP elements
a-alveyblanc Jan 28, 2024
b2e909e
Minor formatting
a-alveyblanc Jan 28, 2024
220c483
Merge branch 'inducer:main' into tensor-product-differentiation-opera…
a-alveyblanc Feb 11, 2024
fdcf4b8
Add simplicial test back to div convergence test
a-alveyblanc Feb 11, 2024
d9dbffe
Start working on TP DOF axis tagging (nothing working yet)
a-alveyblanc Feb 29, 2024
d611023
another TP DOF axis tagging commit (still nothing working yet)
a-alveyblanc Feb 29, 2024
f9a5330
Start implementing call_loopy in grudge eager actx
a-alveyblanc Mar 1, 2024
f216355
Revert eager changes. Remove unnecessary code in lazy actx. Update ex…
a-alveyblanc Mar 1, 2024
90d7092
Update TP operator and data tagging
a-alveyblanc Apr 2, 2024
8ebccc7
Update a comment
a-alveyblanc Apr 2, 2024
29be28d
Add TensorProductOperatorAxisTag
a-alveyblanc Apr 2, 2024
607d368
Add some clarifying comments
a-alveyblanc Apr 2, 2024
f03230d
Update docs. Testing IgnoredForEqualityTag
a-alveyblanc Apr 2, 2024
cadb98a
Rename some tags, change to IgnoredForPropagationTag in TP operator a…
a-alveyblanc Apr 3, 2024
a662445
Small change
a-alveyblanc Apr 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
272 changes: 272 additions & 0 deletions examples/tensor-product-examples/acoustic_pulse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
__copyright__ = """
Copyright (C) 2021 University of Illinois Board of Trustees
"""

__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.
"""


from meshmode.mesh import TensorProductElementGroup
import numpy as np

import pyopencl as cl
import pyopencl.tools as cl_tools

from grudge.array_context import (
PyOpenCLArrayContext,
PytatoPyOpenCLArrayContext
)
from grudge.models.euler import (
ConservedEulerField,
EulerOperator,
InviscidWallBC
)
from grudge.shortcuts import rk4_step

from meshmode.mesh import BTAG_ALL

from pytools.obj_array import make_obj_array

import grudge.op as op

import logging
logger = logging.getLogger(__name__)


def gaussian_profile(
x_vec, t=0, rho0=1.0, rhoamp=1.0, p0=1.0, gamma=1.4,
center=None, velocity=None):

dim = len(x_vec)
if center is None:
center = np.zeros(shape=(dim,))
if velocity is None:
velocity = np.zeros(shape=(dim,))

lump_loc = center + t * velocity

# coordinates relative to lump center
rel_center = make_obj_array(
[x_vec[i] - lump_loc[i] for i in range(dim)]
)
actx = x_vec[0].array_context
r = actx.np.sqrt(np.dot(rel_center, rel_center))
expterm = rhoamp * actx.np.exp(1 - r ** 2)

mass = expterm + rho0
mom = velocity * mass
energy = (p0 / (gamma - 1.0)) + np.dot(mom, mom) / (2.0 * mass)

return ConservedEulerField(mass=mass, energy=energy, momentum=mom)


def make_pulse(amplitude, r0, w, r):
dim = len(r)
r_0 = np.zeros(dim)
r_0 = r_0 + r0
rel_center = make_obj_array(
[r[i] - r_0[i] for i in range(dim)]
)
actx = r[0].array_context
rms2 = w * w
r2 = np.dot(rel_center, rel_center) / rms2
return amplitude * actx.np.exp(-.5 * r2)


def acoustic_pulse_condition(x_vec, t=0):
dim = len(x_vec)
vel = np.zeros(shape=(dim,))
orig = np.zeros(shape=(dim,))
uniform_gaussian = gaussian_profile(
x_vec, t=t, center=orig, velocity=vel, rhoamp=0.0)

amplitude = 1.0
width = 0.1
pulse = make_pulse(amplitude, orig, width, x_vec)

return ConservedEulerField(
mass=uniform_gaussian.mass,
energy=uniform_gaussian.energy + pulse,
momentum=uniform_gaussian.momentum
)


def run_acoustic_pulse(actx,
order=3,
final_time=1,
resolution=16,
overintegration=False,
visualize=False,
rotate_mesh=False):

# eos-related parameters
gamma = 1.4

# {{{ discretization

from meshmode.mesh.generation import generate_regular_rect_mesh

dim = 2
box_ll = -0.5
box_ur = 0.5
mesh = generate_regular_rect_mesh(
a=(box_ll,)*dim,
b=(box_ur,)*dim,
nelements_per_axis=(resolution,)*dim,
group_cls=TensorProductElementGroup)

if rotate_mesh:
from meshmode.mesh.processing import affine_map
alpha = .3
rot_mat = np.array([
[np.cos(alpha), np.sin(alpha)],
[-np.sin(alpha), np.cos(alpha)]
])
mesh = affine_map(mesh, A=rot_mat)

from grudge import DiscretizationCollection
from grudge.dof_desc import DISCR_TAG_BASE, DISCR_TAG_QUAD
from meshmode.discretization.poly_element import \
LegendreGaussLobattoTensorProductGroupFactory as LGL

exp_name = f"fld-acoustic-pulse-N{order}-K{resolution}"
if overintegration:
exp_name += "-overintegrated"
quad_tag = DISCR_TAG_QUAD
else:
quad_tag = None

dcoll = DiscretizationCollection(
actx, mesh,
discr_tag_to_group_factory={
DISCR_TAG_BASE: LGL(order)
}
)

# }}}

# {{{ Euler operator

euler_operator = EulerOperator(
dcoll,
bdry_conditions={BTAG_ALL: InviscidWallBC()},
flux_type="lf",
gamma=gamma,
quadrature_tag=quad_tag
)

def rhs(t, q):
return euler_operator.operator(t, q)

compiled_rhs = actx.compile(rhs)

from grudge.dt_utils import h_min_from_volume

cfl = 0.125
cn = 0.5*(order + 1)**2
dt = cfl * actx.to_numpy(h_min_from_volume(dcoll)) / cn

fields = acoustic_pulse_condition(actx.thaw(dcoll.nodes()))

logger.info("Timestep size: %g", dt)

# }}}

from grudge.shortcuts import make_visualizer

vis = make_visualizer(dcoll)

# {{{ time stepping

step = 0
t = 0.0
while t < final_time:
if step % 10 == 0:
norm_q = actx.to_numpy(op.norm(dcoll, fields, 2))
logger.info("[%04d] t = %.5f |q| = %.5e", step, t, norm_q)
if visualize:
vis.write_vtk_file(
f"{exp_name}-{step:04d}.vtu",
[
("rho", fields.mass),
("energy", fields.energy),
("momentum", fields.momentum)
]
)
assert norm_q < 5

fields = actx.thaw(actx.freeze(fields))
fields = rk4_step(fields, t, dt, compiled_rhs)
t += dt
step += 1

# }}}


def main(ctx_factory, order=3, final_time=1, resolution=16,
overintegration=False, visualize=False, lazy=False):
cl_ctx = ctx_factory()
queue = cl.CommandQueue(cl_ctx)

if lazy:
actx = PytatoPyOpenCLArrayContext(
queue,
allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)),
)
else:
actx = PyOpenCLArrayContext(
queue,
allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)),
force_device_scalars=False
)

run_acoustic_pulse(
actx,
order=order,
resolution=resolution,
overintegration=overintegration,
final_time=final_time,
visualize=visualize
)


if __name__ == "__main__":
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--order", default=3, type=int)
parser.add_argument("--tfinal", default=0.1, type=float)
parser.add_argument("--resolution", default=16, type=int)
parser.add_argument("--oi", action="store_true",
help="use overintegration")
parser.add_argument("--visualize", action="store_true",
help="write out vtk output")
parser.add_argument("--lazy", action="store_true",
help="switch to a lazy computation mode")
args = parser.parse_args()

logging.basicConfig(level=logging.INFO)
main(cl.create_some_context,
order=args.order,
final_time=args.tfinal,
resolution=args.resolution,
overintegration=args.oi,
visualize=args.visualize,
lazy=args.lazy)
102 changes: 102 additions & 0 deletions examples/tp-transform-cartoon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import loopy as lp

import meshmode.mesh.generation as mgen

import numpy as np
import pyopencl as cl
import pytato as pt

from grudge import op
from grudge.array_context import OutputIsTensorProductDOFArrayOrdered
from grudge.discretization import make_discretization_collection

from meshmode.array_context import PytatoPyOpenCLArrayContext


class PytatoTensorProductArrayContext(PytatoPyOpenCLArrayContext):
def transform_dag(self, dag):
if "dag_dots" not in dir(self):
self.dag_dots = []

self.dag_dots.append(pt.get_dot_graph(dag))

return super().transform_dag(dag)

def transform_loopy_program(self, t_unit):
knl = t_unit.default_entrypoint

# {{{ adjust strides according to tensor product structure
if knl.tags_of_type(OutputIsTensorProductDOFArrayOrdered):
new_args = []
for arg in knl.args:
if arg.is_output:
arg = arg.copy(dim_tags=(
f"N{len(arg.shape)-1},"
+ ",".join(f"N{i}"
for i in range(len(arg.shape)-1))
))

new_args.append(arg)

knl = knl.copy(args=new_args)
# }}}

# {{{ prefetch
# }}}

# {{{ tile
# }}}

# FIXME: remove this (eventually)
knl = lp.set_options(knl, insert_gbarriers=True)
t_unit = t_unit.with_kernel(knl)
self.dev_code = lp.generate_code_v2(t_unit).device_code()

return super().transform_loopy_program(t_unit)


def main():
order = 1

ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)
actx = PytatoTensorProductArrayContext(queue)

dim = 2
res = 2

from meshmode.mesh import TensorProductElementGroup
from meshmode.discretization.poly_element import \
LegendreGaussLobattoTensorProductGroupFactory as LGL

mesh = mgen.generate_regular_rect_mesh(
a=(-1,)*dim, b=(1,)*dim,
nelements_per_axis=(res,)*dim,
group_cls=TensorProductElementGroup)

import grudge.dof_desc as dd
dcoll = make_discretization_collection(
actx,
mesh,
discr_tag_to_group_factory={
dd.DISCR_TAG_BASE: LGL(order)})

def f(x):
result = dcoll.zeros(actx) + 1
for i in range(dim-1):
result = result * actx.np.sin(np.pi*x[i])
result = result * actx.np.cos(np.pi/2*x[dim-1])
return result


x = actx.thaw(dcoll.nodes())

u = f(x)

grad_u = op.local_grad(dcoll, u)
grad_u = actx.np.stack(grad_u)[0]
pt.show_dot_graph(grad_u)

if __name__ == "__main__":
main()

Loading