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

Purge .join() from mirgecom #566

Merged
merged 23 commits into from
Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
bb960f6
Remove .join() calls in Euler operator
thomasgibson Dec 10, 2021
0450f5c
Compute componentwise norms for array containers
thomasgibson Dec 10, 2021
a1fe2c0
Merge branch 'main' into thg/purge-join
thomasgibson Dec 10, 2021
a29209d
Document componentwise norms
thomasgibson Dec 10, 2021
72948f2
Start updating unit tests
thomasgibson Dec 10, 2021
b9e714a
Purge join from tests
MTCam Dec 12, 2021
a5476c2
Update tests to subvert discr.norm of emtpy array
MTCam Dec 12, 2021
4199953
Merge remote-tracking branch 'origin/main' into mrgmn
MTCam Dec 12, 2021
35ff60f
Correct/add docstring for max_component_norm
MTCam Dec 12, 2021
82c21f7
Udpate lazy test to handle join purge.
MTCam Dec 12, 2021
8a592ab
Use custom production branch temporarily
MTCam Dec 13, 2021
3c4c245
Undo production env customization
MTCam Dec 13, 2021
9e8824a
Use productions version of Euler operator
MTCam Dec 13, 2021
b3e5891
Revert to main-compatible Euler API
MTCam Dec 13, 2021
6e2e4d3
Remove extraneous argument to Euler operator
MTCam Dec 13, 2021
2c8c3e8
Clean up max expression for util
MTCam Dec 13, 2021
d3275d7
Revert to previous expression
MTCam Dec 13, 2021
0824668
Remove crufty check on empty species flux
MTCam Dec 13, 2021
a2e7449
Make comment about dumb work-around
MTCam Dec 15, 2021
b4df6b8
deflakeate
MTCam Dec 15, 2021
74558fa
Update filter docs and remove decorator
thomasgibson Dec 15, 2021
7ff7bc4
Merge branch 'main' into thg/purge-join
MTCam Dec 15, 2021
4951228
Fix up inviscid boundary flux interface per upstream changes.
MTCam Dec 15, 2021
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
34 changes: 12 additions & 22 deletions mirgecom/euler.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,13 @@
inviscid_flux,
inviscid_facial_flux
)
from grudge.eager import (
interior_trace_pair,
cross_rank_trace_pairs
)
from grudge.trace_pair import TracePair
from mirgecom.fluid import make_conserved

from grudge.trace_pair import interior_trace_pairs
from mirgecom.operators import div_operator


def euler_operator(discr, eos, boundaries, cv, time=0.0):
def euler_operator(discr, eos, boundaries, cv, time=0.0,
dv=None):
thomasgibson marked this conversation as resolved.
Show resolved Hide resolved
r"""Compute RHS of the Euler flow equations.

Returns
Expand Down Expand Up @@ -100,28 +97,21 @@ def euler_operator(discr, eos, boundaries, cv, time=0.0):
Agglomerated object array of DOF arrays representing the RHS of the Euler
flow equations.
"""
# Compute volume contributions
inviscid_flux_vol = inviscid_flux(discr, eos, cv)
interior_cv = interior_trace_pairs(discr, cv)
# Compute interface contributions
inviscid_flux_bnd = (
inviscid_facial_flux(discr, eos=eos, cv_tpair=interior_trace_pair(discr, cv))
+ sum(inviscid_facial_flux(
discr, eos=eos, cv_tpair=TracePair(
part_tpair.dd, interior=make_conserved(discr.dim, q=part_tpair.int),
exterior=make_conserved(discr.dim, q=part_tpair.ext)))
for part_tpair in cross_rank_trace_pairs(discr, cv.join()))
# Interior faces
+ sum(inviscid_facial_flux(discr, eos=eos, cv_tpair=part_tpair)
for part_tpair in interior_cv)
# Domain boundaries
+ sum(boundaries[btag].inviscid_boundary_flux(discr, btag=btag, cv=cv,
eos=eos, time=time)
for btag in boundaries)
)
q = -div_operator(discr, inviscid_flux_vol.join(), inviscid_flux_bnd.join())
return make_conserved(discr.dim, q=q)


def inviscid_operator(discr, eos, boundaries, q, t=0.0):
"""Interface :function:`euler_operator` with backwards-compatible API."""
from warnings import warn
warn("Do not call inviscid_operator; it is now called euler_operator. This"
"function will disappear August 1, 2021", DeprecationWarning, stacklevel=2)
return euler_operator(discr, eos, boundaries, make_conserved(discr.dim, q=q), t)
return -div_operator(discr, inviscid_flux_vol, inviscid_flux_bnd)


# By default, run unitless
Expand Down
8 changes: 7 additions & 1 deletion mirgecom/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,13 @@ def filter_modally(dcoll, dd, cutoff, mode_resp_func, field):
dd_modal = dof_desc.DD_VOLUME_MODAL
discr = dcoll.discr_from_dd(dd)

assert isinstance(field, DOFArray)
from arraycontext import map_array_container
from functools import partial
if not isinstance(field, DOFArray):
return map_array_container(
partial(filter_modally, dcoll, dd, cutoff, mode_resp_func), field
)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the @obj_array_vectorize_n_args be removed after this change? Also, the docstring should probably be updated to reflect that fields and the return value can be object arrays now.

I think with inducer/arraycontext#128 it may be possible to implement this function as something along the lines of:

    def filter_scalar(f):
        dd_nodal = dof_desc.as_dofdesc(dd)
        dd_modal = dof_desc.DD_VOLUME_MODAL
        discr = dcoll.discr_from_dd(dd_nodal)
        actx = f.array_context
        modal_map = dcoll.connection_from_dds(dd_nodal, dd_modal)
        nodal_map = dcoll.connection_from_dds(dd_modal, dd_nodal)
        f = modal_map(f)
        f = apply_spectral_filter(actx, f, discr, cutoff, mode_resp_func)
        return nodal_map(f)

    from arraycontext import rec_map_array_container
    return rec_map_array_container(filter_scalar, field, leaf_class=DOFArray)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're totally right that @obj_array_vectorize_n_args can be removed, thanks for pointing that out. I also updated the docs to reflect the changes: 74558fa

I think with inducer/arraycontext#128 it may be possible to implement this function as something along the lines of:

    def filter_scalar(f):
        dd_nodal = dof_desc.as_dofdesc(dd)
        dd_modal = dof_desc.DD_VOLUME_MODAL
        discr = dcoll.discr_from_dd(dd_nodal)
        actx = f.array_context
        modal_map = dcoll.connection_from_dds(dd_nodal, dd_modal)
        nodal_map = dcoll.connection_from_dds(dd_modal, dd_nodal)
        f = modal_map(f)
        f = apply_spectral_filter(actx, f, discr, cutoff, mode_resp_func)
        return nodal_map(f)

    from arraycontext import rec_map_array_container
    return rec_map_array_container(filter_scalar, field, leaf_class=DOFArray)

I think it's certainly an option. However, I'd prefer not to tackle that in this PR.

actx = field.array_context

modal_map = dcoll.connection_from_dds(dd, dd_modal)
Expand Down
40 changes: 39 additions & 1 deletion mirgecom/simutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
--------------------

.. autofunction:: compare_fluid_solutions
.. autofunction:: componentwise_norms
.. autofunction:: max_component_norm
.. autofunction:: check_naninf_local
.. autofunction:: check_range_local

Expand Down Expand Up @@ -48,6 +50,13 @@
import numpy as np
import grudge.op as op

from arraycontext import map_array_container, flatten

from functools import partial

from meshmode.dof_array import DOFArray


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -290,7 +299,36 @@ def compare_fluid_solutions(discr, red_state, blue_state):
"""
actx = red_state.array_context
resid = red_state - blue_state
return [actx.to_numpy(discr.norm(v, np.inf)) for v in resid.join()]
resid_errs = actx.to_numpy(
flatten(componentwise_norms(discr, resid, order=np.inf), actx))

return resid_errs.tolist()


def componentwise_norms(discr, fields, order=np.inf):
"""Return the *order*-norm for each component of *fields*.

.. note::
This is a collective routine and must be called by all MPI ranks.
"""
if not isinstance(fields, DOFArray):
return map_array_container(
partial(componentwise_norms, discr, order=order), fields)
if len(fields) > 0:
return discr.norm(fields, order)
else:
return 0
thomasgibson marked this conversation as resolved.
Show resolved Hide resolved


def max_component_norm(discr, fields, order=np.inf):
"""Return the max *order*-norm over the components of *fields*.

.. note::
This is a collective routine and must be called by all MPI ranks.
"""
actx = fields.array_context
return max(actx.to_numpy(flatten(
componentwise_norms(discr, fields, order), actx)))
thomasgibson marked this conversation as resolved.
Show resolved Hide resolved


def generate_and_distribute_mesh(comm, generate_mesh):
Expand Down
17 changes: 8 additions & 9 deletions test/test_euler.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
pytest_generate_tests_for_pyopencl_array_context
as pytest_generate_tests)

from mirgecom.simutil import max_component_norm

from grudge.shortcuts import make_visualizer
from mirgecom.inviscid import get_inviscid_timestep
Expand Down Expand Up @@ -234,7 +235,8 @@ def test_vortex_rhs(actx_factory, order):
discr, eos=IdealSingleGas(), boundaries=boundaries,
cv=vortex_soln, time=0.0)

err_max = actx.to_numpy(discr.norm(inviscid_rhs.join(), np.inf))
err_max = max_component_norm(discr, inviscid_rhs, np.inf)

eoc_rec.add_data_point(1.0 / nel_1d, err_max)

logger.info(
Expand Down Expand Up @@ -293,8 +295,7 @@ def test_lump_rhs(actx_factory, dim, order):
)
expected_rhs = lump.exact_rhs(discr, cv=lump_soln, time=0)

err_max = actx.to_numpy(
discr.norm((inviscid_rhs-expected_rhs).join(), np.inf))
err_max = max_component_norm(discr, inviscid_rhs-expected_rhs, np.inf)
if err_max > maxxerr:
maxxerr = err_max

Expand Down Expand Up @@ -371,7 +372,7 @@ def test_multilump_rhs(actx_factory, dim, order, v0):
print(f"expected_rhs = {expected_rhs}")

err_max = actx.to_numpy(
discr.norm((inviscid_rhs-expected_rhs).join(), np.inf))
discr.norm((inviscid_rhs-expected_rhs), np.inf))
if err_max > maxxerr:
maxxerr = err_max

Expand Down Expand Up @@ -437,7 +438,7 @@ def _euler_flow_stepper(actx, parameters):
def write_soln(state, write_status=True):
dv = eos.dependent_vars(cv=state)
expected_result = initializer(nodes, t=t)
result_resid = (state - expected_result).join()
result_resid = state - expected_result
maxerr = [np.max(np.abs(result_resid[i].get())) for i in range(dim + 2)]
mindv = [np.min(dvfld.get()) for dvfld in dv]
maxdv = [np.max(dvfld.get()) for dvfld in dv]
Expand Down Expand Up @@ -492,9 +493,7 @@ def rhs(t, q):
write_soln(state=cv)

cv = rk4_step(cv, t, dt, rhs)
cv = make_conserved(
dim, q=filter_modally(discr, "vol", cutoff, frfunc, cv.join())
)
cv = filter_modally(discr, "vol", cutoff, frfunc, cv)

t += dt
istep += 1
Expand All @@ -506,7 +505,7 @@ def rhs(t, q):
maxerr = max(write_soln(cv, False))
else:
expected_result = initializer(nodes, time=t)
maxerr = actx.to_numpy(discr.norm((cv - expected_result).join(), np.inf))
maxerr = max_component_norm(discr, cv-expected_result, np.inf)

logger.info(f"Max Error: {maxerr}")
if maxerr > exittol:
Expand Down
5 changes: 3 additions & 2 deletions test/test_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,14 @@ def test_filter_function(actx_factory, dim, order, do_viz=False):
# the filter unharmed.
from mirgecom.initializers import Uniform
initr = Uniform(dim=dim)
uniform_soln = initr(t=0, x_vec=nodes).join()
uniform_soln = initr(t=0, x_vec=nodes)

from mirgecom.filter import filter_modally
filtered_soln = filter_modally(discr, "vol", cutoff,
frfunc, uniform_soln)
soln_resid = uniform_soln - filtered_soln
max_errors = [actx.to_numpy(discr.norm(v, np.inf)) for v in soln_resid]
from mirgecom.simutil import componentwise_norms
max_errors = componentwise_norms(discr, soln_resid, np.inf)

tol = 1e-14

Expand Down
13 changes: 5 additions & 8 deletions test/test_fluid.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ def test_velocity_gradient_sanity(actx_factory, dim, mass_exp, vel_fac):

cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom)
from grudge.op import local_grad
grad_cv = make_conserved(dim,
q=local_grad(discr, cv.join()))
grad_cv = local_grad(discr, cv)

grad_v = velocity_gradient(discr, cv, grad_cv)

Expand Down Expand Up @@ -123,8 +122,7 @@ def test_velocity_gradient_eoc(actx_factory, dim):

cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom)
from grudge.op import local_grad
grad_cv = make_conserved(dim,
q=local_grad(discr, cv.join()))
grad_cv = local_grad(discr, cv)
grad_v = velocity_gradient(discr, cv, grad_cv)

def exact_grad_row(xdata, gdim, dim):
Expand Down Expand Up @@ -178,8 +176,7 @@ def test_velocity_gradient_structure(actx_factory):

cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom)
from grudge.op import local_grad
grad_cv = make_conserved(dim,
q=local_grad(discr, cv.join()))
grad_cv = local_grad(discr, cv)
grad_v = velocity_gradient(discr, cv, grad_cv)

tol = 1e-11
Expand Down Expand Up @@ -233,8 +230,8 @@ def test_species_mass_gradient(actx_factory, dim):
cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom,
species_mass=species_mass)
from grudge.op import local_grad
grad_cv = make_conserved(dim,
q=local_grad(discr, cv.join()))
grad_cv = local_grad(discr, cv)

from mirgecom.fluid import species_mass_fraction_gradient
grad_y = species_mass_fraction_gradient(discr, cv, grad_cv)

Expand Down
21 changes: 9 additions & 12 deletions test/test_lazy.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import numpy as np
from functools import partial
from pytools.obj_array import make_obj_array, obj_array_vectorize
from pytools.obj_array import make_obj_array, obj_array_vectorize # noqa
import pyopencl as cl
import pyopencl.tools as cl_tools
import pyopencl.array as cla # noqa
Expand Down Expand Up @@ -75,19 +75,16 @@ def get_discr(order):

# Mimics math.isclose for state arrays
def _isclose(discr, x, y, rel_tol=1e-9, abs_tol=0, return_operands=False):
def componentwise_norm(a):
from mirgecom.fluid import ConservedVars
if isinstance(a, ConservedVars):
return componentwise_norm(a.join())
from arraycontext import get_container_context_recursively
actx = get_container_context_recursively(a)
return obj_array_vectorize(lambda b: actx.to_numpy(discr.norm(b, np.inf)), a)

lhs = componentwise_norm(x - y)

from mirgecom.simutil import componentwise_norms
from arraycontext import flatten
actx = x.array_context
lhs = actx.to_numpy(flatten(componentwise_norms(discr, x - y, np.inf), actx))

rhs = np.maximum(
rel_tol * np.maximum(
componentwise_norm(x),
componentwise_norm(y)),
actx.to_numpy(flatten(componentwise_norms(discr, x, np.inf), actx)),
actx.to_numpy(flatten(componentwise_norms(discr, y, np.inf), actx))),
abs_tol)

is_close = np.all(lhs <= rhs)
Expand Down
29 changes: 11 additions & 18 deletions test/test_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,12 @@ def sym_eval(expr, x_vec):
test_data = test_func(nodes)
exact_grad = grad_test_func(nodes)

def inf_norm(x):
return actx.to_numpy(discr.norm(x, np.inf))
from mirgecom.simutil import componentwise_norms
from arraycontext import flatten

err_scale = max(flatten(componentwise_norms(discr, exact_grad, np.inf),
actx))

if isinstance(test_data, ConservedVars):
err_scale = inf_norm(exact_grad.join())
else:
err_scale = inf_norm(exact_grad)
if err_scale <= 1e-16:
err_scale = 1

Expand All @@ -236,18 +235,12 @@ def inf_norm(x):
test_data_int_tpair, boundaries)

from mirgecom.operators import grad_operator
if isinstance(test_data, ConservedVars):
test_grad = make_conserved(
dim=dim, q=grad_operator(discr, test_data.join(),
test_data_flux_bnd.join())
)
grad_err = inf_norm((test_grad - exact_grad).join())/err_scale
else:
test_grad = grad_operator(discr, test_data, test_data_flux_bnd)
grad_err = inf_norm(test_grad - exact_grad)/err_scale

print(f"{test_grad=}")
eoc.add_data_point(actx.to_numpy(h_max), grad_err)
test_grad = grad_operator(discr, test_data, test_data_flux_bnd)
grad_err = \
max(flatten(componentwise_norms(discr, test_grad - exact_grad, np.inf),
actx)) / err_scale

eoc.add_data_point(actx.to_numpy(h_max), actx.to_numpy(grad_err))

assert (
eoc.order_estimate() >= order - 0.5
Expand Down
3 changes: 2 additions & 1 deletion test/test_restart.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,5 @@ def test_restart_cv(actx_factory, nspecies):
restart_data = read_restart_data(actx, rst_filename)

resid = test_state - restart_data["state"]
assert actx.to_numpy(discr.norm(resid.join(), np.inf)) == 0
from mirgecom.simutil import max_component_norm
assert max_component_norm(discr, resid, np.inf) == 0
7 changes: 5 additions & 2 deletions test/test_simutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

from arraycontext import ( # noqa
thaw,
flatten,
pytest_generate_tests_for_pyopencl_array_context
as pytest_generate_tests
)
Expand Down Expand Up @@ -108,7 +109,7 @@ def test_basic_cfd_healthcheck(actx_factory):
def test_analytic_comparison(actx_factory):
"""Quick test of state comparison routine."""
from mirgecom.initializers import Vortex2D
from mirgecom.simutil import compare_fluid_solutions
from mirgecom.simutil import compare_fluid_solutions, componentwise_norms

actx = actx_factory()
nel_1d = 4
Expand All @@ -134,7 +135,9 @@ def test_analytic_comparison(actx_factory):

cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom)
resid = vortex_soln - cv
expected_errors = [actx.to_numpy(discr.norm(v, np.inf)) for v in resid.join()]

expected_errors = actx.to_numpy(
flatten(componentwise_norms(discr, resid, order=np.inf), actx)).tolist()

errors = compare_fluid_solutions(discr, cv, cv)
assert max(errors) == 0
Expand Down
Loading