From 8e7ddda588e51c4ee339d169e57a6750e882e1fe Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Wed, 28 Oct 2020 18:22:51 -0500 Subject: [PATCH 001/106] Initial implementation of artificial viscosity for the euler equations --- mirgecom/artificial_viscosity.py | 124 +++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 mirgecom/artificial_viscosity.py diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py new file mode 100644 index 000000000..c496e3a1e --- /dev/null +++ b/mirgecom/artificial_viscosity.py @@ -0,0 +1,124 @@ +r""":mod:`mirgecom.artificial viscosity` applys and artifical viscosity to the euler equations +""" + +__copyright__ = """ +Copyright (C) 2020 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 dataclasses import dataclass + +import numpy as np +from pytools.obj_array import make_obj_array +from meshmode.dof_array import thaw +from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa +from grudge.eager import ( + interior_trace_pair, + cross_rank_trace_pairs +) +from grudge.symbolic.primitives import TracePair +from mirgecom.euler import split_conserved, join_conserved + + +def scalar(s): + """Create an object array for a scalar.""" + return make_obj_array([s]) + + +def dissapative_flux(discr, q): + + dim = discr.dim + cv = split_conserved(dim, q) + + return join_conserved(dim, + mass=np.ones(dim)*scalar(cv.mass), + energy=np.ones(dim)*scalar(cv.energy), + momentum= np.ones((dim,dim))*cv.momentum ) + +def _facial_flux(discr, q_tpair): + + dim = discr.dim + + actx = q_tpair[0].int.array_context + + flux_int = dissapative_flux(discr,q_tpair.int); + flux_ext = dissapative_flux(discr,q_tpair.ext); + flux_dis = 0.5*(flux_ext + flux_int); + + normal = thaw(actx, discr.normal(q_tpair.dd)) + + flux_out = flux_dis @ normal + + return discr.project(q_tpair.dd, "all_faces", flux_out) + +def artificial_viscosity(discr, r): + r"""Compute artifical viscosity for the euler equations + + """ + + #compute dissapation flux + vol_flux_r = dissapative_flux(discr, r) + dflux_r = discr.weak_div(vol_flux_r) + + #interior face flux + iff_r = _facial_flux(discr, q_tpair=interior_trace_pair(discr,r)) + + #partition boundaries flux + pbf_r = sum( + _facial_flux(discr, q_tpair=part_pair) + for part_pair in cross_rank_trace_pairs(discr, r) + ) + + #domain boundary flux + dir_r = discr.project("vol", BTAG_ALL,r) + dbf_r = _facial_flux( + discr, + q_tpair=TracePair(BTAG_ALL,interior=dir_r,exterior=dir_r) + ) + + q = discr.inverse_mass( 1.0e-2 * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r))) + + #flux of q + vol_flux_q = dissapative_flux(discr, q) + dflux_q = discr.weak_div(vol_flux_q) + + #interior face flux of q + iff_q = _facial_flux(discr, q_tpair=interior_trace_pair(discr,q)) + + #flux across partition boundaries + pbf_q = sum( + _facial_flux(discr, q_tpair=part_pair) + for part_pair in cross_rank_trace_pairs(discr, q) + ) + + #dombain boundary flux + dir_q = discr.project("vol",BTAG_ALL, q); + dbf_q = _facial_flux( + discr, + q_tpair=TracePair(BTAG_ALL,interior=dir_q,exterior=dir_q) + ) + + + return discr.inverse_mass( + dflux_q - discr.face_mass(iff_q + pbf_q + dbf_q) + ) + From 59f80c34735c3cf1638241aaf05bcefb3f4e395f Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Sat, 31 Oct 2020 19:55:24 -0500 Subject: [PATCH 002/106] Initial implementation of smoothness indicator --- mirgecom/tag_cells.py | 103 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 mirgecom/tag_cells.py diff --git a/mirgecom/tag_cells.py b/mirgecom/tag_cells.py new file mode 100644 index 000000000..98fc21842 --- /dev/null +++ b/mirgecom/tag_cells.py @@ -0,0 +1,103 @@ +r""":mod:`mirgecom.tag_cells` Computes smoothness indicator + +Perssons smoothness indicator: + +.. math:: + + S_e = \frac{\langle u_{N_p} - u_{N_{p-1}}, u_{N_p} - u_{N_{p-1}}\rangle_e}{\langle u_{N_p}, u_{N_p} \rangle_e} + +""" +__copyright__ = """ +Copyright (C) 2020 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. +""" + +import numpy as np +import loopy as lp +from grudge import sym +from meshmode.dof_array import DOFArray +from modepy import vandermonde +from pytools import memoize_in + + +def linear_operator_kernel(): + """Apply linear operator to all elements.""" + from meshmode.array_context import make_loopy_program + knl = make_loopy_program( + """{[iel,idof,j]: + 0<=iel Date: Mon, 2 Nov 2020 23:13:43 -0600 Subject: [PATCH 003/106] Updated modal smoothness indicator to mode_ids to select highest mode --- mirgecom/tag_cells.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/mirgecom/tag_cells.py b/mirgecom/tag_cells.py index 98fc21842..bf7e196d6 100644 --- a/mirgecom/tag_cells.py +++ b/mirgecom/tag_cells.py @@ -37,6 +37,7 @@ from meshmode.dof_array import DOFArray from modepy import vandermonde from pytools import memoize_in +from pytools.obj_array import make_obj_array def linear_operator_kernel(): @@ -52,7 +53,6 @@ def linear_operator_kernel(): knl = lp.tag_array_axes(knl, "mat", "stride:auto,stride:auto") return knl -#This is hardcoded for order=3 elements currently, working on generalizing def compute_smoothness_indicator(): """Compute the smoothness indicator for all elements.""" from meshmode.array_context import make_loopy_program @@ -61,8 +61,8 @@ def compute_smoothness_indicator(): 0<=iel Date: Fri, 6 Nov 2020 15:33:28 -0600 Subject: [PATCH 004/106] Fixed updated artificial viscosity implementation to use desired equations --- mirgecom/artificial_viscosity.py | 165 +++++++++++++++++++++---------- 1 file changed, 112 insertions(+), 53 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index c496e3a1e..20eb6eccb 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -28,7 +28,7 @@ #from dataclasses import dataclass import numpy as np -from pytools.obj_array import make_obj_array +from pytools.obj_array import make_obj_array, obj_array_vectorize, flat_obj_array,obj_array_vectorize_n_args from meshmode.dof_array import thaw from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa from grudge.eager import ( @@ -39,86 +39,145 @@ from mirgecom.euler import split_conserved, join_conserved -def scalar(s): - """Create an object array for a scalar.""" - return make_obj_array([s]) +def _facial_flux_r(discr, q_tpair): + dim = discr.dim + actx = q_tpair[0].int.array_context -def dissapative_flux(discr, q): + flux_dis = q_tpair.avg - dim = discr.dim - cv = split_conserved(dim, q) + normal = thaw(actx, discr.normal(q_tpair.dd)) - return join_conserved(dim, - mass=np.ones(dim)*scalar(cv.mass), - energy=np.ones(dim)*scalar(cv.energy), - momentum= np.ones((dim,dim))*cv.momentum ) + flux_out = flux_dis * normal + + # Can't do it here... "obj arrays not allowed on compute device" + #def flux_calc(flux): + # return (flux * normal) + #flux_out = obj_array_vectorize(flux_calc,flux_dis) -def _facial_flux(discr, q_tpair): + return discr.project(q_tpair.dd, "all_faces", flux_out) + +def _facial_flux_q(discr, q_tpair): dim = discr.dim actx = q_tpair[0].int.array_context - flux_int = dissapative_flux(discr,q_tpair.int); - flux_ext = dissapative_flux(discr,q_tpair.ext); - flux_dis = 0.5*(flux_ext + flux_int); - normal = thaw(actx, discr.normal(q_tpair.dd)) - flux_out = flux_dis @ normal + flux_out = np.dot(q_tpair.avg,normal) return discr.project(q_tpair.dd, "all_faces", flux_out) -def artificial_viscosity(discr, r): +def artificial_viscosity(discr, t, eos, boundaries, r, alpha): r"""Compute artifical viscosity for the euler equations """ - #compute dissapation flux - vol_flux_r = dissapative_flux(discr, r) - dflux_r = discr.weak_div(vol_flux_r) + #Cannot call weak_grad on obj of nd arrays, use obj_array_vectorize as work around + dflux_r = obj_array_vectorize(discr.weak_grad,r) + #interior face flux - iff_r = _facial_flux(discr, q_tpair=interior_trace_pair(discr,r)) - #partition boundaries flux - pbf_r = sum( - _facial_flux(discr, q_tpair=part_pair) - for part_pair in cross_rank_trace_pairs(discr, r) - ) + #Doesn't work: something related to obj on compute device + #Not 100% on reason + #qin = interior_trace_pair(discr,r) + #iff_r = _facial_flux(discr,q_tpair=qin) - #domain boundary flux - dir_r = discr.project("vol", BTAG_ALL,r) - dbf_r = _facial_flux( - discr, - q_tpair=TracePair(BTAG_ALL,interior=dir_r,exterior=dir_r) - ) + #Work around? + def my_facialflux_r_interior(q): + qin = interior_trace_pair(discr,make_obj_array([q])) + return _facial_flux_r(discr,q_tpair=qin) - q = discr.inverse_mass( 1.0e-2 * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r))) + iff_r = obj_array_vectorize(my_facialflux_r_interior,r) + + + #partition boundaries flux + #flux across partition boundaries + def my_facialflux_r_partition(q): + qin = cross_rank_trace_pairs(discr,q) + return sum(_facial_flux_r(discr,q_tpair=part_pair) for part_pair in cross_rank_trace_pairs(discr,make_obj_array([q])) ) + + pbf_r = obj_array_vectorize(my_facialflux_r_partition,r) + + #pbf_r = sum( + # _facial_flux_r(discr, q_tpair=part_pair) + # for part_pair in cross_rank_trace_pairs(discr, r) + #) + + #domain boundary flux basic boundary implementation + #def my_facialflux2(r): + # dir_r = discr.project("vol", BTAG_ALL,make_obj_array([r])) + # dbf_r = _facial_flux( + # discr, + # q_tpair=TracePair(BTAG_ALL,interior=dir_r,exterior=dir_r) + # ) + # return (dbf_r) + #dbf_r = obj_array_vectorize(my_facialflux2,r) + + + #True boundary implementation + #Okay, not sure about this... + #What I am attempting: + # 1. Loop through all the boundaries + # 2. Define a function my_TP that performes the trace pair for the given boundary + # given a solution variable + # 3. Get the external solution from the boundary routine + # 4. Get hte projected internal solution + # 5. Compute the boundary flux as a sum over boundaries, using the obj_array_vectorize to + # pass each solution variable one at a time + # DO I really need to do this like this? + dbf_r = 0.0*iff_r + for btag in boundaries: + def my_facialflux_r_boundary(sol_ext,sol_int): + q_tpair = TracePair(btag,interior=make_obj_array([sol_int]),exterior=make_obj_array([sol_ext])) + return _facial_flux_r(discr,q_tpair=q_tpair) + r_ext=boundaries[btag].interior_sol(discr,eos=eos,btag=btag,t=t,q=r) + r_int=discr.project("vol",btag,r) + dbf_r = dbf_r + obj_array_vectorize_n_args(my_facialflux_r_boundary,r_ext,r_int) + + + #Compute q, half way done! + q = discr.inverse_mass( -alpha * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r))) #flux of q - vol_flux_q = dissapative_flux(discr, q) - dflux_q = discr.weak_div(vol_flux_q) + + #Again we need to vectorize + #q is a object array of object arrays (dim,) of DOFArrays (?) + dflux_q = obj_array_vectorize(discr.weak_div,q) #interior face flux of q - iff_q = _facial_flux(discr, q_tpair=interior_trace_pair(discr,q)) + def my_facialflux_q_interior(q): + qin = interior_trace_pair(discr,q) + iff_q = _facial_flux_q(discr, q_tpair=qin) + return (iff_q) - #flux across partition boundaries - pbf_q = sum( - _facial_flux(discr, q_tpair=part_pair) - for part_pair in cross_rank_trace_pairs(discr, q) - ) - - #dombain boundary flux - dir_q = discr.project("vol",BTAG_ALL, q); - dbf_q = _facial_flux( - discr, - q_tpair=TracePair(BTAG_ALL,interior=dir_q,exterior=dir_q) - ) - + iff_q = obj_array_vectorize(my_facialflux_q_interior,q) - return discr.inverse_mass( - dflux_q - discr.face_mass(iff_q + pbf_q + dbf_q) - ) + #flux across partition boundaries + def my_facialflux_q_partition(q): + qin = cross_rank_trace_pairs(discr,q) + return sum(_facial_flux_q(discr,q_tpair=part_pair) for part_pair in cross_rank_trace_pairs(discr,make_obj_array([q])) ) + + pbf_q = obj_array_vectorize(my_facialflux_q_partition,q) + #pbf_q = sum( + # _facial_flux_q(discr, q_tpair=part_pair) + # for part_pair in cross_rank_trace_pairs(discr, q) + #) + + def my_facialflux_q_boundary(q): + #dombain boundary flux + dir_q = discr.project("vol",BTAG_ALL, q); + dbf_q = _facial_flux_q( + discr, + q_tpair=TracePair(BTAG_ALL,interior=dir_q,exterior=dir_q) + ) + return(dbf_q) + + dbf_q = obj_array_vectorize(my_facialflux_q_boundary,q) + + #Return the rhs contribution + return ( discr.inverse_mass( -dflux_q + discr.face_mass(iff_q + pbf_q + dbf_q) ) ) + From 822d86394aa88dc04cf47d1991a3d07bffff923c Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 6 Nov 2020 15:41:13 -0600 Subject: [PATCH 005/106] Add boundary condition function to return projected boundary solution --- mirgecom/artificial_viscosity.py | 2 +- mirgecom/boundary.py | 143 +++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 20eb6eccb..7711cd7fc 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -133,7 +133,7 @@ def my_facialflux_r_partition(q): def my_facialflux_r_boundary(sol_ext,sol_int): q_tpair = TracePair(btag,interior=make_obj_array([sol_int]),exterior=make_obj_array([sol_ext])) return _facial_flux_r(discr,q_tpair=q_tpair) - r_ext=boundaries[btag].interior_sol(discr,eos=eos,btag=btag,t=t,q=r) + r_ext=boundaries[btag].exterior_sol(discr,eos=eos,btag=btag,t=t,q=r) r_int=discr.project("vol",btag,r) dbf_r = dbf_r + obj_array_vectorize_n_args(my_facialflux_r_boundary,r_ext,r_int) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index c867f94c1..86fe509d2 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -5,6 +5,7 @@ .. autoclass:: PrescribedBoundary .. autoclass:: DummyBoundary +.. autoclass:: AdiabaticSlipBoundary """ __copyright__ = """ @@ -31,10 +32,14 @@ THE SOFTWARE. """ +import numpy as np +from pytools.obj_array import make_obj_array from meshmode.dof_array import thaw from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa from mirgecom.eos import IdealSingleGas +# from mirgecom.euler import split_conserved from grudge.symbolic.primitives import TracePair +from mirgecom.euler import split_conserved, join_conserved class PrescribedBoundary: @@ -67,6 +72,17 @@ def boundary_pair( int_soln = discr.project("vol", btag, q) return TracePair(btag, interior=int_soln, exterior=ext_soln) + def exterior_sol( + self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() + ): + """Get the interior solution on the boundary.""" + actx = q[0].array_context + + boundary_discr = discr.discr_from_dd(btag) + nodes = thaw(actx, boundary_discr.nodes()) + ext_soln = self._userfunc(t, nodes) + return ext_soln + class DummyBoundary: """Use the boundary-adjacent solution as the boundary solution. @@ -74,9 +90,136 @@ class DummyBoundary: .. automethod:: boundary_pair """ + def __init__(self): + """Initialize dummy boundary.""" + self.test = 1 + def boundary_pair( self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() ): """Get the interior and exterior solution on the boundary.""" dir_soln = discr.project("vol", btag, q) return TracePair(btag, interior=dir_soln, exterior=dir_soln) + + def exterior_sol( + self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() + ): + """Get the interior and exterior solution on the boundary.""" + dir_soln = discr.project("vol", btag, q) + return dir_soln + +class AdiabaticSlipBoundary: + """Adiabatic slip boundary for inviscid flows. + + a.k.a. Reflective inviscid wall boundary + + This class implements an adiabatic reflective slip boundary + wherein the normal component of velocity at the wall is 0, and + tangential components are preserved. These perfectly reflecting + conditions are used by the forward-facing step case in + JSH/TW Nodal DG Methods, Section 6.6 DOI: 10.1007/978-0-387-72067-8 and + described in detail by Poinsot and Lele's JCP paper + http://acoustics.ae.illinois.edu/pdfs/poinsot-lele-1992.pdf + + .. automethod:: boundary_pair + """ + + def __init__(self): + """Create the adiabatic slip boundary.""" + self.test = 1 + + def boundary_pair( + self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() + ): + """Get the interior and exterior solution on the boundary. + + The exterior solution is set such that there will be vanishing + flux through the boundary, preserving mass, momentum (magnitude) and + energy. + rho_plus = rho_minus + v_plus = v_minus - 2 * (v_minus . n_hat) * n_hat + mom_plus = rho_plus * v_plus + E_plus = E_minus + """ + # Grab some boundary-relevant data + dim = discr.dim + cv = split_conserved(dim, q) + actx = cv.mass.array_context + + # Grab a unit normal to the boundary + normal = thaw(actx, discr.normal(btag)) + normal_mag = actx.np.sqrt(np.dot(normal, normal)) + nhat_mult = 1.0 / normal_mag + nhat = normal * make_obj_array([nhat_mult]) + + # Get the interior/exterior solns + int_soln = discr.project("vol", btag, q) + bndry_cv = split_conserved(dim, int_soln) + # bpressure = eos.pressure(bndry_cv) + + # Subtract out the 2*wall-normal component + # of velocity from the velocity at the wall to + # induce an equal but opposite wall-normal (reflected) wave + # preserving the tangential component + wall_velocity = bndry_cv.momentum / make_obj_array([bndry_cv.mass]) + nvel_comp = np.dot(wall_velocity, nhat) # part of velocity normal to wall + wnorm_vel = nhat * make_obj_array([nvel_comp]) # wall-normal velocity vec + wall_velocity = wall_velocity - 2.0 * wnorm_vel # prescribed ext velocity + + # Re-calculate the boundary solution with the new + # momentum + bndry_cv.momentum = wall_velocity * make_obj_array([bndry_cv.mass]) + # bndry_cv.energy = eos.total_energy(bndry_cv, bpressure) + bndry_soln = join_conserved(dim=dim, mass=bndry_cv.mass, + energy=bndry_cv.energy, + momentum=bndry_cv.momentum) + + return TracePair(btag, interior=int_soln, exterior=bndry_soln) + + def exterior_sol( + self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() + ): + """Get the interior and exterior solution on the boundary. + + The exterior solution is set such that there will be vanishing + flux through the boundary, preserving mass, momentum (magnitude) and + energy. + rho_plus = rho_minus + v_plus = v_minus - 2 * (v_minus . n_hat) * n_hat + mom_plus = rho_plus * v_plus + E_plus = E_minus + """ + # Grab some boundary-relevant data + dim = discr.dim + cv = split_conserved(dim, q) + actx = cv.mass.array_context + + # Grab a unit normal to the boundary + normal = thaw(actx, discr.normal(btag)) + normal_mag = actx.np.sqrt(np.dot(normal, normal)) + nhat_mult = 1.0 / normal_mag + nhat = normal * make_obj_array([nhat_mult]) + + # Get the interior/exterior solns + int_soln = discr.project("vol", btag, q) + bndry_cv = split_conserved(dim, int_soln) + # bpressure = eos.pressure(bndry_cv) + + # Subtract out the 2*wall-normal component + # of velocity from the velocity at the wall to + # induce an equal but opposite wall-normal (reflected) wave + # preserving the tangential component + wall_velocity = bndry_cv.momentum / make_obj_array([bndry_cv.mass]) + nvel_comp = np.dot(wall_velocity, nhat) # part of velocity normal to wall + wnorm_vel = nhat * make_obj_array([nvel_comp]) # wall-normal velocity vec + wall_velocity = wall_velocity - 2.0 * wnorm_vel # prescribed ext velocity + + # Re-calculate the boundary solution with the new + # momentum + bndry_cv.momentum = wall_velocity * make_obj_array([bndry_cv.mass]) + # bndry_cv.energy = eos.total_energy(bndry_cv, bpressure) + bndry_soln = join_conserved(dim=dim, mass=bndry_cv.mass, + energy=bndry_cv.energy, + momentum=bndry_cv.momentum) + + return bndry_soln From e0f0ce43e1c76017aa301827ab854890b81ed474 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 6 Nov 2020 15:41:58 -0600 Subject: [PATCH 006/106] Added double mach reflection example problem --- examples/doublemach-mpi.py | 181 +++++++++++++++++++++++++++++++++++++ mirgecom/initializers.py | 115 +++++++++++++++++++++++ 2 files changed, 296 insertions(+) create mode 100644 examples/doublemach-mpi.py diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py new file mode 100644 index 000000000..be32f4ac5 --- /dev/null +++ b/examples/doublemach-mpi.py @@ -0,0 +1,181 @@ +__copyright__ = """ +Copyright (C) 2020 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. +""" +import logging +import pyopencl as cl +import pyopencl.tools as cl_tools +from functools import partial + +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 +from grudge.shortcuts import make_visualizer + + +from mirgecom.euler import inviscid_operator +from mirgecom.artificial_viscosity import artificial_viscosity +from mirgecom.heat import heat_operator +from mirgecom.simutil import ( + inviscid_sim_timestep, + sim_checkpoint, + create_parallel_grid, + ExactSolutionMismatch, +) +from mirgecom.io import make_init_message +from mirgecom.mpi import mpi_entry_point + +from mirgecom.integrators import rk4_step +from mirgecom.steppers import advance_state +from mirgecom.boundary import AdiabaticSlipBoundary, PrescribedBoundary +from mirgecom.initializers import DoubleMachReflection, SodShock1D +from mirgecom.eos import IdealSingleGas + +from pytools.obj_array import obj_array_vectorize + +logger = logging.getLogger(__name__) + + +@mpi_entry_point +def main(ctx_factory=cl.create_some_context): + cl_ctx = ctx_factory() + queue = cl.CommandQueue(cl_ctx) + actx = PyOpenCLArrayContext(queue, + allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue))) + + dim = 2 + nel = (40,10) + order = 3 + # tolerate large errors; case is unstable + exittol = 2.0 #.2 + t_final = 1.0 + current_cfl = 0.1 + current_dt = .00031250 + current_t = 0 + eos = IdealSingleGas() + initializer = DoubleMachReflection(dim) + #initializer = SodShock1D(dim,x0=0.5) + casename = "sod1d" + #boundaries = {BTAG_ALL: AdiabaticSlipBoundary()} + from grudge import sym + boundaries = {sym.DTAG_BOUNDARY("ic1"): PrescribedBoundary(initializer), + sym.DTAG_BOUNDARY("ic2"): PrescribedBoundary(initializer), + sym.DTAG_BOUNDARY("ic3"): PrescribedBoundary(initializer), + sym.DTAG_BOUNDARY("wall"): AdiabaticSlipBoundary(), + sym.DTAG_BOUNDARY("out"): AdiabaticSlipBoundary()} + constant_cfl = False + nstatus = 10 + nviz = 25 + rank = 0 + checkpoint_t = current_t + current_step = 0 + timestepper = rk4_step + box_ll = (0.0,0.0) + box_ur = (4.0,1.0) + + from mpi4py import MPI + comm = MPI.COMM_WORLD + rank = comm.Get_rank() + + #from meshmode.mesh.generation import generate_regular_rect_mesh + #generate_grid = partial(generate_regular_rect_mesh, a=box_ll, + # b=box_ur, n=nel ) + #local_mesh, global_nelements = create_parallel_grid(comm, generate_grid) + + + from meshmode.mesh.io import read_gmsh, generate_gmsh, ScriptWithFilesSource + local_mesh = read_gmsh("doubleMach1.msh",force_ambient_dim=2) + global_nelements = local_mesh.nelements + + local_nelements = local_mesh.nelements + + discr = EagerDGDiscretization( + actx, local_mesh, order=order, mpi_communicator=comm + ) + nodes = thaw(actx, discr.nodes()) + current_state = initializer(0, nodes) + + #visualizer = make_visualizer(discr, discr.order + 3 + # if discr.dim == 2 else discr.order) + visualizer = make_visualizer(discr, discr.order + if discr.dim == 2 else discr.order) + initname = initializer.__class__.__name__ + eosname = eos.__class__.__name__ + init_message = make_init_message(dim=dim, order=order, + nelements=local_nelements, + global_nelements=global_nelements, + dt=current_dt, t_final=t_final, nstatus=nstatus, + nviz=nviz, cfl=current_cfl, + constant_cfl=constant_cfl, initname=initname, + eosname=eosname, casename=casename) + if rank == 0: + logger.info(init_message) + + get_timestep = partial(inviscid_sim_timestep, discr=discr, t=current_t, + dt=current_dt, cfl=current_cfl, eos=eos, + t_final=t_final, constant_cfl=constant_cfl) + def my_av(state): + return (heat_operator(discr,alpha=1.0e-3,w=state) ) + + def my_rhs(t, state): + return ( + inviscid_operator(discr, q=state, t=t,boundaries=boundaries, eos=eos) + + artificial_viscosity(discr,t=t, r=state, eos=eos, boundaries=boundaries, alpha=4.0e-2) + ) + #return ( + # inviscid_operator(discr, q=state, t=t,boundaries=boundaries, eos=eos) + # + artificial_viscosity(discr, r=state, eos=eos, boundaries=boundaries, alpha=1.0e-3) + + def my_checkpoint(step, t, dt, state): + return sim_checkpoint(discr, visualizer, eos, q=state, + vizname=casename, step=step, + t=t, dt=dt, nstatus=nstatus, nviz=nviz, + exittol=exittol, constant_cfl=constant_cfl, comm=comm) + + try: + (current_step, current_t, current_state) = \ + advance_state(rhs=my_rhs, timestepper=timestepper, + checkpoint=my_checkpoint, + get_timestep=get_timestep, state=current_state, + t=current_t, t_final=t_final) + except ExactSolutionMismatch as ex: + current_step = ex.step + current_t = ex.t + current_state = ex.state + + # if current_t != checkpoint_t: + if rank == 0: + logger.info("Checkpointing final state ...") + my_checkpoint(current_step, t=current_t, + dt=(current_t - checkpoint_t), + state=current_state) + + if current_t - t_final < 0: + raise ValueError("Simulation exited abnormally") + + +if __name__ == "__main__": + logging.basicConfig(format="%(message)s", level=logging.INFO) + main() + +# vim: foldmethod=marker diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index e873ae117..a28ce7187 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -5,6 +5,7 @@ ^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: Vortex2D .. autoclass:: SodShock1D +.. autoclass:: DoubleMachReflection .. autoclass:: Lump .. autoclass:: Uniform """ @@ -212,6 +213,120 @@ def __call__(self, t, x_vec, eos=IdealSingleGas()): return flat_obj_array(mass, energy, mom) +class DoubleMachReflection: + r"""Implement the double shock reflection problem + + - Woodward and Collela + + The inital condition is defined + + .. math:: + + (\rho,u,v,P) = + + This function only serves as an initial condition + + .. automethod:: __init__ + .. automethod:: __call__ + """ + + def __init__( + self,dim=2, x0=1.0/6.0, us=4.0 + ): + """Initialize initial condition options + + Parameters + ---------- + dim: int + dimension of domain, must be 2 + x0: float + location of shock + us: float + shock speed + """ + self._x0 = x0 + self._dim = dim + self._us = us + + def __call__(self, t, x_vec, eos=IdealSingleGas()): + """ + Create the 1D Sod's shock solution at locations *x_vec*. + + Parameters + ---------- + t: float + Current time at which the solution is desired (unused) + x_vec: numpy.ndarray + Nodal coordinates + eos: :class:`mirgecom.eos.GasEOS` + Equation of state class to be used in construction of soln (if needed) + """ + assert self._dim == 2, "only defined for dim=2" + + gm1 = eos.gamma() - 1.0 + gmn1 = 1.0 / gm1 + x_rel = x_vec[0] + y_rel = x_vec[1] + actx = x_rel.array_context + + zeros = 0*x_rel + + x0 = zeros + self._x0 + us = zeros + self._us + t = zeros + t + + + #Mach 10 + #rhol = zeros + 8.0 + #rhor = zeros + 1.4 + + #ul = zeros + 8.25*np.cos(np.pi/6.0) + #ur = zeros + 0.0 + #vl = zeros - 8.25*np.sin(np.pi/6.0) + #vr = zeros + 0.0 + #rhoel = zeros + gmn1 * 116.5 + #rhoer = zeros + gmn1 * 1.0 + + #Mach 2.0 + #rhol = zeros + 2.666666*1.4 + #rhor = zeros + 1.4 + + #ul = zeros + 1.25*np.cos(np.pi/6.0) + #ur = zeros + 0.0 + #vl = zeros - 1.25*np.sin(np.pi/6.0) + #vr = zeros + 0.0 + #rhoel = zeros + gmn1 * 4.5 + #rhoer = zeros + gmn1 * 1.0 + + #Mach 4.0 + rhol = zeros + 4.57142857*1.4 + rhor = zeros + 1.4 + + ul = zeros + 3.125*np.cos(np.pi/6.0) + ur = zeros + 0.0 + vl = zeros - 3.125*np.sin(np.pi/6.0) + vr = zeros + 0.0 + rhoel = zeros + gmn1 * 18.5 + rhoer = zeros + gmn1 * 1.0 + + #yesno = x_rel > (x0 + y_rel/np.sqrt(3.0) + 2.0*us*t/np.sqrt(3.0)) + #mass = actx.np.where(yesno, rhor, rhol) + #rhoe = actx.np.where(yesno, rhoer, rhoel) + #u = actx.np.where(yesno, ur, ul) + #v = actx.np.where(yesno, vr, vl) + xinter = (x0 + y_rel/np.sqrt(3.0) + 2.0*us*t/np.sqrt(3.0)) + sigma=0.05 + xtanh = 1.0/sigma*(x_rel-xinter) + mass = rhol/2.0*(actx.np.tanh(-xtanh)+1.0)+rhor/2.0*(actx.np.tanh(xtanh)+1.0) + rhoe = rhoel/2.0*(actx.np.tanh(-xtanh)+1.0)+rhoer/2.0*(actx.np.tanh(xtanh)+1.0) + u = ul/2.0*(actx.np.tanh(-xtanh)+1.0)+ur/2.0*(actx.np.tanh(xtanh)+1.0) + v = vl/2.0*(actx.np.tanh(-xtanh)+1.0)+vr/2.0*(actx.np.tanh(xtanh)+1.0) + rhou = mass*u + rhov = mass*v + energy = rhoe + 0.5*mass*(u*u + v*v) + + return flat_obj_array(mass, energy, rhou, rhov) + class Lump: r"""Implement an N-dimensional Gaussian lump of mass. From d35771a069b10b87ccc7ae790932c058c6bfb14f Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 6 Nov 2020 15:41:58 -0600 Subject: [PATCH 007/106] Added double mach reflection example problem --- examples/doublemach-mpi.py | 180 +++++++++++++++++++++++++++++++++++++ mirgecom/initializers.py | 115 ++++++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 examples/doublemach-mpi.py diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py new file mode 100644 index 000000000..6410e0e36 --- /dev/null +++ b/examples/doublemach-mpi.py @@ -0,0 +1,180 @@ +__copyright__ = """ +Copyright (C) 2020 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. +""" +import logging +import pyopencl as cl +import pyopencl.tools as cl_tools +from functools import partial + +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 +from grudge.shortcuts import make_visualizer + + +from mirgecom.euler import inviscid_operator +from mirgecom.artificial_viscosity import artificial_viscosity +from mirgecom.simutil import ( + inviscid_sim_timestep, + sim_checkpoint, + create_parallel_grid, + ExactSolutionMismatch, +) +from mirgecom.io import make_init_message +from mirgecom.mpi import mpi_entry_point + +from mirgecom.integrators import rk4_step +from mirgecom.steppers import advance_state +from mirgecom.boundary import AdiabaticSlipBoundary, PrescribedBoundary +from mirgecom.initializers import DoubleMachReflection, SodShock1D +from mirgecom.eos import IdealSingleGas + +from pytools.obj_array import obj_array_vectorize + +logger = logging.getLogger(__name__) + + +@mpi_entry_point +def main(ctx_factory=cl.create_some_context): + cl_ctx = ctx_factory() + queue = cl.CommandQueue(cl_ctx) + actx = PyOpenCLArrayContext(queue, + allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue))) + + dim = 2 + nel = (40,10) + order = 3 + # tolerate large errors; case is unstable + exittol = 2.0 #.2 + t_final = 1.0 + current_cfl = 0.1 + current_dt = .00031250 + current_t = 0 + eos = IdealSingleGas() + initializer = DoubleMachReflection(dim) + #initializer = SodShock1D(dim,x0=0.5) + casename = "sod1d" + #boundaries = {BTAG_ALL: AdiabaticSlipBoundary()} + from grudge import sym + boundaries = {sym.DTAG_BOUNDARY("ic1"): PrescribedBoundary(initializer), + sym.DTAG_BOUNDARY("ic2"): PrescribedBoundary(initializer), + sym.DTAG_BOUNDARY("ic3"): PrescribedBoundary(initializer), + sym.DTAG_BOUNDARY("wall"): AdiabaticSlipBoundary(), + sym.DTAG_BOUNDARY("out"): AdiabaticSlipBoundary()} + constant_cfl = False + nstatus = 10 + nviz = 25 + rank = 0 + checkpoint_t = current_t + current_step = 0 + timestepper = rk4_step + box_ll = (0.0,0.0) + box_ur = (4.0,1.0) + + from mpi4py import MPI + comm = MPI.COMM_WORLD + rank = comm.Get_rank() + + #from meshmode.mesh.generation import generate_regular_rect_mesh + #generate_grid = partial(generate_regular_rect_mesh, a=box_ll, + # b=box_ur, n=nel ) + #local_mesh, global_nelements = create_parallel_grid(comm, generate_grid) + + + from meshmode.mesh.io import read_gmsh, generate_gmsh, ScriptWithFilesSource + local_mesh = read_gmsh("doubleMach1.msh",force_ambient_dim=2) + global_nelements = local_mesh.nelements + + local_nelements = local_mesh.nelements + + discr = EagerDGDiscretization( + actx, local_mesh, order=order, mpi_communicator=comm + ) + nodes = thaw(actx, discr.nodes()) + current_state = initializer(0, nodes) + + #visualizer = make_visualizer(discr, discr.order + 3 + # if discr.dim == 2 else discr.order) + visualizer = make_visualizer(discr, discr.order + if discr.dim == 2 else discr.order) + initname = initializer.__class__.__name__ + eosname = eos.__class__.__name__ + init_message = make_init_message(dim=dim, order=order, + nelements=local_nelements, + global_nelements=global_nelements, + dt=current_dt, t_final=t_final, nstatus=nstatus, + nviz=nviz, cfl=current_cfl, + constant_cfl=constant_cfl, initname=initname, + eosname=eosname, casename=casename) + if rank == 0: + logger.info(init_message) + + get_timestep = partial(inviscid_sim_timestep, discr=discr, t=current_t, + dt=current_dt, cfl=current_cfl, eos=eos, + t_final=t_final, constant_cfl=constant_cfl) + def my_av(state): + return (heat_operator(discr,alpha=1.0e-3,w=state) ) + + def my_rhs(t, state): + return ( + inviscid_operator(discr, q=state, t=t,boundaries=boundaries, eos=eos) + + artificial_viscosity(discr,t=t, r=state, eos=eos, boundaries=boundaries, alpha=4.0e-2) + ) + #return ( + # inviscid_operator(discr, q=state, t=t,boundaries=boundaries, eos=eos) + # + artificial_viscosity(discr, r=state, eos=eos, boundaries=boundaries, alpha=1.0e-3) + + def my_checkpoint(step, t, dt, state): + return sim_checkpoint(discr, visualizer, eos, q=state, + vizname=casename, step=step, + t=t, dt=dt, nstatus=nstatus, nviz=nviz, + exittol=exittol, constant_cfl=constant_cfl, comm=comm) + + try: + (current_step, current_t, current_state) = \ + advance_state(rhs=my_rhs, timestepper=timestepper, + checkpoint=my_checkpoint, + get_timestep=get_timestep, state=current_state, + t=current_t, t_final=t_final) + except ExactSolutionMismatch as ex: + current_step = ex.step + current_t = ex.t + current_state = ex.state + + # if current_t != checkpoint_t: + if rank == 0: + logger.info("Checkpointing final state ...") + my_checkpoint(current_step, t=current_t, + dt=(current_t - checkpoint_t), + state=current_state) + + if current_t - t_final < 0: + raise ValueError("Simulation exited abnormally") + + +if __name__ == "__main__": + logging.basicConfig(format="%(message)s", level=logging.INFO) + main() + +# vim: foldmethod=marker diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index e873ae117..a28ce7187 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -5,6 +5,7 @@ ^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: Vortex2D .. autoclass:: SodShock1D +.. autoclass:: DoubleMachReflection .. autoclass:: Lump .. autoclass:: Uniform """ @@ -212,6 +213,120 @@ def __call__(self, t, x_vec, eos=IdealSingleGas()): return flat_obj_array(mass, energy, mom) +class DoubleMachReflection: + r"""Implement the double shock reflection problem + + - Woodward and Collela + + The inital condition is defined + + .. math:: + + (\rho,u,v,P) = + + This function only serves as an initial condition + + .. automethod:: __init__ + .. automethod:: __call__ + """ + + def __init__( + self,dim=2, x0=1.0/6.0, us=4.0 + ): + """Initialize initial condition options + + Parameters + ---------- + dim: int + dimension of domain, must be 2 + x0: float + location of shock + us: float + shock speed + """ + self._x0 = x0 + self._dim = dim + self._us = us + + def __call__(self, t, x_vec, eos=IdealSingleGas()): + """ + Create the 1D Sod's shock solution at locations *x_vec*. + + Parameters + ---------- + t: float + Current time at which the solution is desired (unused) + x_vec: numpy.ndarray + Nodal coordinates + eos: :class:`mirgecom.eos.GasEOS` + Equation of state class to be used in construction of soln (if needed) + """ + assert self._dim == 2, "only defined for dim=2" + + gm1 = eos.gamma() - 1.0 + gmn1 = 1.0 / gm1 + x_rel = x_vec[0] + y_rel = x_vec[1] + actx = x_rel.array_context + + zeros = 0*x_rel + + x0 = zeros + self._x0 + us = zeros + self._us + t = zeros + t + + + #Mach 10 + #rhol = zeros + 8.0 + #rhor = zeros + 1.4 + + #ul = zeros + 8.25*np.cos(np.pi/6.0) + #ur = zeros + 0.0 + #vl = zeros - 8.25*np.sin(np.pi/6.0) + #vr = zeros + 0.0 + #rhoel = zeros + gmn1 * 116.5 + #rhoer = zeros + gmn1 * 1.0 + + #Mach 2.0 + #rhol = zeros + 2.666666*1.4 + #rhor = zeros + 1.4 + + #ul = zeros + 1.25*np.cos(np.pi/6.0) + #ur = zeros + 0.0 + #vl = zeros - 1.25*np.sin(np.pi/6.0) + #vr = zeros + 0.0 + #rhoel = zeros + gmn1 * 4.5 + #rhoer = zeros + gmn1 * 1.0 + + #Mach 4.0 + rhol = zeros + 4.57142857*1.4 + rhor = zeros + 1.4 + + ul = zeros + 3.125*np.cos(np.pi/6.0) + ur = zeros + 0.0 + vl = zeros - 3.125*np.sin(np.pi/6.0) + vr = zeros + 0.0 + rhoel = zeros + gmn1 * 18.5 + rhoer = zeros + gmn1 * 1.0 + + #yesno = x_rel > (x0 + y_rel/np.sqrt(3.0) + 2.0*us*t/np.sqrt(3.0)) + #mass = actx.np.where(yesno, rhor, rhol) + #rhoe = actx.np.where(yesno, rhoer, rhoel) + #u = actx.np.where(yesno, ur, ul) + #v = actx.np.where(yesno, vr, vl) + xinter = (x0 + y_rel/np.sqrt(3.0) + 2.0*us*t/np.sqrt(3.0)) + sigma=0.05 + xtanh = 1.0/sigma*(x_rel-xinter) + mass = rhol/2.0*(actx.np.tanh(-xtanh)+1.0)+rhor/2.0*(actx.np.tanh(xtanh)+1.0) + rhoe = rhoel/2.0*(actx.np.tanh(-xtanh)+1.0)+rhoer/2.0*(actx.np.tanh(xtanh)+1.0) + u = ul/2.0*(actx.np.tanh(-xtanh)+1.0)+ur/2.0*(actx.np.tanh(xtanh)+1.0) + v = vl/2.0*(actx.np.tanh(-xtanh)+1.0)+vr/2.0*(actx.np.tanh(xtanh)+1.0) + rhou = mass*u + rhov = mass*v + energy = rhoe + 0.5*mass*(u*u + v*v) + + return flat_obj_array(mass, energy, rhou, rhov) + class Lump: r"""Implement an N-dimensional Gaussian lump of mass. From 0f132ebeca5b1fb5f422128cd4bcf0048c22f217 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 20 Nov 2020 11:54:38 -0800 Subject: [PATCH 008/106] Fixed error in calculating face fluxes across ranks --- mirgecom/artificial_viscosity.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 7711cd7fc..4d9679e25 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -96,8 +96,8 @@ def my_facialflux_r_interior(q): #partition boundaries flux #flux across partition boundaries def my_facialflux_r_partition(q): - qin = cross_rank_trace_pairs(discr,q) - return sum(_facial_flux_r(discr,q_tpair=part_pair) for part_pair in cross_rank_trace_pairs(discr,make_obj_array([q])) ) + qin = cross_rank_trace_pairs(discr,make_obj_array([q])) + return sum(_facial_flux_r(discr,q_tpair=part_pair) for part_pair in qin ) pbf_r = obj_array_vectorize(my_facialflux_r_partition,r) @@ -159,7 +159,7 @@ def my_facialflux_q_interior(q): #flux across partition boundaries def my_facialflux_q_partition(q): qin = cross_rank_trace_pairs(discr,q) - return sum(_facial_flux_q(discr,q_tpair=part_pair) for part_pair in cross_rank_trace_pairs(discr,make_obj_array([q])) ) + return sum(_facial_flux_q(discr,q_tpair=part_pair) for part_pair in qin) pbf_q = obj_array_vectorize(my_facialflux_q_partition,q) #pbf_q = sum( From 40656f36bfc206c2b8795536ce3851ca9b9347b2 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 20 Nov 2020 12:02:10 -0800 Subject: [PATCH 009/106] Removed unessecary reference to heat operator --- examples/doublemach-mpi.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 6410e0e36..fc3f82fc1 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -133,8 +133,6 @@ def main(ctx_factory=cl.create_some_context): get_timestep = partial(inviscid_sim_timestep, discr=discr, t=current_t, dt=current_dt, cfl=current_cfl, eos=eos, t_final=t_final, constant_cfl=constant_cfl) - def my_av(state): - return (heat_operator(discr,alpha=1.0e-3,w=state) ) def my_rhs(t, state): return ( From d49de5992eee602fdce2d9722d810c4645ed51ff Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 20 Nov 2020 12:04:59 -0800 Subject: [PATCH 010/106] Fixed error in not distributing grid --- examples/doublemach-mpi.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index fc3f82fc1..d583259a2 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -103,8 +103,10 @@ def main(ctx_factory=cl.create_some_context): from meshmode.mesh.io import read_gmsh, generate_gmsh, ScriptWithFilesSource - local_mesh = read_gmsh("doubleMach1.msh",force_ambient_dim=2) - global_nelements = local_mesh.nelements + + gen_grid = partial(read_gmsh,"doubleMach2.msh",force_ambient_dim=2) + + local_mesh, global_nelements = create_parallel_grid(comm, gen_grid) local_nelements = local_mesh.nelements From 80e1a62f2da68c79404e373fc13d6e0105558c6d Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 20 Nov 2020 12:37:59 -0800 Subject: [PATCH 011/106] Added shock indicator and integrated with artificial viscosity --- mirgecom/artificial_viscosity.py | 9 ++++++++- mirgecom/tag_cells.py | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 4d9679e25..4459966cb 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -37,6 +37,7 @@ ) from grudge.symbolic.primitives import TracePair from mirgecom.euler import split_conserved, join_conserved +from mirgecom.tag_cells import smoothness_indicator def _facial_flux_r(discr, q_tpair): @@ -73,6 +74,12 @@ def artificial_viscosity(discr, t, eos, boundaries, r, alpha): r"""Compute artifical viscosity for the euler equations """ + #Get smoothness indicator + epsilon = np.zeros((2+discr.dim,),dtype=object) + indicator = make_obj_array([smoothness_indicator(r[0],discr)]) + for i in range(2+discr.dim): + epsilon[i] = indicator + #compute dissapation flux #Cannot call weak_grad on obj of nd arrays, use obj_array_vectorize as work around @@ -139,7 +146,7 @@ def my_facialflux_r_boundary(sol_ext,sol_int): #Compute q, half way done! - q = discr.inverse_mass( -alpha * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r))) + q = discr.inverse_mass( -alpha * epsilon * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r))) #flux of q diff --git a/mirgecom/tag_cells.py b/mirgecom/tag_cells.py index bf7e196d6..2addfe234 100644 --- a/mirgecom/tag_cells.py +++ b/mirgecom/tag_cells.py @@ -62,7 +62,7 @@ def compute_smoothness_indicator(): 0<=idof (so-kappa) + yesnou = indicator > (so+kappa) + sin_indicator = actx.np.where(yesnol,0.5*(1.0+actx.np.sin(np.pi *(indicator - so)/(2.0*kappa))),0.0*indicator) + indicator = actx.np.where(yesnou,1.0+0.0*indicator,sin_indicator) return indicator From 0c25238c987595af28f6e0452cd29db7c07caba9 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 20 Nov 2020 12:38:30 -0800 Subject: [PATCH 012/106] Added output field for shock indicator --- mirgecom/simutil.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mirgecom/simutil.py b/mirgecom/simutil.py index 2ca30e306..9565be569 100644 --- a/mirgecom/simutil.py +++ b/mirgecom/simutil.py @@ -104,6 +104,9 @@ def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, from mirgecom.euler import split_conserved cv = split_conserved(discr.dim, q) dependent_vars = eos.dependent_vars(cv) + + from mirgecom.tag_cells import smoothness_indicator + tagedcells = smoothness_indicator(q[0],discr) rank = 0 if comm is not None: @@ -121,7 +124,8 @@ def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, if do_viz: io_fields = [ ("cv", cv), - ("dv", dependent_vars) + ("dv", dependent_vars), + ("tagged", tagedcells) ] if exact_soln is not None: exact_list = [ From 96fc18cf15b52a5b53ee8e1f2ac4412bb1922cfb Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Tue, 1 Dec 2020 15:12:11 -0800 Subject: [PATCH 013/106] Modified stepping parameters for scaling tests --- examples/doublemach-mpi.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index d583259a2..1ea5a2bab 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -67,9 +67,9 @@ def main(ctx_factory=cl.create_some_context): order = 3 # tolerate large errors; case is unstable exittol = 2.0 #.2 - t_final = 1.0 + t_final = 0.0001 current_cfl = 0.1 - current_dt = .00031250 + current_dt = .000001 current_t = 0 eos = IdealSingleGas() initializer = DoubleMachReflection(dim) @@ -84,7 +84,7 @@ def main(ctx_factory=cl.create_some_context): sym.DTAG_BOUNDARY("out"): AdiabaticSlipBoundary()} constant_cfl = False nstatus = 10 - nviz = 25 + nviz = 100 rank = 0 checkpoint_t = current_t current_step = 0 @@ -96,11 +96,6 @@ def main(ctx_factory=cl.create_some_context): comm = MPI.COMM_WORLD rank = comm.Get_rank() - #from meshmode.mesh.generation import generate_regular_rect_mesh - #generate_grid = partial(generate_regular_rect_mesh, a=box_ll, - # b=box_ur, n=nel ) - #local_mesh, global_nelements = create_parallel_grid(comm, generate_grid) - from meshmode.mesh.io import read_gmsh, generate_gmsh, ScriptWithFilesSource @@ -139,7 +134,7 @@ def main(ctx_factory=cl.create_some_context): def my_rhs(t, state): return ( inviscid_operator(discr, q=state, t=t,boundaries=boundaries, eos=eos) - + artificial_viscosity(discr,t=t, r=state, eos=eos, boundaries=boundaries, alpha=4.0e-2) + + artificial_viscosity(discr,t=t, r=state, eos=eos, boundaries=boundaries, alpha=2.0e-2) ) #return ( # inviscid_operator(discr, q=state, t=t,boundaries=boundaries, eos=eos) From 446cacea6e57913892d50bb4cc43d7f9b638d652 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Wed, 20 Jan 2021 15:42:22 -0800 Subject: [PATCH 014/106] Fixed artifical viscosity boundary conditions --- mirgecom/artificial_viscosity.py | 41 +++++++------------------ mirgecom/boundary.py | 51 ++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 4459966cb..b0e7b8b42 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -108,21 +108,6 @@ def my_facialflux_r_partition(q): pbf_r = obj_array_vectorize(my_facialflux_r_partition,r) - #pbf_r = sum( - # _facial_flux_r(discr, q_tpair=part_pair) - # for part_pair in cross_rank_trace_pairs(discr, r) - #) - - #domain boundary flux basic boundary implementation - #def my_facialflux2(r): - # dir_r = discr.project("vol", BTAG_ALL,make_obj_array([r])) - # dbf_r = _facial_flux( - # discr, - # q_tpair=TracePair(BTAG_ALL,interior=dir_r,exterior=dir_r) - # ) - # return (dbf_r) - #dbf_r = obj_array_vectorize(my_facialflux2,r) - #True boundary implementation #Okay, not sure about this... @@ -146,6 +131,7 @@ def my_facialflux_r_boundary(sol_ext,sol_int): #Compute q, half way done! + #q = discr.inverse_mass( -alpha * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r))) q = discr.inverse_mass( -alpha * epsilon * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r))) #flux of q @@ -169,21 +155,16 @@ def my_facialflux_q_partition(q): return sum(_facial_flux_q(discr,q_tpair=part_pair) for part_pair in qin) pbf_q = obj_array_vectorize(my_facialflux_q_partition,q) - #pbf_q = sum( - # _facial_flux_q(discr, q_tpair=part_pair) - # for part_pair in cross_rank_trace_pairs(discr, q) - #) - - def my_facialflux_q_boundary(q): - #dombain boundary flux - dir_q = discr.project("vol",BTAG_ALL, q); - dbf_q = _facial_flux_q( - discr, - q_tpair=TracePair(BTAG_ALL,interior=dir_q,exterior=dir_q) - ) - return(dbf_q) - - dbf_q = obj_array_vectorize(my_facialflux_q_boundary,q) + + dbf_q = 0.0*iff_q + for btag in boundaries: + def my_facialflux_q_boundary(sol_ext,sol_int): + q_tpair = TracePair(btag,interior=sol_int,exterior=sol_ext) + return _facial_flux_q(discr,q_tpair=q_tpair) + q_ext=boundaries[btag].av(discr,eos=eos,btag=btag,t=t,q=q) + q_int=discr.project("vol",btag,q) + dbf_q = dbf_q + obj_array_vectorize_n_args(my_facialflux_q_boundary,q_ext,q_int) + #Return the rhs contribution return ( discr.inverse_mass( -dflux_q + discr.face_mass(iff_q + pbf_q + dbf_q) ) ) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 86fe509d2..40cb11f8b 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -83,6 +83,11 @@ def exterior_sol( ext_soln = self._userfunc(t, nodes) return ext_soln + def av( + self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() + ): + return discr.project("vol",btag,q) + class DummyBoundary: """Use the boundary-adjacent solution as the boundary solution. @@ -108,6 +113,11 @@ def exterior_sol( dir_soln = discr.project("vol", btag, q) return dir_soln + def av( + self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() + ): + return discr.project("vol",btag,q) + class AdiabaticSlipBoundary: """Adiabatic slip boundary for inviscid flows. @@ -223,3 +233,44 @@ def exterior_sol( momentum=bndry_cv.momentum) return bndry_soln + + def av( + self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() + ): + # Grab some boundary-relevant data + dim = discr.dim + cv = split_conserved(dim, q) + actx = cv.mass[0].array_context + + # Grab a unit normal to the boundary + normal = thaw(actx, discr.normal(btag)) + + # Get the interior soln + int_soln = discr.project("vol", btag, q) + bndry_cv = split_conserved(dim, int_soln) + + #flip signs on mass and energy + bndry_cv.mass = -1*bndry_cv.mass + bndry_cv.energy = -1*bndry_cv.energy + + #things are in the wrong order here...flip? + for i in range(dim): + tmp = np.zeros(dim, dtype=object) + for j in range(dim): + tmp[j] = bndry_cv.momentum[j][i] + flip = np.dot(tmp,normal) + norm_flip = normal*make_obj_array([flip]) + tmp = tmp - 2.0*norm_flip + for j in range(dim): + bndry_cv.momentum[j][i] = tmp[j] + + #also need to flip momentum sign + bndry_cv.momentum = -1*bndry_cv.momentum + + #replace it here without single valued check + #No reason these arrays should be messed up... + result = np.zeros(2+dim, dtype=object) + result[0] = bndry_cv.mass + result[1] = bndry_cv.energy + result[2:] = bndry_cv.momentum + return(result) From bf67fc04747bb6a93caf0dbad57bb085f1c27616 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Wed, 3 Feb 2021 14:48:44 -0600 Subject: [PATCH 015/106] Bring back functions inadvertently removed in hand merge --- mirgecom/boundary.py | 59 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 64f3c897d..7e5f4b93a 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -105,6 +105,18 @@ def boundary_pair( dir_soln = discr.project("vol", btag, q) return TracePair(btag, interior=dir_soln, exterior=dir_soln) + def exterior_sol( + self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() + ): + """Get the interior and exterior solution on the boundary.""" + dir_soln = discr.project("vol", btag, q) + return dir_soln + + def av( + self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() + ): + return discr.project("vol", btag, q) + class AdiabaticSlipBoundary: r"""Boundary condition implementing inviscid slip boundary. @@ -164,6 +176,53 @@ def boundary_pair( return TracePair(btag, interior=int_soln, exterior=bndry_soln) + def exterior_sol( + self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() + ): + """Get the interior and exterior solution on the boundary. + The exterior solution is set such that there will be vanishing + flux through the boundary, preserving mass, momentum (magnitude) and + energy. + rho_plus = rho_minus + v_plus = v_minus - 2 * (v_minus . n_hat) * n_hat + mom_plus = rho_plus * v_plus + E_plus = E_minus + """ + # Grab some boundary-relevant data + dim = discr.dim + cv = split_conserved(dim, q) + actx = cv.mass.array_context + + # Grab a unit normal to the boundary + normal = thaw(actx, discr.normal(btag)) + normal_mag = actx.np.sqrt(np.dot(normal, normal)) + nhat_mult = 1.0 / normal_mag + nhat = normal * make_obj_array([nhat_mult]) + + # Get the interior/exterior solns + int_soln = discr.project("vol", btag, q) + bndry_cv = split_conserved(dim, int_soln) + # bpressure = eos.pressure(bndry_cv) + + # Subtract out the 2*wall-normal component + # of velocity from the velocity at the wall to + # induce an equal but opposite wall-normal (reflected) wave + # preserving the tangential component + wall_velocity = bndry_cv.momentum / make_obj_array([bndry_cv.mass]) + nvel_comp = np.dot(wall_velocity, nhat) # part of velocity normal to wall + wnorm_vel = nhat * make_obj_array([nvel_comp]) # wall-normal velocity vec + wall_velocity = wall_velocity - 2.0 * wnorm_vel # prescribed ext velocity + + # Re-calculate the boundary solution with the new + # momentum + bndry_cv.momentum = wall_velocity * make_obj_array([bndry_cv.mass]) + # bndry_cv.energy = eos.total_energy(bndry_cv, bpressure) + bndry_soln = join_conserved(dim=dim, mass=bndry_cv.mass, + energy=bndry_cv.energy, + momentum=bndry_cv.momentum) + + return bndry_soln + def av( self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() ): From f52b8b61e5e7adc6d0fb92c41f30db9cfb6d3f2d Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Wed, 3 Feb 2021 16:52:16 -0800 Subject: [PATCH 016/106] Minimum changes to bring boundary conditions up to date with mainline emirge --- mirgecom/boundary.py | 53 ++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 7e5f4b93a..54153edc0 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -180,6 +180,7 @@ def exterior_sol( self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() ): """Get the interior and exterior solution on the boundary. + The exterior solution is set such that there will be vanishing flux through the boundary, preserving mass, momentum (magnitude) and energy. @@ -194,32 +195,24 @@ def exterior_sol( actx = cv.mass.array_context # Grab a unit normal to the boundary - normal = thaw(actx, discr.normal(btag)) - normal_mag = actx.np.sqrt(np.dot(normal, normal)) - nhat_mult = 1.0 / normal_mag - nhat = normal * make_obj_array([nhat_mult]) + nhat = thaw(actx, discr.normal(btag)) # Get the interior/exterior solns int_soln = discr.project("vol", btag, q) - bndry_cv = split_conserved(dim, int_soln) - # bpressure = eos.pressure(bndry_cv) + int_cv = split_conserved(dim, int_soln) # Subtract out the 2*wall-normal component # of velocity from the velocity at the wall to # induce an equal but opposite wall-normal (reflected) wave # preserving the tangential component - wall_velocity = bndry_cv.momentum / make_obj_array([bndry_cv.mass]) - nvel_comp = np.dot(wall_velocity, nhat) # part of velocity normal to wall - wnorm_vel = nhat * make_obj_array([nvel_comp]) # wall-normal velocity vec - wall_velocity = wall_velocity - 2.0 * wnorm_vel # prescribed ext velocity - - # Re-calculate the boundary solution with the new - # momentum - bndry_cv.momentum = wall_velocity * make_obj_array([bndry_cv.mass]) - # bndry_cv.energy = eos.total_energy(bndry_cv, bpressure) - bndry_soln = join_conserved(dim=dim, mass=bndry_cv.mass, - energy=bndry_cv.energy, - momentum=bndry_cv.momentum) + mom_normcomp = np.dot(int_cv.momentum, nhat) # wall-normal component + wnorm_mom = nhat * mom_normcomp # wall-normal mom vec + ext_mom = int_cv.momentum - 2.0 * wnorm_mom # prescribed ext momentum + + # Form the external boundary solution with the new momentum + bndry_soln = join_conserved(dim=dim, mass=int_cv.mass, + energy=int_cv.energy, + momentum=ext_mom) return bndry_soln @@ -236,30 +229,28 @@ def av( # Get the interior soln int_soln = discr.project("vol", btag, q) - bndry_cv = split_conserved(dim, int_soln) + bndry_q = split_conserved(dim, int_soln) + + #create result array to fill + result = np.zeros(2+dim, dtype=object) # flip signs on mass and energy - bndry_cv.mass = -1*bndry_cv.mass - bndry_cv.energy = -1*bndry_cv.energy + result[0] = -1.0*bndry_q.mass + result[1] = -1.0*bndry_q.energy + + # This needs to be removed + result[2:] = bndry_q.momentum # things are in the wrong order here...flip? for i in range(dim): tmp = np.zeros(dim, dtype=object) for j in range(dim): - tmp[j] = bndry_cv.momentum[j][i] + tmp[j] = bndry_q.momentum[j][i] flip = np.dot(tmp, normal) norm_flip = normal*make_obj_array([flip]) tmp = tmp - 2.0*norm_flip for j in range(dim): - bndry_cv.momentum[j][i] = tmp[j] + result[2+j][i] = -1.0*tmp[j] - # also need to flip momentum sign - bndry_cv.momentum = -1*bndry_cv.momentum - # replace it here without single valued check - # No reason these arrays should be messed up... - result = np.zeros(2+dim, dtype=object) - result[0] = bndry_cv.mass - result[1] = bndry_cv.energy - result[2:] = bndry_cv.momentum return(result) From 703869a268e849dfe4039db106fd3fc59f201f2d Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Wed, 3 Feb 2021 20:26:06 -0600 Subject: [PATCH 017/106] Silence flake8. --- examples/doublemach-mpi.py | 147 ++++++++++++++--------- mirgecom/artificial_viscosity.py | 193 ++++++++++++++++--------------- mirgecom/boundary.py | 3 +- mirgecom/initializers.py | 73 ++++++------ mirgecom/simutil.py | 4 +- mirgecom/tag_cells.py | 76 +++++++----- 6 files changed, 275 insertions(+), 221 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 1ea5a2bab..3b4ebd8de 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -47,11 +47,9 @@ from mirgecom.integrators import rk4_step from mirgecom.steppers import advance_state from mirgecom.boundary import AdiabaticSlipBoundary, PrescribedBoundary -from mirgecom.initializers import DoubleMachReflection, SodShock1D +from mirgecom.initializers import DoubleMachReflection from mirgecom.eos import IdealSingleGas -from pytools.obj_array import obj_array_vectorize - logger = logging.getLogger(__name__) @@ -59,29 +57,33 @@ def main(ctx_factory=cl.create_some_context): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) - actx = PyOpenCLArrayContext(queue, - allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue))) + actx = PyOpenCLArrayContext( + queue, allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)) + ) dim = 2 - nel = (40,10) + # nel = (40, 10) order = 3 # tolerate large errors; case is unstable - exittol = 2.0 #.2 + exittol = 2.0 # .2 t_final = 0.0001 current_cfl = 0.1 - current_dt = .000001 + current_dt = 0.000001 current_t = 0 eos = IdealSingleGas() initializer = DoubleMachReflection(dim) - #initializer = SodShock1D(dim,x0=0.5) + # initializer = SodShock1D(dim,x0=0.5) casename = "sod1d" - #boundaries = {BTAG_ALL: AdiabaticSlipBoundary()} + # boundaries = {BTAG_ALL: AdiabaticSlipBoundary()} from grudge import sym - boundaries = {sym.DTAG_BOUNDARY("ic1"): PrescribedBoundary(initializer), - sym.DTAG_BOUNDARY("ic2"): PrescribedBoundary(initializer), - sym.DTAG_BOUNDARY("ic3"): PrescribedBoundary(initializer), - sym.DTAG_BOUNDARY("wall"): AdiabaticSlipBoundary(), - sym.DTAG_BOUNDARY("out"): AdiabaticSlipBoundary()} + + boundaries = { + sym.DTAG_BOUNDARY("ic1"): PrescribedBoundary(initializer), + sym.DTAG_BOUNDARY("ic2"): PrescribedBoundary(initializer), + sym.DTAG_BOUNDARY("ic3"): PrescribedBoundary(initializer), + sym.DTAG_BOUNDARY("wall"): AdiabaticSlipBoundary(), + sym.DTAG_BOUNDARY("out"): AdiabaticSlipBoundary(), + } constant_cfl = False nstatus = 10 nviz = 100 @@ -89,69 +91,99 @@ def main(ctx_factory=cl.create_some_context): checkpoint_t = current_t current_step = 0 timestepper = rk4_step - box_ll = (0.0,0.0) - box_ur = (4.0,1.0) + # box_ll = (0.0, 0.0) + # box_ur = (4.0, 1.0) from mpi4py import MPI + comm = MPI.COMM_WORLD rank = comm.Get_rank() + from meshmode.mesh.io import read_gmsh + gen_grid = partial(read_gmsh, "doubleMach2.msh", force_ambient_dim=2) - from meshmode.mesh.io import read_gmsh, generate_gmsh, ScriptWithFilesSource - - gen_grid = partial(read_gmsh,"doubleMach2.msh",force_ambient_dim=2) - local_mesh, global_nelements = create_parallel_grid(comm, gen_grid) local_nelements = local_mesh.nelements - discr = EagerDGDiscretization( - actx, local_mesh, order=order, mpi_communicator=comm - ) + discr = EagerDGDiscretization(actx, local_mesh, order=order, + mpi_communicator=comm) nodes = thaw(actx, discr.nodes()) current_state = initializer(0, nodes) - #visualizer = make_visualizer(discr, discr.order + 3 + # visualizer = make_visualizer(discr, discr.order + 3 # if discr.dim == 2 else discr.order) - visualizer = make_visualizer(discr, discr.order - if discr.dim == 2 else discr.order) + visualizer = make_visualizer(discr, + discr.order if discr.dim == 2 else discr.order) initname = initializer.__class__.__name__ eosname = eos.__class__.__name__ - init_message = make_init_message(dim=dim, order=order, - nelements=local_nelements, - global_nelements=global_nelements, - dt=current_dt, t_final=t_final, nstatus=nstatus, - nviz=nviz, cfl=current_cfl, - constant_cfl=constant_cfl, initname=initname, - eosname=eosname, casename=casename) + init_message = make_init_message( + dim=dim, + order=order, + nelements=local_nelements, + global_nelements=global_nelements, + dt=current_dt, + t_final=t_final, + nstatus=nstatus, + nviz=nviz, + cfl=current_cfl, + constant_cfl=constant_cfl, + initname=initname, + eosname=eosname, + casename=casename, + ) if rank == 0: logger.info(init_message) - get_timestep = partial(inviscid_sim_timestep, discr=discr, t=current_t, - dt=current_dt, cfl=current_cfl, eos=eos, - t_final=t_final, constant_cfl=constant_cfl) + get_timestep = partial( + inviscid_sim_timestep, + discr=discr, + t=current_t, + dt=current_dt, + cfl=current_cfl, + eos=eos, + t_final=t_final, + constant_cfl=constant_cfl, + ) def my_rhs(t, state): - return ( - inviscid_operator(discr, q=state, t=t,boundaries=boundaries, eos=eos) - + artificial_viscosity(discr,t=t, r=state, eos=eos, boundaries=boundaries, alpha=2.0e-2) - ) - #return ( - # inviscid_operator(discr, q=state, t=t,boundaries=boundaries, eos=eos) - # + artificial_viscosity(discr, r=state, eos=eos, boundaries=boundaries, alpha=1.0e-3) + return inviscid_operator( + discr, q=state, t=t, boundaries=boundaries, eos=eos + ) + artificial_viscosity( + discr, t=t, r=state, eos=eos, boundaries=boundaries, alpha=2.0e-2 + ) + # return ( + # inviscid_operator(discr, q=state, t=t,boundaries=boundaries, eos=eos) + # + artificial_viscosity(discr, r=state, eos=eos, boundaries=boundaries, + # alpha=1.0e-3) def my_checkpoint(step, t, dt, state): - return sim_checkpoint(discr, visualizer, eos, q=state, - vizname=casename, step=step, - t=t, dt=dt, nstatus=nstatus, nviz=nviz, - exittol=exittol, constant_cfl=constant_cfl, comm=comm) + return sim_checkpoint( + discr, + visualizer, + eos, + q=state, + vizname=casename, + step=step, + t=t, + dt=dt, + nstatus=nstatus, + nviz=nviz, + exittol=exittol, + constant_cfl=constant_cfl, + comm=comm, + ) try: - (current_step, current_t, current_state) = \ - advance_state(rhs=my_rhs, timestepper=timestepper, - checkpoint=my_checkpoint, - get_timestep=get_timestep, state=current_state, - t=current_t, t_final=t_final) + (current_step, current_t, current_state) = advance_state( + rhs=my_rhs, + timestepper=timestepper, + checkpoint=my_checkpoint, + get_timestep=get_timestep, + state=current_state, + t=current_t, + t_final=t_final, + ) except ExactSolutionMismatch as ex: current_step = ex.step current_t = ex.t @@ -160,9 +192,12 @@ def my_checkpoint(step, t, dt, state): # if current_t != checkpoint_t: if rank == 0: logger.info("Checkpointing final state ...") - my_checkpoint(current_step, t=current_t, - dt=(current_t - checkpoint_t), - state=current_state) + my_checkpoint( + current_step, + t=current_t, + dt=(current_t - checkpoint_t), + state=current_state, + ) if current_t - t_final < 0: raise ValueError("Simulation exited abnormally") diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index b0e7b8b42..3204bb854 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -1,4 +1,4 @@ -r""":mod:`mirgecom.artificial viscosity` applys and artifical viscosity to the euler equations +r""":mod:`mirgecom.artificial viscosity` Artificial viscocity for Euler. """ __copyright__ = """ @@ -25,24 +25,24 @@ THE SOFTWARE. """ -#from dataclasses import dataclass +# from dataclasses import dataclass import numpy as np -from pytools.obj_array import make_obj_array, obj_array_vectorize, flat_obj_array,obj_array_vectorize_n_args +from pytools.obj_array import ( + make_obj_array, + obj_array_vectorize, + obj_array_vectorize_n_args, +) from meshmode.dof_array import thaw from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa -from grudge.eager import ( - interior_trace_pair, - cross_rank_trace_pairs -) +from grudge.eager import interior_trace_pair, cross_rank_trace_pairs from grudge.symbolic.primitives import TracePair -from mirgecom.euler import split_conserved, join_conserved +# from mirgecom.euler import split_conserved, join_conserved from mirgecom.tag_cells import smoothness_indicator def _facial_flux_r(discr, q_tpair): - dim = discr.dim actx = q_tpair[0].int.array_context flux_dis = q_tpair.avg @@ -50,122 +50,129 @@ def _facial_flux_r(discr, q_tpair): normal = thaw(actx, discr.normal(q_tpair.dd)) flux_out = flux_dis * normal - + # Can't do it here... "obj arrays not allowed on compute device" - #def flux_calc(flux): + # def flux_calc(flux): # return (flux * normal) - #flux_out = obj_array_vectorize(flux_calc,flux_dis) + # flux_out = obj_array_vectorize(flux_calc,flux_dis) return discr.project(q_tpair.dd, "all_faces", flux_out) -def _facial_flux_q(discr, q_tpair): - dim = discr.dim +def _facial_flux_q(discr, q_tpair): actx = q_tpair[0].int.array_context normal = thaw(actx, discr.normal(q_tpair.dd)) - flux_out = np.dot(q_tpair.avg,normal) + flux_out = np.dot(q_tpair.avg, normal) return discr.project(q_tpair.dd, "all_faces", flux_out) -def artificial_viscosity(discr, t, eos, boundaries, r, alpha): - r"""Compute artifical viscosity for the euler equations - """ - #Get smoothness indicator - epsilon = np.zeros((2+discr.dim,),dtype=object) - indicator = make_obj_array([smoothness_indicator(r[0],discr)]) - for i in range(2+discr.dim): +def artificial_viscosity(discr, t, eos, boundaries, r, alpha): + r"""Compute artifical viscosity for the euler equations""" + # Get smoothness indicator + epsilon = np.zeros((2 + discr.dim,), dtype=object) + indicator = make_obj_array([smoothness_indicator(r[0], discr)]) + for i in range(2 + discr.dim): epsilon[i] = indicator - #compute dissapation flux + # compute dissapation flux + + # Cannot call weak_grad on obj of nd arrays + # use obj_array_vectorize as work around + dflux_r = obj_array_vectorize(discr.weak_grad, r) - #Cannot call weak_grad on obj of nd arrays, use obj_array_vectorize as work around - dflux_r = obj_array_vectorize(discr.weak_grad,r) - - #interior face flux + # interior face flux - #Doesn't work: something related to obj on compute device - #Not 100% on reason - #qin = interior_trace_pair(discr,r) - #iff_r = _facial_flux(discr,q_tpair=qin) + # Doesn't work: something related to obj on compute device + # Not 100% on reason + # qin = interior_trace_pair(discr,r) + # iff_r = _facial_flux(discr,q_tpair=qin) - #Work around? + # Work around? def my_facialflux_r_interior(q): - qin = interior_trace_pair(discr,make_obj_array([q])) - return _facial_flux_r(discr,q_tpair=qin) + qin = interior_trace_pair(discr, make_obj_array([q])) + return _facial_flux_r(discr, q_tpair=qin) - iff_r = obj_array_vectorize(my_facialflux_r_interior,r) - + iff_r = obj_array_vectorize(my_facialflux_r_interior, r) - #partition boundaries flux - #flux across partition boundaries + # partition boundaries flux + # flux across partition boundaries def my_facialflux_r_partition(q): - qin = cross_rank_trace_pairs(discr,make_obj_array([q])) - return sum(_facial_flux_r(discr,q_tpair=part_pair) for part_pair in qin ) - - pbf_r = obj_array_vectorize(my_facialflux_r_partition,r) - - - #True boundary implementation - #Okay, not sure about this... - #What I am attempting: + qin = cross_rank_trace_pairs(discr, make_obj_array([q])) + return sum(_facial_flux_r(discr, q_tpair=part_pair) for part_pair in qin) + + pbf_r = obj_array_vectorize(my_facialflux_r_partition, r) + + # True boundary implementation + # Okay, not sure about this... + # What I am attempting: # 1. Loop through all the boundaries - # 2. Define a function my_TP that performes the trace pair for the given boundary - # given a solution variable + # 2. Define a function my_TP that performes the trace pair for the given + # boundary given a solution variable # 3. Get the external solution from the boundary routine # 4. Get hte projected internal solution - # 5. Compute the boundary flux as a sum over boundaries, using the obj_array_vectorize to - # pass each solution variable one at a time + # 5. Compute the boundary flux as a sum over boundaries, using the + # obj_array_vectorize to pass each solution variable one at a time # DO I really need to do this like this? - dbf_r = 0.0*iff_r + dbf_r = 0.0 * iff_r for btag in boundaries: - def my_facialflux_r_boundary(sol_ext,sol_int): - q_tpair = TracePair(btag,interior=make_obj_array([sol_int]),exterior=make_obj_array([sol_ext])) - return _facial_flux_r(discr,q_tpair=q_tpair) - r_ext=boundaries[btag].exterior_sol(discr,eos=eos,btag=btag,t=t,q=r) - r_int=discr.project("vol",btag,r) - dbf_r = dbf_r + obj_array_vectorize_n_args(my_facialflux_r_boundary,r_ext,r_int) - - - #Compute q, half way done! - #q = discr.inverse_mass( -alpha * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r))) - q = discr.inverse_mass( -alpha * epsilon * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r))) - - #flux of q - - #Again we need to vectorize - #q is a object array of object arrays (dim,) of DOFArrays (?) - dflux_q = obj_array_vectorize(discr.weak_div,q) - - #interior face flux of q + + def my_facialflux_r_boundary(sol_ext, sol_int): + q_tpair = TracePair( + btag, + interior=make_obj_array([sol_int]), + exterior=make_obj_array([sol_ext]), + ) + return _facial_flux_r(discr, q_tpair=q_tpair) + + r_ext = boundaries[btag].exterior_sol(discr, eos=eos, btag=btag, t=t, q=r) + r_int = discr.project("vol", btag, r) + dbf_r = dbf_r + obj_array_vectorize_n_args( + my_facialflux_r_boundary, r_ext, r_int + ) + + # Compute q, half way done! + # q = discr.inverse_mass(-alpha*(dflux_r-discr.face_mass(iff_r + pbf_r + dbf_r))) + q = discr.inverse_mass( + -alpha * epsilon * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r)) + ) + + # flux of q + + # Again we need to vectorize + # q is a object array of object arrays (dim,) of DOFArrays (?) + dflux_q = obj_array_vectorize(discr.weak_div, q) + + # interior face flux of q def my_facialflux_q_interior(q): - qin = interior_trace_pair(discr,q) - iff_q = _facial_flux_q(discr, q_tpair=qin) - return (iff_q) + qin = interior_trace_pair(discr, q) + iff_q = _facial_flux_q(discr, q_tpair=qin) + return iff_q - iff_q = obj_array_vectorize(my_facialflux_q_interior,q) - + iff_q = obj_array_vectorize(my_facialflux_q_interior, q) - #flux across partition boundaries + # flux across partition boundaries def my_facialflux_q_partition(q): - qin = cross_rank_trace_pairs(discr,q) - return sum(_facial_flux_q(discr,q_tpair=part_pair) for part_pair in qin) - - pbf_q = obj_array_vectorize(my_facialflux_q_partition,q) + qin = cross_rank_trace_pairs(discr, q) + return sum(_facial_flux_q(discr, q_tpair=part_pair) for part_pair in qin) + + pbf_q = obj_array_vectorize(my_facialflux_q_partition, q) - dbf_q = 0.0*iff_q + dbf_q = 0.0 * iff_q for btag in boundaries: - def my_facialflux_q_boundary(sol_ext,sol_int): - q_tpair = TracePair(btag,interior=sol_int,exterior=sol_ext) - return _facial_flux_q(discr,q_tpair=q_tpair) - q_ext=boundaries[btag].av(discr,eos=eos,btag=btag,t=t,q=q) - q_int=discr.project("vol",btag,q) - dbf_q = dbf_q + obj_array_vectorize_n_args(my_facialflux_q_boundary,q_ext,q_int) - - - #Return the rhs contribution - return ( discr.inverse_mass( -dflux_q + discr.face_mass(iff_q + pbf_q + dbf_q) ) ) - + + def my_facialflux_q_boundary(sol_ext, sol_int): + q_tpair = TracePair(btag, interior=sol_int, exterior=sol_ext) + return _facial_flux_q(discr, q_tpair=q_tpair) + + q_ext = boundaries[btag].av(discr, eos=eos, btag=btag, t=t, q=q) + q_int = discr.project("vol", btag, q) + dbf_q = dbf_q + obj_array_vectorize_n_args( + my_facialflux_q_boundary, q_ext, q_int + ) + + # Return the rhs contribution + return discr.inverse_mass(-dflux_q + discr.face_mass(iff_q + pbf_q + dbf_q)) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 54153edc0..e8162a6c0 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -231,7 +231,7 @@ def av( int_soln = discr.project("vol", btag, q) bndry_q = split_conserved(dim, int_soln) - #create result array to fill + # create result array to fill result = np.zeros(2+dim, dtype=object) # flip signs on mass and energy @@ -252,5 +252,4 @@ def av( for j in range(dim): result[2+j][i] = -1.0*tmp[j] - return(result) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 251cfcec4..51db02520 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -305,6 +305,7 @@ def __call__(self, t, x_vec, eos=IdealSingleGas()): return flat_obj_array(mass, energy, mom) + class DoubleMachReflection: r"""Implement the double shock reflection problem @@ -314,7 +315,7 @@ class DoubleMachReflection: .. math:: - (\rho,u,v,P) = + (\rho,u,v,P) = This function only serves as an initial condition @@ -323,7 +324,7 @@ class DoubleMachReflection: """ def __init__( - self,dim=2, x0=1.0/6.0, us=4.0 + self, dim=2, x0=1.0/6.0, us=4.0 ): """Initialize initial condition options @@ -337,7 +338,7 @@ def __init__( shock speed """ self._x0 = x0 - self._dim = dim + self._dim = dim self._us = us def __call__(self, t, x_vec, eos=IdealSingleGas()): @@ -366,34 +367,33 @@ def __call__(self, t, x_vec, eos=IdealSingleGas()): x0 = zeros + self._x0 us = zeros + self._us t = zeros + t - - - #Mach 10 - #rhol = zeros + 8.0 - #rhor = zeros + 1.4 - - #ul = zeros + 8.25*np.cos(np.pi/6.0) - #ur = zeros + 0.0 - #vl = zeros - 8.25*np.sin(np.pi/6.0) - #vr = zeros + 0.0 - #rhoel = zeros + gmn1 * 116.5 - #rhoer = zeros + gmn1 * 1.0 - - #Mach 2.0 - #rhol = zeros + 2.666666*1.4 - #rhor = zeros + 1.4 - - #ul = zeros + 1.25*np.cos(np.pi/6.0) - #ur = zeros + 0.0 - #vl = zeros - 1.25*np.sin(np.pi/6.0) - #vr = zeros + 0.0 - #rhoel = zeros + gmn1 * 4.5 - #rhoer = zeros + gmn1 * 1.0 - - #Mach 4.0 + + # Mach 10 + # rhol = zeros + 8.0 + # rhor = zeros + 1.4 + + # ul = zeros + 8.25*np.cos(np.pi/6.0) + # ur = zeros + 0.0 + # vl = zeros - 8.25*np.sin(np.pi/6.0) + # vr = zeros + 0.0 + # rhoel = zeros + gmn1 * 116.5 + # rhoer = zeros + gmn1 * 1.0 + + # Mach 2.0 + # rhol = zeros + 2.666666*1.4 + # rhor = zeros + 1.4 + + # ul = zeros + 1.25*np.cos(np.pi/6.0) + # ur = zeros + 0.0 + # vl = zeros - 1.25*np.sin(np.pi/6.0) + # vr = zeros + 0.0 + # rhoel = zeros + gmn1 * 4.5 + # rhoer = zeros + gmn1 * 1.0 + + # Mach 4.0 rhol = zeros + 4.57142857*1.4 rhor = zeros + 1.4 - + ul = zeros + 3.125*np.cos(np.pi/6.0) ur = zeros + 0.0 vl = zeros - 3.125*np.sin(np.pi/6.0) @@ -401,16 +401,17 @@ def __call__(self, t, x_vec, eos=IdealSingleGas()): rhoel = zeros + gmn1 * 18.5 rhoer = zeros + gmn1 * 1.0 - #yesno = x_rel > (x0 + y_rel/np.sqrt(3.0) + 2.0*us*t/np.sqrt(3.0)) - #mass = actx.np.where(yesno, rhor, rhol) - #rhoe = actx.np.where(yesno, rhoer, rhoel) - #u = actx.np.where(yesno, ur, ul) - #v = actx.np.where(yesno, vr, vl) + # yesno = x_rel > (x0 + y_rel/np.sqrt(3.0) + 2.0*us*t/np.sqrt(3.0)) + # mass = actx.np.where(yesno, rhor, rhol) + # rhoe = actx.np.where(yesno, rhoer, rhoel) + # u = actx.np.where(yesno, ur, ul) + # v = actx.np.where(yesno, vr, vl) xinter = (x0 + y_rel/np.sqrt(3.0) + 2.0*us*t/np.sqrt(3.0)) - sigma=0.05 + sigma = 0.05 xtanh = 1.0/sigma*(x_rel-xinter) mass = rhol/2.0*(actx.np.tanh(-xtanh)+1.0)+rhor/2.0*(actx.np.tanh(xtanh)+1.0) - rhoe = rhoel/2.0*(actx.np.tanh(-xtanh)+1.0)+rhoer/2.0*(actx.np.tanh(xtanh)+1.0) + rhoe = (rhoel/2.0*(actx.np.tanh(-xtanh)+1.0) + + rhoer/2.0*(actx.np.tanh(xtanh)+1.0)) u = ul/2.0*(actx.np.tanh(-xtanh)+1.0)+ur/2.0*(actx.np.tanh(xtanh)+1.0) v = vl/2.0*(actx.np.tanh(-xtanh)+1.0)+vr/2.0*(actx.np.tanh(xtanh)+1.0) rhou = mass*u diff --git a/mirgecom/simutil.py b/mirgecom/simutil.py index 9565be569..6b7cbbfd1 100644 --- a/mirgecom/simutil.py +++ b/mirgecom/simutil.py @@ -104,9 +104,9 @@ def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, from mirgecom.euler import split_conserved cv = split_conserved(discr.dim, q) dependent_vars = eos.dependent_vars(cv) - + from mirgecom.tag_cells import smoothness_indicator - tagedcells = smoothness_indicator(q[0],discr) + tagedcells = smoothness_indicator(q[0], discr) rank = 0 if comm is not None: diff --git a/mirgecom/tag_cells.py b/mirgecom/tag_cells.py index 2addfe234..5616c81d2 100644 --- a/mirgecom/tag_cells.py +++ b/mirgecom/tag_cells.py @@ -4,7 +4,8 @@ .. math:: - S_e = \frac{\langle u_{N_p} - u_{N_{p-1}}, u_{N_p} - u_{N_{p-1}}\rangle_e}{\langle u_{N_p}, u_{N_p} \rangle_e} + S_e = \frac{\langle u_{N_p} - u_{N_{p-1}}, u_{N_p} - + u_{N_{p-1}}\rangle_e}{\langle u_{N_p}, u_{N_p} \rangle_e} """ __copyright__ = """ @@ -33,43 +34,48 @@ import numpy as np import loopy as lp -from grudge import sym from meshmode.dof_array import DOFArray from modepy import vandermonde -from pytools import memoize_in -from pytools.obj_array import make_obj_array def linear_operator_kernel(): """Apply linear operator to all elements.""" from meshmode.array_context import make_loopy_program + knl = make_loopy_program( """{[iel,idof,j]: 0<=iel (so-kappa) - yesnou = indicator > (so+kappa) - sin_indicator = actx.np.where(yesnol,0.5*(1.0+actx.np.sin(np.pi *(indicator - so)/(2.0*kappa))),0.0*indicator) - indicator = actx.np.where(yesnou,1.0+0.0*indicator,sin_indicator) + # Compute artificail viscosity percentage based on idicator and set parameters + yesnol = indicator > (so - kappa) + yesnou = indicator > (so + kappa) + sin_indicator = actx.np.where( + yesnol, + 0.5 * (1.0 + actx.np.sin(np.pi * (indicator - so) / (2.0 * kappa))), + 0.0 * indicator, + ) + indicator = actx.np.where(yesnou, 1.0 + 0.0 * indicator, sin_indicator) return indicator - From f20059f873a74db5a4c0b73e2f2104f88400fc05 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Wed, 3 Feb 2021 20:43:15 -0600 Subject: [PATCH 018/106] Silence pydocstyle --- examples/doublemach-mpi.py | 3 +++ examples/heat-source-mpi.py | 3 +++ mirgecom/artificial_viscosity.py | 5 ++--- mirgecom/boundary.py | 3 +++ mirgecom/initializers.py | 4 ++-- mirgecom/profiling.py | 1 + mirgecom/tag_cells.py | 4 ++-- 7 files changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 3b4ebd8de..d23adb80f 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -1,3 +1,5 @@ +"""Demonstrate doublemach reflection.""" + __copyright__ = """ Copyright (C) 2020 University of Illinois Board of Trustees """ @@ -55,6 +57,7 @@ @mpi_entry_point def main(ctx_factory=cl.create_some_context): + """Drive the example.""" cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext( diff --git a/examples/heat-source-mpi.py b/examples/heat-source-mpi.py index 35e79c8fb..8150305fc 100644 --- a/examples/heat-source-mpi.py +++ b/examples/heat-source-mpi.py @@ -1,3 +1,5 @@ +"""Demonstrate heat source.""" + __copyright__ = "Copyright (C) 2020 University of Illinois Board of Trustees" __license__ = """ @@ -45,6 +47,7 @@ @mpi_entry_point def main(): + """Drive the example.""" cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue, diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 3204bb854..b1c13d723 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -1,5 +1,4 @@ -r""":mod:`mirgecom.artificial viscosity` Artificial viscocity for Euler. -""" +""":mod:`mirgecom.artificial viscosity` Artificial viscocity for Euler.""" __copyright__ = """ Copyright (C) 2020 University of Illinois Board of Trustees @@ -71,7 +70,7 @@ def _facial_flux_q(discr, q_tpair): def artificial_viscosity(discr, t, eos, boundaries, r, alpha): - r"""Compute artifical viscosity for the euler equations""" + r"""Compute artifical viscosity for the euler equations.""" # Get smoothness indicator epsilon = np.zeros((2 + discr.dim,), dtype=object) indicator = make_obj_array([smoothness_indicator(r[0], discr)]) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index e8162a6c0..3b9354566 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -85,6 +85,7 @@ def exterior_sol( def av( self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() ): + """Do artificial viscosity function.""" return discr.project("vol", btag, q) @@ -115,6 +116,7 @@ def exterior_sol( def av( self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() ): + """Do artificial viscosity function.""" return discr.project("vol", btag, q) @@ -219,6 +221,7 @@ def exterior_sol( def av( self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() ): + """Do artificial viscosity function.""" # Grab some boundary-relevant data dim = discr.dim cv = split_conserved(dim, q) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 51db02520..6d784fb83 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -307,7 +307,7 @@ def __call__(self, t, x_vec, eos=IdealSingleGas()): class DoubleMachReflection: - r"""Implement the double shock reflection problem + r"""Implement the double shock reflection problem. - Woodward and Collela @@ -326,7 +326,7 @@ class DoubleMachReflection: def __init__( self, dim=2, x0=1.0/6.0, us=4.0 ): - """Initialize initial condition options + """Initialize initial condition options. Parameters ---------- diff --git a/mirgecom/profiling.py b/mirgecom/profiling.py index a880f98d5..d600d6ce7 100644 --- a/mirgecom/profiling.py +++ b/mirgecom/profiling.py @@ -106,6 +106,7 @@ class PyOpenCLProfilingArrayContext(PyOpenCLArrayContext): """ def __init__(self, queue, allocator=None) -> None: + """Initialize the object.""" super().__init__(queue, allocator) if not queue.properties & cl.command_queue_properties.PROFILING_ENABLE: diff --git a/mirgecom/tag_cells.py b/mirgecom/tag_cells.py index 5616c81d2..3288ae921 100644 --- a/mirgecom/tag_cells.py +++ b/mirgecom/tag_cells.py @@ -1,4 +1,4 @@ -r""":mod:`mirgecom.tag_cells` Computes smoothness indicator +r""":mod:`mirgecom.tag_cells` Compute smoothness indicator. Perssons smoothness indicator: @@ -74,7 +74,7 @@ def compute_smoothness_indicator(): def smoothness_indicator(u, discr): - + """Calculate the smoothness indicator.""" assert isinstance(u, DOFArray) # #@memoize_in(u.array_context, (smoothness_indicator, "get_kernel")) From 1340ea6c2ea74afb163266612755486aa0a3d37f Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Thu, 4 Feb 2021 12:09:17 -0800 Subject: [PATCH 019/106] Remove un-needed make_obj_array calls --- mirgecom/artificial_viscosity.py | 13 ++++++------- mirgecom/boundary.py | 3 +-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index b1c13d723..7ba1d0cb9 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -28,7 +28,6 @@ import numpy as np from pytools.obj_array import ( - make_obj_array, obj_array_vectorize, obj_array_vectorize_n_args, ) @@ -42,7 +41,7 @@ def _facial_flux_r(discr, q_tpair): - actx = q_tpair[0].int.array_context + actx = q_tpair.int.array_context flux_dis = q_tpair.avg @@ -73,7 +72,7 @@ def artificial_viscosity(discr, t, eos, boundaries, r, alpha): r"""Compute artifical viscosity for the euler equations.""" # Get smoothness indicator epsilon = np.zeros((2 + discr.dim,), dtype=object) - indicator = make_obj_array([smoothness_indicator(r[0], discr)]) + indicator = smoothness_indicator(r[0], discr) for i in range(2 + discr.dim): epsilon[i] = indicator @@ -92,7 +91,7 @@ def artificial_viscosity(discr, t, eos, boundaries, r, alpha): # Work around? def my_facialflux_r_interior(q): - qin = interior_trace_pair(discr, make_obj_array([q])) + qin = interior_trace_pair(discr, q) return _facial_flux_r(discr, q_tpair=qin) iff_r = obj_array_vectorize(my_facialflux_r_interior, r) @@ -100,7 +99,7 @@ def my_facialflux_r_interior(q): # partition boundaries flux # flux across partition boundaries def my_facialflux_r_partition(q): - qin = cross_rank_trace_pairs(discr, make_obj_array([q])) + qin = cross_rank_trace_pairs(discr, q) return sum(_facial_flux_r(discr, q_tpair=part_pair) for part_pair in qin) pbf_r = obj_array_vectorize(my_facialflux_r_partition, r) @@ -122,8 +121,8 @@ def my_facialflux_r_partition(q): def my_facialflux_r_boundary(sol_ext, sol_int): q_tpair = TracePair( btag, - interior=make_obj_array([sol_int]), - exterior=make_obj_array([sol_ext]), + interior=sol_int, + exterior=sol_ext, ) return _facial_flux_r(discr, q_tpair=q_tpair) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 4469a3f0b..324bf2689 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -33,7 +33,6 @@ """ import numpy as np -from pytools.obj_array import make_obj_array from meshmode.dof_array import thaw from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa from mirgecom.eos import IdealSingleGas @@ -243,7 +242,7 @@ def av( for j in range(dim): tmp[j] = bndry_q.momentum[j][i] flip = np.dot(tmp, normal) - norm_flip = normal*make_obj_array([flip]) + norm_flip = normal*flip tmp = tmp - 2.0*norm_flip for j in range(dim): result[2+j][i] = -1.0*tmp[j] From 9d32a7a9fef80637a12dd555492f9c08621266e1 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Thu, 4 Feb 2021 13:17:14 -0800 Subject: [PATCH 020/106] Rework boundary conditions to avoid duplicating code --- mirgecom/artificial_viscosity.py | 2 +- mirgecom/boundary.py | 82 +++++++------------------------- 2 files changed, 19 insertions(+), 65 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 7ba1d0cb9..c9add83d2 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -126,7 +126,7 @@ def my_facialflux_r_boundary(sol_ext, sol_int): ) return _facial_flux_r(discr, q_tpair=q_tpair) - r_ext = boundaries[btag].exterior_sol(discr, eos=eos, btag=btag, t=t, q=r) + r_ext = boundaries[btag].exterior_soln(discr, eos=eos, btag=btag, t=t, q=r) r_int = discr.project("vol", btag, r) dbf_r = dbf_r + obj_array_vectorize_n_args( my_facialflux_r_boundary, r_ext, r_int diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 324bf2689..bf5272fc6 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -62,29 +62,21 @@ def __init__(self, userfunc): def boundary_pair(self, discr, q, btag, **kwargs): """Get the interior and exterior solution on the boundary.""" - actx = q[0].array_context - - boundary_discr = discr.discr_from_dd(btag) - nodes = thaw(actx, boundary_discr.nodes()) - ext_soln = self._userfunc(nodes, **kwargs) + ext_soln = self.exterior_soln(self, discr, q, btag, **kwargs) int_soln = discr.project("vol", btag, q) return TracePair(btag, interior=int_soln, exterior=ext_soln) - def exterior_sol( - self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() - ): - """Get the interior solution on the boundary.""" + def exterior_soln(self, discr, q, btag, **kwargs): + """Get the exterior solution on the boundary.""" actx = q[0].array_context boundary_discr = discr.discr_from_dd(btag) nodes = thaw(actx, boundary_discr.nodes()) - ext_soln = self._userfunc(t, nodes) + ext_soln = self._userfunc(nodes, **kwargs) return ext_soln - def av( - self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() - ): - """Do artificial viscosity function.""" + def av(self, discr, q, btag, **kwargs): + """Get the exterior solution on the boundary.""" return discr.project("vol", btag, q) @@ -96,20 +88,16 @@ class DummyBoundary: def boundary_pair(self, discr, q, btag, **kwargs): """Get the interior and exterior solution on the boundary.""" - dir_soln = discr.project("vol", btag, q) + dir_soln = self.exterior_soln(self, discr, q, btag, **kwargs) return TracePair(btag, interior=dir_soln, exterior=dir_soln) - def exterior_sol( - self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() - ): - """Get the interior and exterior solution on the boundary.""" + def exterior_soln(self, discr, q, btag, **kwargs): + """Get the exterior solution on the boundary.""" dir_soln = discr.project("vol", btag, q) return dir_soln - def av( - self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() - ): - """Do artificial viscosity function.""" + def av(self, discr, q, btag, **kwargs): + """Get the exterior solution on the boundary.""" return discr.project("vol", btag, q) @@ -132,48 +120,15 @@ class AdiabaticSlipBoundary: """ def boundary_pair(self, discr, q, btag, **kwargs): - """Get the interior and exterior solution on the boundary. - - The exterior solution is set such that there will be vanishing - flux through the boundary, preserving mass, momentum (magnitude) and - energy. - rho_plus = rho_minus - v_plus = v_minus - 2 * (v_minus . n_hat) * n_hat - mom_plus = rho_plus * v_plus - E_plus = E_minus - """ - # Grab some boundary-relevant data - dim = discr.dim - cv = split_conserved(dim, q) - actx = cv.mass.array_context - - # Grab a unit normal to the boundary - nhat = thaw(actx, discr.normal(btag)) + """Get the interior and exterior solution on the boundary.""" - # Get the interior/exterior solns + bndry_soln = self.exterior_soln(discr, q, btag, **kwargs) int_soln = discr.project("vol", btag, q) - int_cv = split_conserved(dim, int_soln) - - # Subtract out the 2*wall-normal component - # of velocity from the velocity at the wall to - # induce an equal but opposite wall-normal (reflected) wave - # preserving the tangential component - mom_normcomp = np.dot(int_cv.momentum, nhat) # wall-normal component - wnorm_mom = nhat * mom_normcomp # wall-normal mom vec - ext_mom = int_cv.momentum - 2.0 * wnorm_mom # prescribed ext momentum - - # Form the external boundary solution with the new momentum - bndry_soln = join_conserved(dim=dim, mass=int_cv.mass, - energy=int_cv.energy, - momentum=ext_mom, - species_mass=int_cv.species_mass) return TracePair(btag, interior=int_soln, exterior=bndry_soln) - def exterior_sol( - self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() - ): - """Get the interior and exterior solution on the boundary. + def exterior_soln(self, discr, q, btag, **kwargs): + """Get the exterior solution on the boundary. The exterior solution is set such that there will be vanishing flux through the boundary, preserving mass, momentum (magnitude) and @@ -210,10 +165,9 @@ def exterior_sol( return bndry_soln - def av( - self, discr, q, t=0.0, btag=BTAG_ALL, eos=IdealSingleGas() - ): - """Do artificial viscosity function.""" + def av(self, discr, q, btag, **kwargs): + """Get the exterior solution on the boundary.""" + # Grab some boundary-relevant data dim = discr.dim cv = split_conserved(dim, q) From 3a13a05a02744830b8f0b8cc5a30756a1ed67107 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Thu, 4 Feb 2021 13:29:31 -0800 Subject: [PATCH 021/106] Fix docstyle, remove unused import --- mirgecom/boundary.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index bf5272fc6..153fec29e 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -35,7 +35,6 @@ import numpy as np from meshmode.dof_array import thaw from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa -from mirgecom.eos import IdealSingleGas from mirgecom.euler import split_conserved, join_conserved from grudge.symbolic.primitives import TracePair @@ -121,7 +120,6 @@ class AdiabaticSlipBoundary: def boundary_pair(self, discr, q, btag, **kwargs): """Get the interior and exterior solution on the boundary.""" - bndry_soln = self.exterior_soln(discr, q, btag, **kwargs) int_soln = discr.project("vol", btag, q) @@ -167,7 +165,6 @@ def exterior_soln(self, discr, q, btag, **kwargs): def av(self, discr, q, btag, **kwargs): """Get the exterior solution on the boundary.""" - # Grab some boundary-relevant data dim = discr.dim cv = split_conserved(dim, q) From 1b2b30e199bcf53505976d6553efd5cde8df1d55 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Thu, 4 Feb 2021 16:29:24 -0800 Subject: [PATCH 022/106] Expose smoothness indicator parameters --- mirgecom/artificial_viscosity.py | 4 ++-- mirgecom/simutil.py | 11 ++++++++--- mirgecom/tag_cells.py | 13 ++++--------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 7ba1d0cb9..fc4626a96 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -68,11 +68,11 @@ def _facial_flux_q(discr, q_tpair): return discr.project(q_tpair.dd, "all_faces", flux_out) -def artificial_viscosity(discr, t, eos, boundaries, r, alpha): +def artificial_viscosity(discr, t, eos, boundaries, r, alpha, **kwargs): r"""Compute artifical viscosity for the euler equations.""" # Get smoothness indicator epsilon = np.zeros((2 + discr.dim,), dtype=object) - indicator = smoothness_indicator(r[0], discr) + indicator = smoothness_indicator(r[0], discr, **kwargs) for i in range(2 + discr.dim): epsilon[i] = indicator diff --git a/mirgecom/simutil.py b/mirgecom/simutil.py index 6a138086a..c8be8b6af 100644 --- a/mirgecom/simutil.py +++ b/mirgecom/simutil.py @@ -93,7 +93,7 @@ def __init__(self, step, t, state): def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, step=0, t=0, dt=0, cfl=1.0, nstatus=-1, nviz=-1, exittol=1e-16, - constant_cfl=False, comm=None, overwrite=False): + s0=None, kappa=None, constant_cfl=False, comm=None, overwrite=False): """Check simulation health, status, viz dumps, and restart.""" # TODO: Add restart do_viz = check_step(step=step, interval=nviz) @@ -106,7 +106,8 @@ def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, dependent_vars = eos.dependent_vars(cv) from mirgecom.tag_cells import smoothness_indicator - tagedcells = smoothness_indicator(q[0], discr) + if s0 is not None and kappa is not None: + tagedcells = smoothness_indicator(q[0], discr, kappa=kappa, s0=s0) rank = 0 if comm is not None: @@ -125,13 +126,17 @@ def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, io_fields = [ ("cv", cv), ("dv", dependent_vars), - ("tagged", tagedcells) ] if exact_soln is not None: exact_list = [ ("exact_soln", expected_state), ] io_fields.extend(exact_list) + if s0 is not None and kappa is not None: + tagged_list = [ + ("tagged", tagedcells), + ] + io_fields.extend(tagged_list) from mirgecom.io import make_rank_fname, make_par_fname rank_fn = make_rank_fname(basename=vizname, rank=rank, step=step, t=t) diff --git a/mirgecom/tag_cells.py b/mirgecom/tag_cells.py index 3288ae921..20e223046 100644 --- a/mirgecom/tag_cells.py +++ b/mirgecom/tag_cells.py @@ -73,7 +73,7 @@ def compute_smoothness_indicator(): return knl -def smoothness_indicator(u, discr): +def smoothness_indicator(u, discr, kappa=1.0, s0=-6.0): """Calculate the smoothness indicator.""" assert isinstance(u, DOFArray) @@ -120,17 +120,12 @@ def get_indicator(): # Take log10 of indicator indicator = actx.np.log10(indicator + 1.0e-12) - # No special meaning to these values - # Should be exposed as tuning parameters - kappa = 0.5 - so = -7.0 - # Compute artificail viscosity percentage based on idicator and set parameters - yesnol = indicator > (so - kappa) - yesnou = indicator > (so + kappa) + yesnol = indicator > (s0 - kappa) + yesnou = indicator > (s0 + kappa) sin_indicator = actx.np.where( yesnol, - 0.5 * (1.0 + actx.np.sin(np.pi * (indicator - so) / (2.0 * kappa))), + 0.5 * (1.0 + actx.np.sin(np.pi * (indicator - s0) / (2.0 * kappa))), 0.0 * indicator, ) indicator = actx.np.where(yesnou, 1.0 + 0.0 * indicator, sin_indicator) From 0dff5e53dd2625cf91b68648b8f8abd72685dece Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 26 Feb 2021 15:09:10 -0800 Subject: [PATCH 023/106] Fixed boundary calls to self --- mirgecom/boundary.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 153fec29e..a3601d080 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -61,7 +61,7 @@ def __init__(self, userfunc): def boundary_pair(self, discr, q, btag, **kwargs): """Get the interior and exterior solution on the boundary.""" - ext_soln = self.exterior_soln(self, discr, q, btag, **kwargs) + ext_soln = self.exterior_soln(discr, q, btag, **kwargs) int_soln = discr.project("vol", btag, q) return TracePair(btag, interior=int_soln, exterior=ext_soln) @@ -87,7 +87,7 @@ class DummyBoundary: def boundary_pair(self, discr, q, btag, **kwargs): """Get the interior and exterior solution on the boundary.""" - dir_soln = self.exterior_soln(self, discr, q, btag, **kwargs) + dir_soln = self.exterior_soln(discr, q, btag, **kwargs) return TracePair(btag, interior=dir_soln, exterior=dir_soln) def exterior_soln(self, discr, q, btag, **kwargs): From 1b57517c8f1edca791906a2fc919d3a32c2828d7 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 26 Feb 2021 15:18:24 -0800 Subject: [PATCH 024/106] Fixed flake8 line to long --- mirgecom/simutil.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mirgecom/simutil.py b/mirgecom/simutil.py index c8be8b6af..5b8183a5f 100644 --- a/mirgecom/simutil.py +++ b/mirgecom/simutil.py @@ -93,7 +93,8 @@ def __init__(self, step, t, state): def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, step=0, t=0, dt=0, cfl=1.0, nstatus=-1, nviz=-1, exittol=1e-16, - s0=None, kappa=None, constant_cfl=False, comm=None, overwrite=False): + s0=None, kappa=None, constant_cfl=False, comm=None, + overwrite=False): """Check simulation health, status, viz dumps, and restart.""" # TODO: Add restart do_viz = check_step(step=step, interval=nviz) From f39deb2ab389d5e3f39333246a11aae2de89e8fe Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Tue, 2 Mar 2021 12:16:25 -0800 Subject: [PATCH 025/106] Clean up AdiabaticSlipBoundary for artificial viscosity condition. --- mirgecom/boundary.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index a3601d080..e4c7d2e30 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -181,21 +181,17 @@ def av(self, discr, q, btag, **kwargs): result = np.zeros(2+dim, dtype=object) # flip signs on mass and energy + # to apply a neumann condition on q result[0] = -1.0*bndry_q.mass result[1] = -1.0*bndry_q.energy - # This needs to be removed - result[2:] = bndry_q.momentum - - # things are in the wrong order here...flip? - for i in range(dim): - tmp = np.zeros(dim, dtype=object) - for j in range(dim): - tmp[j] = bndry_q.momentum[j][i] - flip = np.dot(tmp, normal) - norm_flip = normal*flip - tmp = tmp - 2.0*norm_flip - for j in range(dim): - result[2+j][i] = -1.0*tmp[j] + # Subtract 2*wall-normal component of q + # to enforce q=0 on the wall + # flip remaining components to set a neumann condition + from pytools.obj_array import make_obj_array + q_mom_normcomp = make_obj_array( + [np.outer(normal,np.dot(bndry_q.momentum,normal))[i] for i in range(dim)] + ) + result[2:] = -1*(bndry_q.momentum-2.0*q_mom_normcomp) return(result) From 6b9a29d335b1c7b52d0b11a3a615fad93dd0d123 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Fri, 12 Mar 2021 14:30:00 -0600 Subject: [PATCH 026/106] Added inital documentation to artificial viscosity routines (#8) * Added inital documentation to artificial viscosity routines * Fix style issues * more style fixes Co-authored-by: Wyatt Hagen --- mirgecom/artificial_viscosity.py | 29 +++++++++++++++++++++++++++- mirgecom/tag_cells.py | 33 +++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 53bc06441..6ba1bde96 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -1,4 +1,31 @@ -""":mod:`mirgecom.artificial viscosity` Artificial viscocity for Euler.""" +r""":mod:`mirgecom.artificial viscosity` Artificial viscocity for Euler. + +Artificial viscosity for the Euler Equations: + +.. math:: + + \partial_t \mathbf{Q} = \nabla\cdot{\varepsilon\nabla\mathbf{Q}} + +where: + +- state $\mathbf{Q} = [\rho, \rho{E}, \rho\vec{V}, \rho{Y}_\alpha]$ +- artifical viscosity coefficient $\varepsilon$ + +To evalutate the second order derivative the problem is recast as a set of first + order problems: + +.. math:: + + \partial_t \mathbf{Q} = \nabla\cdot{\mathbf{R}} + \mathbf{R} = \varepsilon\nabla\mathbf{Q} + +where $\mathbf{R}$ is an intermediate variable. + +RHS Evaluation +^^^^^^^^^^^^^^ + +.. autofunction:: artificial_viscosity +""" __copyright__ = """ Copyright (C) 2020 University of Illinois Board of Trustees diff --git a/mirgecom/tag_cells.py b/mirgecom/tag_cells.py index 20e223046..a55abaacd 100644 --- a/mirgecom/tag_cells.py +++ b/mirgecom/tag_cells.py @@ -1,13 +1,44 @@ r""":mod:`mirgecom.tag_cells` Compute smoothness indicator. -Perssons smoothness indicator: +Evalutes the smoothness indicator of Persson: .. math:: S_e = \frac{\langle u_{N_p} - u_{N_{p-1}}, u_{N_p} - u_{N_{p-1}}\rangle_e}{\langle u_{N_p}, u_{N_p} \rangle_e} +where: +- $S_e$ is the smoothness indicator +- $u_{N_p}$ is the modal representation of the solution at the current polynomial + order +- $u_{N_{p-1}}$ is the truncated modal represention to the polynomial order $p-1$ +- The $L_2$ inner product on an element is denoted $\langle \cdot,\cdot \rangle_e$ + +The elementwise viscoisty is then calculated: + +.. math:: + + \varepsilon_e = \varepsilon_0 + \begin{cases} + 0, & s_e < s_0 - \kappa \\ + \frac{1}{2}\left( 1 + \sin \frac{\pi(s_e - s_0)}{2 \kappa} \right ), + & s_0-\kappa \le s_e \le s_0+\kappa \\ + 1, & s_e > s_0+\kappa + \end{cases} + +where: +- $\varepsilon_e$ is the element viscosity +- $\varepsilon_0 ~\sim h/p$ is a reference viscosity +- $s_e = \log_{10}{S_e} \sim 1/p^4$ is the smoothness indicator +- $s_0$ is a reference smoothness value +- $\kappa$ controls the width of the transition between 0 to $\varepsilon_0$ + +Smoothness Indicator Evaluation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autofunction:: smoothness_indicator """ + __copyright__ = """ Copyright (C) 2020 University of Illinois Board of Trustees """ From d17ea87e57a0d60e7dd75460d81f4b72a25c3ca2 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 12 Mar 2021 15:09:00 -0800 Subject: [PATCH 027/106] fixed flake8 error --- mirgecom/boundary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index e4c7d2e30..a407f72d7 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -190,7 +190,7 @@ def av(self, discr, q, btag, **kwargs): # flip remaining components to set a neumann condition from pytools.obj_array import make_obj_array q_mom_normcomp = make_obj_array( - [np.outer(normal,np.dot(bndry_q.momentum,normal))[i] for i in range(dim)] + [np.outer(normal, np.dot(bndry_q.momentum, normal))[i] for i in range(dim)] ) result[2:] = -1*(bndry_q.momentum-2.0*q_mom_normcomp) From 100b1c3f708313ac80830bc5fef73e2e00d36f29 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Fri, 12 Mar 2021 15:14:33 -0800 Subject: [PATCH 028/106] Fixed too long line --- mirgecom/boundary.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index a407f72d7..84c471d45 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -190,7 +190,8 @@ def av(self, discr, q, btag, **kwargs): # flip remaining components to set a neumann condition from pytools.obj_array import make_obj_array q_mom_normcomp = make_obj_array( - [np.outer(normal, np.dot(bndry_q.momentum, normal))[i] for i in range(dim)] + [np.outer(normal, np.dot(bndry_q.momentum, normal))[i] + for i in range(dim)] ) result[2:] = -1*(bndry_q.momentum-2.0*q_mom_normcomp) From 9d0f8edd7433c15ed80fab33d086e9f769236f9b Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Fri, 12 Mar 2021 17:23:46 -0600 Subject: [PATCH 029/106] Added tests to artificial viscosity routines. (#9) * Added tests to artificial viscosity routines. * Fixed flake8 errors. * Fixed error in getting basis polynomials * Fixed style errors Co-authored-by: Wyatt Hagen --- test/test_artificial_viscosity.py | 200 ++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 test/test_artificial_viscosity.py diff --git a/test/test_artificial_viscosity.py b/test/test_artificial_viscosity.py new file mode 100644 index 000000000..972cfc1b6 --- /dev/null +++ b/test/test_artificial_viscosity.py @@ -0,0 +1,200 @@ +"""Test the artificial viscosity functions.""" + +__copyright__ = """ +Copyright (C) 2020 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. +""" + +import logging +import numpy as np +import pyopencl as cl +import pytest +from meshmode.array_context import PyOpenCLArrayContext +from meshmode.dof_array import thaw +from meshmode.mesh import BTAG_ALL + +from mirgecom.tag_cells import smoothness_indicator +from mirgecom.artificial_viscosity import artificial_viscosity +from mirgecom.boundary import DummyBoundary +from grudge.eager import EagerDGDiscretization +from pytools.obj_array import flat_obj_array +from pyopencl.tools import ( # noqa + pytest_generate_tests_for_pyopencl as pytest_generate_tests, +) + +logger = logging.getLogger(__name__) + + +@pytest.mark.parametrize("dim", [1, 2, 3]) +@pytest.mark.parametrize("order", [1, 5]) +def test_tag_cells(ctx_factory, dim, order): + """Test tag_cells. + + Tests that the cells tagging properly tags cells + given a prescirbed solutions. + """ + cl_ctx = ctx_factory() + queue = cl.CommandQueue(cl_ctx) + actx = PyOpenCLArrayContext(queue) + + nel_1d = 2 + tolerance = 1.e-16 + + def norm_indicator(expected, discr, soln, **kwargs): + return(discr.norm(expected-smoothness_indicator(soln, discr, **kwargs), + np.inf)) + + from meshmode.mesh.generation import generate_regular_rect_mesh + + mesh = generate_regular_rect_mesh( + a=(-1.0, )*dim, b=(1.0, )*dim, n=(nel_1d, ) * dim + ) + + discr = EagerDGDiscretization(actx, mesh, order=order) + nodes = thaw(actx, discr.nodes()) + nele = mesh.nelements + zeros = 0.0*nodes[0] + + # test jump discontinuity + soln = actx.np.where(nodes[0] > 0.0+zeros, 1.0+zeros, zeros) + err = norm_indicator(1.0, discr, soln) + + assert err < tolerance, "Jump discontinuity should trigger indicator (1.0)" + + # get meshmode polynomials + group = discr.discr_from_dd("vol").groups[0] + basis = group.basis() # only one group + unit_nodes = group.unit_nodes + modes = group.mode_ids() + order = group.order + + # loop over modes and check smoothness + for i, mode in enumerate(modes): + ele_soln = basis[i](unit_nodes) + soln[0].set(np.tile(ele_soln, (nele, 1))) + if sum(mode) == order: + expected = 1.0 + else: + expected = 0.0 + err = norm_indicator(expected, discr, soln) + assert err < tolerance, "Only highest modes should trigger indicator (1.0)" + + # Test s0 + s0 = -1. + eps = 1.0e-6 + + phi_n_p = np.sqrt(np.power(10, s0)) + phi_n_pm1 = np.sqrt(1. - np.power(10, s0)) + + # pick a polynomial of order n_p, n_p-1 + n_p = np.array(np.nonzero((np.sum(modes, axis=1) == order))).flat[0] + n_pm1 = np.array(np.nonzero((np.sum(modes, axis=1) == order-1))).flat[0] + + # create test soln perturbed around + # Solution above s0 + ele_soln = ((phi_n_p+eps)*basis[n_p](unit_nodes) + + phi_n_pm1*basis[n_pm1](unit_nodes)) + soln[0].set(np.tile(ele_soln, (nele, 1))) + err = norm_indicator(1.0, discr, soln, s0=s0, kappa=0.0) + assert err < tolerance, ( + "A function with an indicator >s0 should trigger indicator") + + # Solution below s0 + ele_soln = ((phi_n_p-eps)*basis[n_p](unit_nodes) + + phi_n_pm1*basis[n_pm1](unit_nodes)) + soln[0].set(np.tile(ele_soln, (nele, 1))) + err = norm_indicator(0.0, discr, soln, s0=s0, kappa=0.0) + assert err < tolerance, ( + "A function with an indicator tolerance, "s_e>s_0-kappa should trigger indicator" + + # lower bound + err = norm_indicator(1.0, discr, soln, s0=s0-(kappa+shift), kappa=kappa) + assert err < tolerance, "s_e>s_0+kappa should fully trigger indicator (1.0)" + err = norm_indicator(1.0, discr, soln, s0=s0-(kappa-shift), kappa=kappa) + assert err > tolerance, "s_e Date: Fri, 12 Mar 2021 16:13:46 -0800 Subject: [PATCH 030/106] Fixed missed merge conflict. --- mirgecom/simutil.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/mirgecom/simutil.py b/mirgecom/simutil.py index 4b6fad0a7..a6227f0bf 100644 --- a/mirgecom/simutil.py +++ b/mirgecom/simutil.py @@ -132,16 +132,13 @@ def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, ("exact_soln", expected_state), ] io_fields.extend(exact_list) -<<<<<<< HEAD if s0 is not None and kappa is not None: tagged_list = [ ("tagged", tagedcells), ] io_fields.extend(tagged_list) -======= if viz_fields is not None: io_fields.extend(viz_fields) ->>>>>>> main from mirgecom.io import make_rank_fname, make_par_fname rank_fn = make_rank_fname(basename=vizname, rank=rank, step=step, t=t) From 34b96bffb1991712a07431cac20ff0a0723264ee Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Sat, 13 Mar 2021 18:26:12 -0800 Subject: [PATCH 031/106] Fixed errors in dobule mach initialization. --- mirgecom/initializers.py | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 91a0660fa..b32d1a734 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -298,7 +298,7 @@ def __init__( self._dim = dim self._us = us - def __call__(self, t, x_vec, eos=IdealSingleGas()): + def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): """ Create the 1D Sod's shock solution at locations *x_vec*. @@ -325,28 +325,6 @@ def __call__(self, t, x_vec, eos=IdealSingleGas()): us = zeros + self._us t = zeros + t - # Mach 10 - # rhol = zeros + 8.0 - # rhor = zeros + 1.4 - - # ul = zeros + 8.25*np.cos(np.pi/6.0) - # ur = zeros + 0.0 - # vl = zeros - 8.25*np.sin(np.pi/6.0) - # vr = zeros + 0.0 - # rhoel = zeros + gmn1 * 116.5 - # rhoer = zeros + gmn1 * 1.0 - - # Mach 2.0 - # rhol = zeros + 2.666666*1.4 - # rhor = zeros + 1.4 - - # ul = zeros + 1.25*np.cos(np.pi/6.0) - # ur = zeros + 0.0 - # vl = zeros - 1.25*np.sin(np.pi/6.0) - # vr = zeros + 0.0 - # rhoel = zeros + gmn1 * 4.5 - # rhoer = zeros + gmn1 * 1.0 - # Mach 4.0 rhol = zeros + 4.57142857*1.4 rhor = zeros + 1.4 @@ -358,11 +336,6 @@ def __call__(self, t, x_vec, eos=IdealSingleGas()): rhoel = zeros + gmn1 * 18.5 rhoer = zeros + gmn1 * 1.0 - # yesno = x_rel > (x0 + y_rel/np.sqrt(3.0) + 2.0*us*t/np.sqrt(3.0)) - # mass = actx.np.where(yesno, rhor, rhol) - # rhoe = actx.np.where(yesno, rhoer, rhoel) - # u = actx.np.where(yesno, ur, ul) - # v = actx.np.where(yesno, vr, vl) xinter = (x0 + y_rel/np.sqrt(3.0) + 2.0*us*t/np.sqrt(3.0)) sigma = 0.05 xtanh = 1.0/sigma*(x_rel-xinter) @@ -375,7 +348,7 @@ def __call__(self, t, x_vec, eos=IdealSingleGas()): rhov = mass*v energy = rhoe + 0.5*mass*(u*u + v*v) - return flat_obj_array(mass, energy, rhou, rhov) + return join_conserved(dim=self._dim, mass=mass, energy=energy, momentum=make_obj_array([u,v])) class Lump: From f52a165085cf9d2965a2aa6653922c9c3b1df8c4 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen Date: Sat, 13 Mar 2021 19:58:21 -0800 Subject: [PATCH 032/106] Fixed error in initialization. --- mirgecom/initializers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index b32d1a734..8c8bd87d0 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -348,7 +348,8 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): rhov = mass*v energy = rhoe + 0.5*mass*(u*u + v*v) - return join_conserved(dim=self._dim, mass=mass, energy=energy, momentum=make_obj_array([u,v])) + return join_conserved(dim=self._dim, mass=mass, energy=energy, + momentum=make_obj_array([rhou, rhov])) class Lump: From c8858e4c635616146361cc996ee55c9d75cb8d6e Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Sun, 14 Mar 2021 11:57:41 -0700 Subject: [PATCH 033/106] Cleaned up artificial viscosity routines. --- mirgecom/artificial_viscosity.py | 49 ++------------------------------ mirgecom/tag_cells.py | 7 +---- 2 files changed, 4 insertions(+), 52 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 6ba1bde96..fe6cb1a3a 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -51,8 +51,6 @@ THE SOFTWARE. """ -# from dataclasses import dataclass - import numpy as np from pytools.obj_array import ( obj_array_vectorize, @@ -62,7 +60,6 @@ from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa from grudge.eager import interior_trace_pair, cross_rank_trace_pairs from grudge.symbolic.primitives import TracePair -# from mirgecom.euler import split_conserved, join_conserved from mirgecom.tag_cells import smoothness_indicator @@ -76,11 +73,6 @@ def _facial_flux_r(discr, q_tpair): flux_out = flux_dis * normal - # Can't do it here... "obj arrays not allowed on compute device" - # def flux_calc(flux): - # return (flux * normal) - # flux_out = obj_array_vectorize(flux_calc,flux_dis) - return discr.project(q_tpair.dd, "all_faces", flux_out) @@ -98,51 +90,23 @@ def _facial_flux_q(discr, q_tpair): def artificial_viscosity(discr, t, eos, boundaries, r, alpha, **kwargs): r"""Compute artifical viscosity for the euler equations.""" # Get smoothness indicator - epsilon = np.zeros((2 + discr.dim,), dtype=object) indicator = smoothness_indicator(r[0], discr, **kwargs) - for i in range(2 + discr.dim): - epsilon[i] = indicator - - # compute dissapation flux - # Cannot call weak_grad on obj of nd arrays - # use obj_array_vectorize as work around dflux_r = obj_array_vectorize(discr.weak_grad, r) - # interior face flux - - # Doesn't work: something related to obj on compute device - # Not 100% on reason - # qin = interior_trace_pair(discr,r) - # iff_r = _facial_flux(discr,q_tpair=qin) - - # Work around? def my_facialflux_r_interior(q): qin = interior_trace_pair(discr, q) return _facial_flux_r(discr, q_tpair=qin) iff_r = obj_array_vectorize(my_facialflux_r_interior, r) - # partition boundaries flux - # flux across partition boundaries def my_facialflux_r_partition(q): qin = cross_rank_trace_pairs(discr, q) return sum(_facial_flux_r(discr, q_tpair=part_pair) for part_pair in qin) pbf_r = obj_array_vectorize(my_facialflux_r_partition, r) - # True boundary implementation - # Okay, not sure about this... - # What I am attempting: - # 1. Loop through all the boundaries - # 2. Define a function my_TP that performes the trace pair for the given - # boundary given a solution variable - # 3. Get the external solution from the boundary routine - # 4. Get hte projected internal solution - # 5. Compute the boundary flux as a sum over boundaries, using the - # obj_array_vectorize to pass each solution variable one at a time - # DO I really need to do this like this? - dbf_r = 0.0 * iff_r + dbf_r = np.zeros_like(iff_r) for btag in boundaries: def my_facialflux_r_boundary(sol_ext, sol_int): @@ -160,18 +124,12 @@ def my_facialflux_r_boundary(sol_ext, sol_int): ) # Compute q, half way done! - # q = discr.inverse_mass(-alpha*(dflux_r-discr.face_mass(iff_r + pbf_r + dbf_r))) q = discr.inverse_mass( - -alpha * epsilon * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r)) + -alpha * indicator * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r)) ) - # flux of q - - # Again we need to vectorize - # q is a object array of object arrays (dim,) of DOFArrays (?) dflux_q = obj_array_vectorize(discr.weak_div, q) - # interior face flux of q def my_facialflux_q_interior(q): qin = interior_trace_pair(discr, q) iff_q = _facial_flux_q(discr, q_tpair=qin) @@ -179,14 +137,13 @@ def my_facialflux_q_interior(q): iff_q = obj_array_vectorize(my_facialflux_q_interior, q) - # flux across partition boundaries def my_facialflux_q_partition(q): qin = cross_rank_trace_pairs(discr, q) return sum(_facial_flux_q(discr, q_tpair=part_pair) for part_pair in qin) pbf_q = obj_array_vectorize(my_facialflux_q_partition, q) - dbf_q = 0.0 * iff_q + dbf_q = np.zeros_like(iff_q) for btag in boundaries: def my_facialflux_q_boundary(sol_ext, sol_int): diff --git a/mirgecom/tag_cells.py b/mirgecom/tag_cells.py index a55abaacd..4167214c9 100644 --- a/mirgecom/tag_cells.py +++ b/mirgecom/tag_cells.py @@ -100,7 +100,6 @@ def compute_smoothness_indicator(): " vec[iel,j]*vec[iel,j]+1.0e-12/ndiscr_nodes_in)", name="smooth_comp", ) - # knl = lp.tag_array_axes(knl, "vec", "stride:auto,stride:auto") return knl @@ -108,11 +107,9 @@ def smoothness_indicator(u, discr, kappa=1.0, s0=-6.0): """Calculate the smoothness indicator.""" assert isinstance(u, DOFArray) - # #@memoize_in(u.array_context, (smoothness_indicator, "get_kernel")) def get_kernel(): return linear_operator_kernel() - # #@memoize_in(u.array_context, (smoothness_indicator, "get_indicator")) def get_indicator(): return compute_smoothness_indicator() @@ -147,11 +144,9 @@ def get_indicator(): vec=uhat[group.index], modes=actx.from_numpy(highest_mode), ) - - # Take log10 of indicator indicator = actx.np.log10(indicator + 1.0e-12) - # Compute artificail viscosity percentage based on idicator and set parameters + # Compute artificial viscosity percentage based on indicator and set parameters yesnol = indicator > (s0 - kappa) yesnou = indicator > (s0 + kappa) sin_indicator = actx.np.where( From 1afa3d78d52979d779e389171b582dac165f1973 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Sun, 14 Mar 2021 14:09:04 -0700 Subject: [PATCH 034/106] Fixed errors in calling gmsh --- examples/doublemach-mpi.py | 81 +++++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index d23adb80f..f775b54f4 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -54,6 +54,51 @@ logger = logging.getLogger(__name__) +def get_doublemach_mesh(): + """Generate or import a grid using `gmsh`. + + Input required: + doubleMach.msh (read existing mesh + + This routine will generate a new grid if it does + not find the grid file (doubleMach.msh). + """ + from meshmode.mesh.io import ( + read_gmsh, + generate_gmsh, + ScriptWithFilesSource, + ScriptSource, + ) + import os + meshfile="doubleMach.msh" + if os.path.exists(meshfile) is False: + mesh = generate_gmsh( + ScriptSource(""" + x0=1.0/6.0; + setsize=0.025; + Point(1) = {0, 0, 0, setsize}; + Point(2) = {x0,0, 0, setsize}; + Point(3) = {4, 0, 0, setsize}; + Point(4) = {4, 1, 0, setsize}; + Point(5) = {0, 1, 0, setsize}; + Line(1) = {1, 2}; + Line(2) = {2, 3}; + Line(5) = {3, 4}; + Line(6) = {4, 5}; + Line(7) = {5, 1}; + Line Loop(8) = {-5, -6, -7, -1, -2}; + Plane Surface(8) = {8}; + Physical Surface('domain') = {8}; + Physical Curve('ic1') = {6}; + Physical Curve('ic2') = {7}; + Physical Curve('ic3') = {1}; + Physical Curve('wall') = {2}; + Physical Curve('out') = {5}; + ""","geo"), force_ambient_dim=2, dimensions=2, target_unit="M") + else: + mesh = read_gmsh(meshfile,force_ambient_dim=2) + + return mesh @mpi_entry_point def main(ctx_factory=cl.create_some_context): @@ -65,19 +110,14 @@ def main(ctx_factory=cl.create_some_context): ) dim = 2 - # nel = (40, 10) order = 3 - # tolerate large errors; case is unstable - exittol = 2.0 # .2 - t_final = 0.0001 + t_final = 1.0e-2 current_cfl = 0.1 - current_dt = 0.000001 + current_dt = 1.0e-4 current_t = 0 eos = IdealSingleGas() initializer = DoubleMachReflection(dim) - # initializer = SodShock1D(dim,x0=0.5) - casename = "sod1d" - # boundaries = {BTAG_ALL: AdiabaticSlipBoundary()} + casename = "doubleMach" from grudge import sym boundaries = { @@ -94,16 +134,16 @@ def main(ctx_factory=cl.create_some_context): checkpoint_t = current_t current_step = 0 timestepper = rk4_step - # box_ll = (0.0, 0.0) - # box_ur = (4.0, 1.0) + s0 = -6.0 + kappa = 1.0 + alpha = 2.0e-2 from mpi4py import MPI comm = MPI.COMM_WORLD - rank = comm.Get_rank() + rank = comm.Get_rank - from meshmode.mesh.io import read_gmsh - gen_grid = partial(read_gmsh, "doubleMach2.msh", force_ambient_dim=2) + gen_grid = partial(get_doublemach_mesh) local_mesh, global_nelements = create_parallel_grid(comm, gen_grid) @@ -112,10 +152,8 @@ def main(ctx_factory=cl.create_some_context): discr = EagerDGDiscretization(actx, local_mesh, order=order, mpi_communicator=comm) nodes = thaw(actx, discr.nodes()) - current_state = initializer(0, nodes) + current_state = initializer(nodes) - # visualizer = make_visualizer(discr, discr.order + 3 - # if discr.dim == 2 else discr.order) visualizer = make_visualizer(discr, discr.order if discr.dim == 2 else discr.order) initname = initializer.__class__.__name__ @@ -153,12 +191,9 @@ def my_rhs(t, state): return inviscid_operator( discr, q=state, t=t, boundaries=boundaries, eos=eos ) + artificial_viscosity( - discr, t=t, r=state, eos=eos, boundaries=boundaries, alpha=2.0e-2 + discr, t=t, r=state, eos=eos, boundaries=boundaries, alpha=alpha, + s0=s0, kappa=kappa ) - # return ( - # inviscid_operator(discr, q=state, t=t,boundaries=boundaries, eos=eos) - # + artificial_viscosity(discr, r=state, eos=eos, boundaries=boundaries, - # alpha=1.0e-3) def my_checkpoint(step, t, dt, state): return sim_checkpoint( @@ -172,9 +207,11 @@ def my_checkpoint(step, t, dt, state): dt=dt, nstatus=nstatus, nviz=nviz, - exittol=exittol, constant_cfl=constant_cfl, comm=comm, + s0=s0, + kappa=kappa, + overwrite=True, ) try: From a404a62d6db4d6747c59dad8d29dd82228be8297 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Sun, 14 Mar 2021 14:38:00 -0700 Subject: [PATCH 035/106] Add gmsh as requirement --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 2af096ad4..4349c925b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ pyvisfile pymetis importlib-resources psutil +gmsh # The following packages will be git cloned by emirge: --editable git+https://github.com/inducer/pymbolic.git#egg=pymbolic From c1cd4792d1e6ef1d262b5e0d320e7fb9fbea55b5 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Sun, 14 Mar 2021 22:02:01 -0700 Subject: [PATCH 036/106] Fix some style issues and add temporary fix for Issue #280 --- examples/doublemach-mpi.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index f775b54f4..6e77514bc 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -54,6 +54,7 @@ logger = logging.getLogger(__name__) + def get_doublemach_mesh(): """Generate or import a grid using `gmsh`. @@ -66,11 +67,10 @@ def get_doublemach_mesh(): from meshmode.mesh.io import ( read_gmsh, generate_gmsh, - ScriptWithFilesSource, ScriptSource, ) import os - meshfile="doubleMach.msh" + meshfile = "doubleMach.msh" if os.path.exists(meshfile) is False: mesh = generate_gmsh( ScriptSource(""" @@ -94,12 +94,13 @@ def get_doublemach_mesh(): Physical Curve('ic3') = {1}; Physical Curve('wall') = {2}; Physical Curve('out') = {5}; - ""","geo"), force_ambient_dim=2, dimensions=2, target_unit="M") + """, "geo"), force_ambient_dim=2, dimensions=2, target_unit="M") else: - mesh = read_gmsh(meshfile,force_ambient_dim=2) + mesh = read_gmsh(meshfile, force_ambient_dim=2) return mesh + @mpi_entry_point def main(ctx_factory=cl.create_some_context): """Drive the example.""" @@ -151,6 +152,17 @@ def main(ctx_factory=cl.create_some_context): discr = EagerDGDiscretization(actx, local_mesh, order=order, mpi_communicator=comm) + + # Temporary fix for Issue #280 + local_boundaries = {} + for btag in boundaries: + bnd_discr = discr.discr_from_dd(btag) + bnd_nodes = thaw(actx, bnd_discr.nodes()) + if bnd_nodes[0][0].shape[0] > 0: + local_boundaries[btag] = boundaries[btag] + boundaries = local_boundaries + # End fix + nodes = thaw(actx, discr.nodes()) current_state = initializer(nodes) From 8b580e5014dd25f70d86529b1ba496de7752ad2a Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 15 Mar 2021 13:34:42 -0500 Subject: [PATCH 037/106] Fix documentation grammer. Co-authored-by: Mike Campbell --- test/test_artificial_viscosity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_artificial_viscosity.py b/test/test_artificial_viscosity.py index 972cfc1b6..822a7eaa9 100644 --- a/test/test_artificial_viscosity.py +++ b/test/test_artificial_viscosity.py @@ -51,7 +51,7 @@ def test_tag_cells(ctx_factory, dim, order): """Test tag_cells. Tests that the cells tagging properly tags cells - given a prescirbed solutions. + given prescribed solutions. """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) From 40364ac41ce999e79573e5980e6f671e8d20851a Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 15 Mar 2021 12:06:34 -0700 Subject: [PATCH 038/106] Renamed shock parameters to be more descriptive. --- mirgecom/initializers.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 8c8bd87d0..593c10e49 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -281,7 +281,7 @@ class DoubleMachReflection: """ def __init__( - self, dim=2, x0=1.0/6.0, us=4.0 + self, dim=2, shock_location=1.0/6.0, shock_speed=4.0 ): """Initialize initial condition options. @@ -289,14 +289,14 @@ def __init__( ---------- dim: int dimension of domain, must be 2 - x0: float + shock_location: float location of shock - us: float - shock speed + shock_speed: float + shock speed, Mach number """ - self._x0 = x0 + self._shock_location = shock_location self._dim = dim - self._us = us + self._shock_speed = shock_speed def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): """ @@ -321,8 +321,8 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): zeros = 0*x_rel - x0 = zeros + self._x0 - us = zeros + self._us + shock_location = zeros + self._shock_location + shock_speed = zeros + self._shock_speed t = zeros + t # Mach 4.0 @@ -336,7 +336,8 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): rhoel = zeros + gmn1 * 18.5 rhoer = zeros + gmn1 * 1.0 - xinter = (x0 + y_rel/np.sqrt(3.0) + 2.0*us*t/np.sqrt(3.0)) + xinter = (shock_location + y_rel/np.sqrt(3.0) + + 2.0*shock_speed*t/np.sqrt(3.0)) sigma = 0.05 xtanh = 1.0/sigma*(x_rel-xinter) mass = rhol/2.0*(actx.np.tanh(-xtanh)+1.0)+rhor/2.0*(actx.np.tanh(xtanh)+1.0) From af24249e6df0c37ea26e9748ef581b05f81bcf6f Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 15 Mar 2021 12:40:57 -0700 Subject: [PATCH 039/106] Added normal shock relations calculator to DoubleMahcReflection case. --- mirgecom/initializers.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 593c10e49..f9510c349 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -314,6 +314,7 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): assert self._dim == 2, "only defined for dim=2" gm1 = eos.gamma() - 1.0 + gp1 = eos.gamma() + 1.0 gmn1 = 1.0 / gm1 x_rel = x_vec[0] y_rel = x_vec[1] @@ -325,15 +326,19 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): shock_speed = zeros + self._shock_speed t = zeros + t - # Mach 4.0 - rhol = zeros + 4.57142857*1.4 - rhor = zeros + 1.4 + # Normal Shock Relations + shock_speed_2 = self._shock_speed * self._shock_speed + rho_jump = gp1 * shock_speed_2 / (gm1 * shock_speed_2 + 2.) + p_jump = (2. * eos.gamma() * shock_speed_2 - gm1) / gp1 + up = 2. * (shock_speed_2 - 1.) / (gp1 * self._shock_speed) - ul = zeros + 3.125*np.cos(np.pi/6.0) + rhol = zeros + eos.gamma() * rho_jump + rhor = zeros + eos.gamma() + ul = zeros + up * np.cos(np.pi/6.0) ur = zeros + 0.0 - vl = zeros - 3.125*np.sin(np.pi/6.0) + vl = zeros - up * np.sin(np.pi/6.0) vr = zeros + 0.0 - rhoel = zeros + gmn1 * 18.5 + rhoel = zeros + gmn1 * p_jump rhoer = zeros + gmn1 * 1.0 xinter = (shock_location + y_rel/np.sqrt(3.0) From 8a50f22a38d468b311358214e4791b4cab9f47b5 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 15 Mar 2021 12:52:03 -0700 Subject: [PATCH 040/106] Remove linter changes for not my file --- examples/heat-source-mpi.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/heat-source-mpi.py b/examples/heat-source-mpi.py index 8150305fc..cca028e79 100644 --- a/examples/heat-source-mpi.py +++ b/examples/heat-source-mpi.py @@ -1,5 +1,3 @@ -"""Demonstrate heat source.""" - __copyright__ = "Copyright (C) 2020 University of Illinois Board of Trustees" __license__ = """ From 77b02639eb730b820de6dd70f405f58451b2e5fb Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 15 Mar 2021 14:49:16 -0700 Subject: [PATCH 041/106] use viz_fields to visualize tagged cells. --- examples/doublemach-mpi.py | 13 ++++++++----- mirgecom/simutil.py | 13 ++----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 6e77514bc..2bd1c719e 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -35,8 +35,9 @@ from grudge.shortcuts import make_visualizer -from mirgecom.euler import inviscid_operator +from mirgecom.euler import inviscid_operator, split_conserved from mirgecom.artificial_viscosity import artificial_viscosity +from mirgecom.tag_cells import smoothness_indicator from mirgecom.simutil import ( inviscid_sim_timestep, sim_checkpoint, @@ -59,7 +60,7 @@ def get_doublemach_mesh(): """Generate or import a grid using `gmsh`. Input required: - doubleMach.msh (read existing mesh + doubleMach.msh (read existing mesh) This routine will generate a new grid if it does not find the grid file (doubleMach.msh). @@ -203,11 +204,14 @@ def my_rhs(t, state): return inviscid_operator( discr, q=state, t=t, boundaries=boundaries, eos=eos ) + artificial_viscosity( - discr, t=t, r=state, eos=eos, boundaries=boundaries, alpha=alpha, + discr, t=t, r=state, boundaries=boundaries, alpha=alpha, eos=eos, s0=s0, kappa=kappa ) def my_checkpoint(step, t, dt, state): + cv = split_conserved(dim, state) + tagged_cells = smoothness_indicator(discr, cv.mass, s0=s0, kappa=kappa) + viz_fields = [("tagged cells", tagged_cells)] return sim_checkpoint( discr, visualizer, @@ -221,8 +225,7 @@ def my_checkpoint(step, t, dt, state): nviz=nviz, constant_cfl=constant_cfl, comm=comm, - s0=s0, - kappa=kappa, + viz_fields=viz_fields, overwrite=True, ) diff --git a/mirgecom/simutil.py b/mirgecom/simutil.py index a6227f0bf..0347ec5db 100644 --- a/mirgecom/simutil.py +++ b/mirgecom/simutil.py @@ -93,8 +93,8 @@ def __init__(self, step, t, state): def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, step=0, t=0, dt=0, cfl=1.0, nstatus=-1, nviz=-1, exittol=1e-16, - s0=None, kappa=None, constant_cfl=False, comm=None, - viz_fields=None, overwrite=False, vis_timer=None): + constant_cfl=False, comm=None, viz_fields=None, overwrite=False, + vis_timer=None): """Check simulation health, status, viz dumps, and restart.""" do_viz = check_step(step=step, interval=nviz) do_status = check_step(step=step, interval=nstatus) @@ -105,10 +105,6 @@ def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, cv = split_conserved(discr.dim, q) dependent_vars = eos.dependent_vars(cv) - from mirgecom.tag_cells import smoothness_indicator - if s0 is not None and kappa is not None: - tagedcells = smoothness_indicator(q[0], discr, kappa=kappa, s0=s0) - rank = 0 if comm is not None: rank = comm.Get_rank() @@ -132,11 +128,6 @@ def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, ("exact_soln", expected_state), ] io_fields.extend(exact_list) - if s0 is not None and kappa is not None: - tagged_list = [ - ("tagged", tagedcells), - ] - io_fields.extend(tagged_list) if viz_fields is not None: io_fields.extend(viz_fields) From 218cb523e501a27c1aabb6ec56899efb9975a816 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 15 Mar 2021 14:54:09 -0700 Subject: [PATCH 042/106] Added interface parameter documentation. --- mirgecom/artificial_viscosity.py | 54 ++++++++++++++++++++++++++------ mirgecom/tag_cells.py | 30 +++++++++++++++--- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index fe6cb1a3a..7b9f4df0c 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -4,11 +4,11 @@ .. math:: - \partial_t \mathbf{Q} = \nabla\cdot{\varepsilon\nabla\mathbf{Q}} + \partial_t \mathbf{R} = \nabla\cdot{\varepsilon\nabla\mathbf{R}} where: -- state $\mathbf{Q} = [\rho, \rho{E}, \rho\vec{V}, \rho{Y}_\alpha]$ +- state $\mathbf{R} = [\rho, \rho{E}, \rho\vec{V}, \rho{Y}_\alpha]$ - artifical viscosity coefficient $\varepsilon$ To evalutate the second order derivative the problem is recast as a set of first @@ -16,10 +16,10 @@ .. math:: - \partial_t \mathbf{Q} = \nabla\cdot{\mathbf{R}} - \mathbf{R} = \varepsilon\nabla\mathbf{Q} + \partial_t \mathbf{R} = \nabla\cdot{\mathbf{Q}} + \mathbf{Q} = \varepsilon\nabla\mathbf{R} -where $\mathbf{R}$ is an intermediate variable. +where $\mathbf{Q}$ is an intermediate variable. RHS Evaluation ^^^^^^^^^^^^^^ @@ -88,9 +88,45 @@ def _facial_flux_q(discr, q_tpair): def artificial_viscosity(discr, t, eos, boundaries, r, alpha, **kwargs): - r"""Compute artifical viscosity for the euler equations.""" + r"""Compute artifical viscosity for the euler equations. + + Calculates + ---------- + numpy.ndarray + The right-hand-side for artificial viscosity for the euler equations. + + .. math:: + + \dot{\nabla\cdot{\varepsilon\nabla\mathbf{R}}} + + Parameters + ---------- + r + State array which expects the quantity to be limited on to be listed + first in the array. For the Euler equations this could be the canonical + conserved variables (mass, energy, mometum) for the fluid along with a + vector of species masses for multi-component fluids. + + boundaries + Dicitionary of boundary functions, one for each valid boundary tag + + t + Time + + alpha + The maximum artifical viscosity coeffiecent to be applied + + eos: mirgecom.eos.GasEOS + Only used as a pass through to the boundary conditions. + + Returns + ------- + numpy.ndarray + Agglomerated object array of DOF Arrays representing the RHS associated + with the artificial viscosity application. + """ # Get smoothness indicator - indicator = smoothness_indicator(r[0], discr, **kwargs) + indicator = smoothness_indicator(discr, r[0], **kwargs) dflux_r = obj_array_vectorize(discr.weak_grad, r) @@ -117,7 +153,7 @@ def my_facialflux_r_boundary(sol_ext, sol_int): ) return _facial_flux_r(discr, q_tpair=q_tpair) - r_ext = boundaries[btag].exterior_soln(discr, eos=eos, btag=btag, t=t, q=r) + r_ext = boundaries[btag].exterior_soln(discr, btag=btag, t=t, q=r, eos=eos) r_int = discr.project("vol", btag, r) dbf_r = dbf_r + obj_array_vectorize_n_args( my_facialflux_r_boundary, r_ext, r_int @@ -150,7 +186,7 @@ def my_facialflux_q_boundary(sol_ext, sol_int): q_tpair = TracePair(btag, interior=sol_int, exterior=sol_ext) return _facial_flux_q(discr, q_tpair=q_tpair) - q_ext = boundaries[btag].av(discr, eos=eos, btag=btag, t=t, q=q) + q_ext = boundaries[btag].av(discr, btag=btag, t=t, q=q, eos=eos) q_int = discr.project("vol", btag, q) dbf_q = dbf_q + obj_array_vectorize_n_args( my_facialflux_q_boundary, q_ext, q_int diff --git a/mirgecom/tag_cells.py b/mirgecom/tag_cells.py index 4167214c9..539cbf97c 100644 --- a/mirgecom/tag_cells.py +++ b/mirgecom/tag_cells.py @@ -18,7 +18,7 @@ .. math:: - \varepsilon_e = \varepsilon_0 + \varepsilon_e = \begin{cases} 0, & s_e < s_0 - \kappa \\ \frac{1}{2}\left( 1 + \sin \frac{\pi(s_e - s_0)}{2 \kappa} \right ), @@ -28,10 +28,9 @@ where: - $\varepsilon_e$ is the element viscosity -- $\varepsilon_0 ~\sim h/p$ is a reference viscosity - $s_e = \log_{10}{S_e} \sim 1/p^4$ is the smoothness indicator - $s_0$ is a reference smoothness value -- $\kappa$ controls the width of the transition between 0 to $\varepsilon_0$ +- $\kappa$ controls the width of the transition between 0 to 1 Smoothness Indicator Evaluation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -103,8 +102,29 @@ def compute_smoothness_indicator(): return knl -def smoothness_indicator(u, discr, kappa=1.0, s0=-6.0): - """Calculate the smoothness indicator.""" +def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): + """Calculate the smoothness indicator. + + Parameters + ---------- + u + A DOF Array of the field that is used to calculate the + smoothness indicator. + + kappa + A optional argument that sets the controls the width of the + transition between 0 to 1. + s0 + A optional argument that sets the smoothness level to limit + on. Logical values are [0,-infinity) where -infinity results in + all cells being tagged and 0 results in none. + + Returns + ------- + meshmode.dof_array.DOFArray + A DOF Array containing elementwise constant values between 0 and 1 + which indicate the smoothness of a given element. + """ assert isinstance(u, DOFArray) def get_kernel(): From cb8be6a102cb0b7089e724324761b97546480db9 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 15 Mar 2021 15:52:44 -0700 Subject: [PATCH 043/106] Remove linting modification to simutil.py --- mirgecom/simutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/simutil.py b/mirgecom/simutil.py index 0347ec5db..42700fd0e 100644 --- a/mirgecom/simutil.py +++ b/mirgecom/simutil.py @@ -121,7 +121,7 @@ def sim_checkpoint(discr, visualizer, eos, q, vizname, exact_soln=None, if do_viz: io_fields = [ ("cv", cv), - ("dv", dependent_vars), + ("dv", dependent_vars) ] if exact_soln is not None: exact_list = [ From 0f2d680a005b9175944cc63f8e913ad923d8ae8e Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 15 Mar 2021 16:28:26 -0700 Subject: [PATCH 044/106] Fixed tests to reflect change in smoothness indicator parameters. --- test/test_artificial_viscosity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_artificial_viscosity.py b/test/test_artificial_viscosity.py index 822a7eaa9..ef36074ad 100644 --- a/test/test_artificial_viscosity.py +++ b/test/test_artificial_viscosity.py @@ -61,7 +61,7 @@ def test_tag_cells(ctx_factory, dim, order): tolerance = 1.e-16 def norm_indicator(expected, discr, soln, **kwargs): - return(discr.norm(expected-smoothness_indicator(soln, discr, **kwargs), + return(discr.norm(expected-smoothness_indicator(discr, soln, **kwargs), np.inf)) from meshmode.mesh.generation import generate_regular_rect_mesh From 834a98cd5946510092ed12c29b987b723262e930 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Fri, 26 Mar 2021 12:35:10 -0500 Subject: [PATCH 045/106] Update mirgecom/initializers.py Co-authored-by: Mike Campbell --- mirgecom/initializers.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index f9510c349..f31a20f96 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -350,12 +350,11 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): + rhoer/2.0*(actx.np.tanh(xtanh)+1.0)) u = ul/2.0*(actx.np.tanh(-xtanh)+1.0)+ur/2.0*(actx.np.tanh(xtanh)+1.0) v = vl/2.0*(actx.np.tanh(-xtanh)+1.0)+vr/2.0*(actx.np.tanh(xtanh)+1.0) - rhou = mass*u - rhov = mass*v - energy = rhoe + 0.5*mass*(u*u + v*v) + vel = make_obj_array([u, v]) + mom = mass * vel + energy = rhoe + .5*mass*np.dot(vel, vel) - return join_conserved(dim=self._dim, mass=mass, energy=energy, - momentum=make_obj_array([rhou, rhov])) + return join_conserved(dim=self._dim, mass=mass, energy=energy, momentum=mom) class Lump: From d72df2abaa2155d7f5942c0e28779baa17f20ae3 Mon Sep 17 00:00:00 2001 From: Mike Campbell Date: Sun, 25 Apr 2021 14:12:52 -0500 Subject: [PATCH 046/106] Refactor AV (#12) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CI: install mirgecom branch directly (#315) * Run flake8 in Github CI on target Py version (#313) * Run flake8 in Github CI on target Py version * Bump Python compat target to 3.8 * Bump Py compatibility target in Github CI to 3.8 Co-authored-by: Matthias Diener * fix CI runs (#316) - Run `brew update` to fix spurious homebrew downloading errors - Make sure to be able to run without a specified branch (for e.g. scheduled CI runs) - prefer mpich over openmpi, as it can show better error messages in CI * skip clone on CI (#318) * Update half-baked, push to save. * Refactor AV to address remaining review comments, merge with main, make it closer to consistent with NS. * Fix up example to use new AV, remove temporary fix for resolved issue. * Fix slipwall boundary issue for multispecies * Tweak for multispecies. * Add documentation for Persson smoothness indicator * Remove function/module name ambiguity * Update doublemach to use av_operator interface * Update test to use av_operator interface * Update docs to correct rendering, formatting * Update docs to correct rendering, formatting * Update docs to correct rendering, formatting Co-authored-by: Matthias Diener Co-authored-by: Andreas Klöckner --- .ci-support/install.sh | 4 +- .github/workflows/ci.yaml | 6 +- doc/misc.rst | 3 + doc/operators/gas-dynamics.rst | 3 +- examples/doublemach-mpi.py | 24 +- mirgecom/artificial_viscosity.py | 311 +++++++++++++----- mirgecom/boundary.py | 68 ++-- mirgecom/fluid.py | 16 + mirgecom/tag_cells.py | 179 ---------- setup.py | 7 +- ...est_artificial_viscosity.py => test_av.py} | 40 ++- 11 files changed, 323 insertions(+), 338 deletions(-) delete mode 100644 mirgecom/tag_cells.py rename test/{test_artificial_viscosity.py => test_av.py} (86%) diff --git a/.ci-support/install.sh b/.ci-support/install.sh index 1327d875a..6b57e2d34 100644 --- a/.ci-support/install.sh +++ b/.ci-support/install.sh @@ -1,11 +1,13 @@ if [ "$(uname)" = "Darwin" ]; then PLATFORM=MacOSX +brew update +brew upgrade brew install open-mpi brew install octave else PLATFORM=Linux sudo apt-get update -sudo apt-get -y install openmpi-bin libopenmpi-dev +sudo apt-get -y install libmpich-dev mpich sudo apt-get -y install octave fi MINIFORGE_INSTALL_DIR=.miniforge3 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ffd78267f..9e626c4f8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,7 +17,8 @@ jobs: - uses: actions/setup-python@v1 with: - python-version: '3.x' + # matches compat target in setup.py + python-version: '3.8' - name: Flake8 test run: | python3 -m venv myenv @@ -143,9 +144,8 @@ jobs: cd .. git clone https://github.com/illinois-ceesd/emirge cd emirge - sed -i.bak '/fetch-mirgecom/d' install.sh cp -a ../mirgecom . - ./install.sh + ./install.sh --skip-clone - name: Run simple mirgecom test run: | diff --git a/doc/misc.rst b/doc/misc.rst index b79553f7f..e5423c112 100644 --- a/doc/misc.rst +++ b/doc/misc.rst @@ -63,3 +63,6 @@ References `DOI: `__ .. [Bassi_1997] F. Bassi and S. Rebay (1997), Journal of Computational Physics 131 \ `(DOI) `__ +.. [Persson_2012] P. Persson and J. Peraire, AIAA 44 \ + `(DOI) `__ + diff --git a/doc/operators/gas-dynamics.rst b/doc/operators/gas-dynamics.rst index bcb0336ed..48aa91507 100644 --- a/doc/operators/gas-dynamics.rst +++ b/doc/operators/gas-dynamics.rst @@ -7,4 +7,5 @@ Gas Dynamics .. automodule:: mirgecom.inviscid .. automodule:: mirgecom.flux .. automodule:: mirgecom.boundary -.. automodule:: mirgecom.euler \ No newline at end of file +.. automodule:: mirgecom.euler +.. automodule:: mirgecom.artificial_viscosity diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 2bd1c719e..4b3036799 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -36,8 +36,10 @@ from mirgecom.euler import inviscid_operator, split_conserved -from mirgecom.artificial_viscosity import artificial_viscosity -from mirgecom.tag_cells import smoothness_indicator +from mirgecom.artificial_viscosity import ( + av_operator, + smoothness_indicator +) from mirgecom.simutil import ( inviscid_sim_timestep, sim_checkpoint, @@ -113,7 +115,9 @@ def main(ctx_factory=cl.create_some_context): dim = 2 order = 3 - t_final = 1.0e-2 + # Too many steps for CI + # t_final = 1.0e-2 + t_final = 1.0e-3 current_cfl = 0.1 current_dt = 1.0e-4 current_t = 0 @@ -154,16 +158,6 @@ def main(ctx_factory=cl.create_some_context): discr = EagerDGDiscretization(actx, local_mesh, order=order, mpi_communicator=comm) - # Temporary fix for Issue #280 - local_boundaries = {} - for btag in boundaries: - bnd_discr = discr.discr_from_dd(btag) - bnd_nodes = thaw(actx, bnd_discr.nodes()) - if bnd_nodes[0][0].shape[0] > 0: - local_boundaries[btag] = boundaries[btag] - boundaries = local_boundaries - # End fix - nodes = thaw(actx, discr.nodes()) current_state = initializer(nodes) @@ -203,8 +197,8 @@ def main(ctx_factory=cl.create_some_context): def my_rhs(t, state): return inviscid_operator( discr, q=state, t=t, boundaries=boundaries, eos=eos - ) + artificial_viscosity( - discr, t=t, r=state, boundaries=boundaries, alpha=alpha, eos=eos, + ) + av_operator( + discr, t=t, q=state, boundaries=boundaries, alpha=alpha, eos=eos, s0=s0, kappa=kappa ) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 7b9f4df0c..290af1201 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -1,30 +1,70 @@ -r""":mod:`mirgecom.artificial viscosity` Artificial viscocity for Euler. +r""":mod:`mirgecom.artificial_viscosity` Artificial viscocity for Euler. -Artificial viscosity for the Euler Equations: +Euler Equations with artificial viscosity term: .. math:: - \partial_t \mathbf{R} = \nabla\cdot{\varepsilon\nabla\mathbf{R}} + \partial_t \mathbf{Q} = -\nabla\cdot\mathbf{F}^I + + \nabla\cdot{\varepsilon\nabla\mathbf{Q}} where: -- state $\mathbf{R} = [\rho, \rho{E}, \rho\vec{V}, \rho{Y}_\alpha]$ -- artifical viscosity coefficient $\varepsilon$ +- fluid state: $\mathbf{Q} = [\rho, \rho{E}, \rho\mathbf{V}, \rho\mathbf{Y}]$ +- inviscid fluxes: $\mathbf{F}^I$ +- artifical viscosity coefficient: $\varepsilon$ To evalutate the second order derivative the problem is recast as a set of first order problems: .. math:: - \partial_t \mathbf{R} = \nabla\cdot{\mathbf{Q}} - \mathbf{Q} = \varepsilon\nabla\mathbf{R} + \partial_t{\mathbf{Q}} &= \nabla\cdot\mathbf{R} -\nabla\cdot\mathbf{F}^I \\ + \mathbf{R} &= \varepsilon\nabla\mathbf{Q} -where $\mathbf{Q}$ is an intermediate variable. +where $\mathbf{R}$ is an intermediate variable, and the artitifial viscosity +coefficient, $\varepsilon$, is spatially dependent and calculated using the +smoothness indicator of [Persson_2012]_: -RHS Evaluation -^^^^^^^^^^^^^^ +.. math:: + + S_e = \frac{\langle u_{N_p} - u_{N_{p-1}}, u_{N_p} - + u_{N_{p-1}}\rangle_e}{\langle u_{N_p}, u_{N_p} \rangle_e} + +where: + +- $S_e$ is the smoothness indicator +- $u_{N_p}$ is the solution in modal basis at the current polynomial order +- $u_{N_{p-1}}$ is the truncated modal represention to the polynomial order $p-1$ +- The $L_2$ inner product on an element is denoted $\langle \cdot,\cdot \rangle_e$ + +The elementwise viscoisty is then calculated: + +.. math:: + + \varepsilon_e = + \begin{cases} + 0, & s_e < s_0 - \kappa \\ + \frac{1}{2}\left( 1 + \sin \frac{\pi(s_e - s_0)}{2 \kappa} \right ), + & s_0-\kappa \le s_e \le s_0+\kappa \\ + 1, & s_e > s_0+\kappa + \end{cases} + +where: + +- $\varepsilon_e$ is the element viscosity +- $s_e = \log_{10}{S_e} \sim 1/p^4$ is the smoothness indicator +- $s_0$ is a reference smoothness value +- $\kappa$ controls the width of the transition between 0 to 1 -.. autofunction:: artificial_viscosity +Smoothness Indicator Evaluation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autofunction:: smoothness_indicator + +AV RHS Evaluation +^^^^^^^^^^^^^^^^^ + +.. autofunction:: av_operator """ __copyright__ = """ @@ -52,22 +92,27 @@ """ import numpy as np -from pytools.obj_array import ( - obj_array_vectorize, - obj_array_vectorize_n_args, -) -from meshmode.dof_array import thaw +import loopy as lp +from modepy import vandermonde +from pytools.obj_array import obj_array_vectorize +from meshmode.dof_array import thaw, DOFArray from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa from grudge.eager import interior_trace_pair, cross_rank_trace_pairs from grudge.symbolic.primitives import TracePair -from mirgecom.tag_cells import smoothness_indicator +from mirgecom.fluid import ( + split_conserved, + join_conserved_vectors +) -def _facial_flux_r(discr, q_tpair): +def _facial_flux_q(discr, q_tpair): - actx = q_tpair.int.array_context + q_int = q_tpair.int + actx = q_int[0].array_context flux_dis = q_tpair.avg + if isinstance(flux_dis, np.ndarray): + flux_dis = flux_dis.reshape(-1, 1) normal = thaw(actx, discr.normal(q_tpair.dd)) @@ -76,32 +121,29 @@ def _facial_flux_r(discr, q_tpair): return discr.project(q_tpair.dd, "all_faces", flux_out) -def _facial_flux_q(discr, q_tpair): +def _facial_flux_r(discr, r_tpair): + r_int = r_tpair.int + actx = r_int[0][0].array_context - actx = q_tpair[0].int.array_context + normal = thaw(actx, discr.normal(r_tpair.dd)) - normal = thaw(actx, discr.normal(q_tpair.dd)) + flux_out = r_tpair.avg @ normal - flux_out = np.dot(q_tpair.avg, normal) + return discr.project(r_tpair.dd, "all_faces", flux_out) - return discr.project(q_tpair.dd, "all_faces", flux_out) - -def artificial_viscosity(discr, t, eos, boundaries, r, alpha, **kwargs): +def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): r"""Compute artifical viscosity for the euler equations. - Calculates - ---------- - numpy.ndarray - The right-hand-side for artificial viscosity for the euler equations. + Computes the the right-hand-side term for artificial viscosity. - .. math:: + .. math:: - \dot{\nabla\cdot{\varepsilon\nabla\mathbf{R}}} + \mbox{RHS}_{\mbox{av}} = \nabla\cdot{\varepsilon\nabla\mathbf{Q}} Parameters ---------- - r + q State array which expects the quantity to be limited on to be listed first in the array. For the Euler equations this could be the canonical conserved variables (mass, energy, mometum) for the fluid along with a @@ -125,72 +167,165 @@ def artificial_viscosity(discr, t, eos, boundaries, r, alpha, **kwargs): Agglomerated object array of DOF Arrays representing the RHS associated with the artificial viscosity application. """ - # Get smoothness indicator - indicator = smoothness_indicator(discr, r[0], **kwargs) - - dflux_r = obj_array_vectorize(discr.weak_grad, r) - - def my_facialflux_r_interior(q): - qin = interior_trace_pair(discr, q) - return _facial_flux_r(discr, q_tpair=qin) + dim = discr.dim + cv = split_conserved(dim, q) - iff_r = obj_array_vectorize(my_facialflux_r_interior, r) + # Get smoothness indicator based on fluid mass density + indicator = smoothness_indicator(discr, cv.mass, **kwargs) - def my_facialflux_r_partition(q): - qin = cross_rank_trace_pairs(discr, q) - return sum(_facial_flux_r(discr, q_tpair=part_pair) for part_pair in qin) + grad_q_vol = join_conserved_vectors(dim, obj_array_vectorize(discr.weak_grad, q)) - pbf_r = obj_array_vectorize(my_facialflux_r_partition, r) - - dbf_r = np.zeros_like(iff_r) + q_flux_int = _facial_flux_q(discr, q_tpair=interior_trace_pair(discr, q)) + q_flux_pb = sum(_facial_flux_q(discr, q_tpair=pb_tpair) + for pb_tpair in cross_rank_trace_pairs(discr, q)) + q_flux_db = 0 for btag in boundaries: - - def my_facialflux_r_boundary(sol_ext, sol_int): - q_tpair = TracePair( - btag, - interior=sol_int, - exterior=sol_ext, - ) - return _facial_flux_r(discr, q_tpair=q_tpair) - - r_ext = boundaries[btag].exterior_soln(discr, btag=btag, t=t, q=r, eos=eos) - r_int = discr.project("vol", btag, r) - dbf_r = dbf_r + obj_array_vectorize_n_args( - my_facialflux_r_boundary, r_ext, r_int - ) - - # Compute q, half way done! - q = discr.inverse_mass( - -alpha * indicator * (dflux_r - discr.face_mass(iff_r + pbf_r + dbf_r)) + q_tpair = TracePair( + btag, + interior=discr.project("vol", btag, q), + exterior=boundaries[btag].exterior_q(discr, btag=btag, t=t, + q=q, eos=eos)) + q_flux_db = q_flux_db + _facial_flux_q(discr, q_tpair=q_tpair) + q_bnd_flux = q_flux_int + q_flux_pb + q_flux_db + + # Compute R + r = discr.inverse_mass( + -alpha * indicator * (grad_q_vol - discr.face_mass(q_bnd_flux)) ) - dflux_q = obj_array_vectorize(discr.weak_div, q) - - def my_facialflux_q_interior(q): - qin = interior_trace_pair(discr, q) - iff_q = _facial_flux_q(discr, q_tpair=qin) - return iff_q + div_r_vol = discr.weak_div(r) + r_flux_int = _facial_flux_r(discr, r_tpair=interior_trace_pair(discr, r)) + r_flux_pb = sum(_facial_flux_r(discr, r_tpair=pb_tpair) + for pb_tpair in cross_rank_trace_pairs(discr, r)) + r_flux_db = 0 + for btag in boundaries: + r_tpair = TracePair( + btag, + interior=discr.project("vol", btag, r), + exterior=boundaries[btag].exterior_grad_q(discr, btag=btag, t=t, + grad_q=r, eos=eos)) + r_flux_db = r_flux_db + _facial_flux_r(discr, r_tpair=r_tpair) + r_flux_bnd = r_flux_int + r_flux_pb + r_flux_db + + # Return the AV RHS term + return discr.inverse_mass(-div_r_vol + discr.face_mass(r_flux_bnd)) + + +def artificial_viscosity(discr, t, eos, boundaries, q, alpha, **kwargs): + """Interface :function:`av_operator` with backwards-compatible API.""" + from warnings import warn + warn("Do not call artificial_viscosity; it is now called av_operator. This" + "function will disappear in 2021", DeprecationWarning, stacklevel=2) + return av_operator(discr=discr, eos=eos, boundaries=boundaries, + q=q, alpha=alpha, t=t) + + +def linear_operator_kernel(): + """Apply linear operator to all elements.""" + from meshmode.array_context import make_loopy_program + + knl = make_loopy_program( + """{[iel,idof,j]: + 0<=iel (s0 - kappa) + yesnou = indicator > (s0 + kappa) + sin_indicator = actx.np.where( + yesnol, + 0.5 * (1.0 + actx.np.sin(np.pi * (indicator - s0) / (2.0 * kappa))), + 0.0 * indicator, + ) + indicator = actx.np.where(yesnou, 1.0 + 0.0 * indicator, sin_indicator) - # Return the rhs contribution - return discr.inverse_mass(-dflux_q + discr.face_mass(iff_q + pbf_q + dbf_q)) + return indicator diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 1bc751354..65be0ed17 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -37,7 +37,11 @@ from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa # from mirgecom.eos import IdealSingleGas from grudge.symbolic.primitives import TracePair -from mirgecom.fluid import split_conserved, join_conserved +from mirgecom.fluid import ( + split_conserved, + join_conserved, + join_conserved_vectors +) class PrescribedBoundary: @@ -62,11 +66,11 @@ def __init__(self, userfunc): def boundary_pair(self, discr, q, btag, **kwargs): """Get the interior and exterior solution on the boundary.""" - ext_soln = self.exterior_soln(discr, q, btag, **kwargs) + ext_soln = self.exterior_q(discr, q, btag, **kwargs) int_soln = discr.project("vol", btag, q) return TracePair(btag, interior=int_soln, exterior=ext_soln) - def exterior_soln(self, discr, q, btag, **kwargs): + def exterior_q(self, discr, q, btag, **kwargs): """Get the exterior solution on the boundary.""" actx = q[0].array_context @@ -75,9 +79,9 @@ def exterior_soln(self, discr, q, btag, **kwargs): ext_soln = self._userfunc(nodes, **kwargs) return ext_soln - def av(self, discr, q, btag, **kwargs): + def exterior_grad_q(self, discr, grad_q, btag, **kwargs): """Get the exterior solution on the boundary.""" - return discr.project("vol", btag, q) + return discr.project("vol", btag, grad_q) class DummyBoundary: @@ -88,17 +92,17 @@ class DummyBoundary: def boundary_pair(self, discr, q, btag, **kwargs): """Get the interior and exterior solution on the boundary.""" - dir_soln = self.exterior_soln(discr, q, btag, **kwargs) + dir_soln = self.exterior_q(discr, q, btag, **kwargs) return TracePair(btag, interior=dir_soln, exterior=dir_soln) - def exterior_soln(self, discr, q, btag, **kwargs): + def exterior_q(self, discr, q, btag, **kwargs): """Get the exterior solution on the boundary.""" dir_soln = discr.project("vol", btag, q) return dir_soln - def av(self, discr, q, btag, **kwargs): - """Get the exterior solution on the boundary.""" - return discr.project("vol", btag, q) + def exterior_grad_q(self, discr, grad_q, btag, **kwargs): + """Get the grad_q on the exterior of the boundary.""" + return discr.project("vol", btag, grad_q) class AdiabaticSlipBoundary: @@ -121,12 +125,12 @@ class AdiabaticSlipBoundary: def boundary_pair(self, discr, q, btag, **kwargs): """Get the interior and exterior solution on the boundary.""" - bndry_soln = self.exterior_soln(discr, q, btag, **kwargs) + bndry_soln = self.exterior_q(discr, q, btag, **kwargs) int_soln = discr.project("vol", btag, q) return TracePair(btag, interior=int_soln, exterior=bndry_soln) - def exterior_soln(self, discr, q, btag, **kwargs): + def exterior_q(self, discr, q, btag, **kwargs): """Get the exterior solution on the boundary. The exterior solution is set such that there will be vanishing @@ -160,40 +164,42 @@ def exterior_soln(self, discr, q, btag, **kwargs): # Form the external boundary solution with the new momentum bndry_soln = join_conserved(dim=dim, mass=int_cv.mass, energy=int_cv.energy, - momentum=ext_mom) + momentum=ext_mom, + species_mass=int_cv.species_mass) return bndry_soln - def av(self, discr, q, btag, **kwargs): - """Get the exterior solution on the boundary.""" + def exterior_grad_q(self, discr, grad_q, btag, **kwargs): + """Get the exterior grad(Q) on the boundary.""" # Grab some boundary-relevant data - dim = discr.dim - cv = split_conserved(dim, q) + num_equations, dim = grad_q.shape + num_species = num_equations - dim - 2 + cv = split_conserved(dim, grad_q) actx = cv.mass[0].array_context - # Grab a unit normal to the boundary normal = thaw(actx, discr.normal(btag)) # Get the interior soln - int_soln = discr.project("vol", btag, q) - bndry_q = split_conserved(dim, int_soln) + int_soln = discr.project("vol", btag, grad_q) + int_cv = split_conserved(dim, int_soln) # create result array to fill - result = np.zeros(2+dim, dtype=object) + result = np.empty(shape=grad_q.shape, dtype=object) # flip signs on mass and energy # to apply a neumann condition on q - result[0] = -1.0*bndry_q.mass - result[1] = -1.0*bndry_q.energy + result[0] = -int_cv.mass + result[1] = -int_cv.energy # Subtract 2*wall-normal component of q # to enforce q=0 on the wall # flip remaining components to set a neumann condition - from pytools.obj_array import make_obj_array - q_mom_normcomp = make_obj_array( - [np.outer(normal, np.dot(bndry_q.momentum, normal))[i] - for i in range(dim)] - ) - result[2:] = -1*(bndry_q.momentum-2.0*q_mom_normcomp) - - return(result) + s_mom_normcomp = np.outer(normal, np.dot(int_cv.momentum, normal)) + s_mom_flux = 2*s_mom_normcomp - int_cv.momentum + for idim in range(dim): + result[2+idim] = s_mom_flux[idim] + + for ispec in range(num_species): + result[dim+2+ispec] = -int_cv.species_mass[ispec] + + return join_conserved_vectors(dim, result) diff --git a/mirgecom/fluid.py b/mirgecom/fluid.py index a83ac13f5..33e3dac3b 100644 --- a/mirgecom/fluid.py +++ b/mirgecom/fluid.py @@ -6,6 +6,7 @@ .. autoclass:: ConservedVars .. autofunction:: split_conserved .. autofunction:: join_conserved +.. autofunction:: join_conserved_vectors Helper Functions ^^^^^^^^^^^^^^^^ @@ -165,6 +166,21 @@ def join_conserved(dim, mass, energy, momentum, return result +def join_conserved_vectors(dim, ary): + r"""Create a 2D array of shape(len(ary), dim).""" + neq = len(ary) + nspecies = neq - (dim+2) + retval = np.empty(shape=(neq, dim), dtype=object) + cv = split_conserved(dim, ary) + retval[0] = cv.mass + retval[1] = cv.energy + for i in range(dim): + retval[2+i] = ary[2+i] + for i in range(nspecies): + retval[dim+2+i] = ary[dim+2+i] + return retval + + def velocity_gradient(discr, cv, grad_cv): r""" Compute the gradient of fluid velocity. diff --git a/mirgecom/tag_cells.py b/mirgecom/tag_cells.py deleted file mode 100644 index 539cbf97c..000000000 --- a/mirgecom/tag_cells.py +++ /dev/null @@ -1,179 +0,0 @@ -r""":mod:`mirgecom.tag_cells` Compute smoothness indicator. - -Evalutes the smoothness indicator of Persson: - -.. math:: - - S_e = \frac{\langle u_{N_p} - u_{N_{p-1}}, u_{N_p} - - u_{N_{p-1}}\rangle_e}{\langle u_{N_p}, u_{N_p} \rangle_e} - -where: -- $S_e$ is the smoothness indicator -- $u_{N_p}$ is the modal representation of the solution at the current polynomial - order -- $u_{N_{p-1}}$ is the truncated modal represention to the polynomial order $p-1$ -- The $L_2$ inner product on an element is denoted $\langle \cdot,\cdot \rangle_e$ - -The elementwise viscoisty is then calculated: - -.. math:: - - \varepsilon_e = - \begin{cases} - 0, & s_e < s_0 - \kappa \\ - \frac{1}{2}\left( 1 + \sin \frac{\pi(s_e - s_0)}{2 \kappa} \right ), - & s_0-\kappa \le s_e \le s_0+\kappa \\ - 1, & s_e > s_0+\kappa - \end{cases} - -where: -- $\varepsilon_e$ is the element viscosity -- $s_e = \log_{10}{S_e} \sim 1/p^4$ is the smoothness indicator -- $s_0$ is a reference smoothness value -- $\kappa$ controls the width of the transition between 0 to 1 - -Smoothness Indicator Evaluation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. autofunction:: smoothness_indicator -""" - -__copyright__ = """ -Copyright (C) 2020 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. -""" - -import numpy as np -import loopy as lp -from meshmode.dof_array import DOFArray -from modepy import vandermonde - - -def linear_operator_kernel(): - """Apply linear operator to all elements.""" - from meshmode.array_context import make_loopy_program - - knl = make_loopy_program( - """{[iel,idof,j]: - 0<=iel (s0 - kappa) - yesnou = indicator > (s0 + kappa) - sin_indicator = actx.np.where( - yesnol, - 0.5 * (1.0 + actx.np.sin(np.pi * (indicator - s0) / (2.0 * kappa))), - 0.0 * indicator, - ) - indicator = actx.np.where(yesnou, 1.0 + 0.0 * indicator, sin_indicator) - - return indicator diff --git a/setup.py b/setup.py index ea49258d4..5a2e5a4f9 100644 --- a/setup.py +++ b/setup.py @@ -27,10 +27,7 @@ def main(): "License :: OSI Approved :: MIT License", "Natural Language :: English", "Programming Language :: Python", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3", "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Information Analysis", "Topic :: Scientific/Engineering :: Mathematics", @@ -41,7 +38,7 @@ def main(): packages=find_packages(), - python_requires="~=3.6", + python_requires="~=3.8", install_requires=[ "mpi4py>=3", diff --git a/test/test_artificial_viscosity.py b/test/test_av.py similarity index 86% rename from test/test_artificial_viscosity.py rename to test/test_av.py index ef36074ad..fa6a7e9e3 100644 --- a/test/test_artificial_viscosity.py +++ b/test/test_av.py @@ -29,15 +29,19 @@ import numpy as np import pyopencl as cl import pytest +from pytools.obj_array import make_obj_array from meshmode.array_context import PyOpenCLArrayContext from meshmode.dof_array import thaw from meshmode.mesh import BTAG_ALL - -from mirgecom.tag_cells import smoothness_indicator -from mirgecom.artificial_viscosity import artificial_viscosity +from mirgecom.fluid import ( + join_conserved, +) +from mirgecom.artificial_viscosity import ( + av_operator, + smoothness_indicator +) from mirgecom.boundary import DummyBoundary from grudge.eager import EagerDGDiscretization -from pytools.obj_array import flat_obj_array from pyopencl.tools import ( # noqa pytest_generate_tests_for_pyopencl as pytest_generate_tests, ) @@ -179,22 +183,28 @@ def test_artificial_viscosity(ctx_factory, dim, order): boundaries = {BTAG_ALL: DummyBoundary()} # Uniform field return 0 rhs - fields = flat_obj_array(zeros+1.0) - rhs = artificial_viscosity(discr, t=0, eos=None, boundaries=boundaries, - r=fields, alpha=1.0, s0=-np.inf) + mass = zeros + 1.0 + energy = zeros + 1.0 + momentum = make_obj_array([zeros + 0 for _ in range(dim)]) + q = join_conserved(dim, mass=mass, energy=energy, momentum=momentum) + rhs = av_operator(discr, t=0, eos=None, boundaries=boundaries, + q=q, alpha=1.0, s0=-np.inf) err = discr.norm(rhs, np.inf) assert err < tolerance - # Linar field return 0 rhs - fields = flat_obj_array(nodes[0]) - rhs = artificial_viscosity(discr, t=0, eos=None, boundaries=boundaries, - r=fields, alpha=1.0, s0=-np.inf) + # Linear field return 0 rhs + mass = nodes[0] + energy = 2.5 + zeros + q = join_conserved(dim, mass=mass, energy=energy, momentum=momentum) + rhs = av_operator(discr, t=0, eos=None, boundaries=boundaries, + q=q, alpha=1.0, s0=-np.inf) err = discr.norm(rhs, np.inf) assert err < tolerance # Quadratic field return constant 2 - fields = flat_obj_array(np.dot(nodes, nodes)) - rhs = artificial_viscosity(discr, t=0, eos=None, boundaries=boundaries, - r=fields, alpha=1.0, s0=-np.inf) - err = discr.norm(2.*dim-rhs, np.inf) + mass = np.dot(nodes, nodes) + q = join_conserved(dim, mass=mass, energy=energy, momentum=momentum) + rhs = av_operator(discr, t=0, eos=None, boundaries=boundaries, + q=q, alpha=1.0, s0=-np.inf) + err = discr.norm(2.*dim-rhs[0], np.inf) assert err < tolerance From 8fc97716acaa7c21d0a7147b56a706d22d03417d Mon Sep 17 00:00:00 2001 From: Mike Campbell Date: Mon, 26 Apr 2021 11:50:16 -0500 Subject: [PATCH 047/106] Add some comments for docs, try to address @thomasgibson comments (#13) --- mirgecom/artificial_viscosity.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 290af1201..8cd872b64 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -106,7 +106,7 @@ def _facial_flux_q(discr, q_tpair): - + """Compute facial flux for each scalar component of Q.""" q_int = q_tpair.int actx = q_int[0].array_context @@ -116,17 +116,22 @@ def _facial_flux_q(discr, q_tpair): normal = thaw(actx, discr.normal(q_tpair.dd)) + # This uses a central scalar flux along nhat: + # flux = 1/2 * (Q- + Q+) * nhat flux_out = flux_dis * normal return discr.project(q_tpair.dd, "all_faces", flux_out) def _facial_flux_r(discr, r_tpair): + """Compute facial flux for vector compontnent of grad(Q).""" r_int = r_tpair.int actx = r_int[0][0].array_context normal = thaw(actx, discr.normal(r_tpair.dd)) + # This uses a central vector flux along nhat: + # flux = 1/2 * (grad(Q)- + grad(Q)+) .dot. nhat flux_out = r_tpair.avg @ normal return discr.project(r_tpair.dd, "all_faces", flux_out) @@ -173,11 +178,15 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): # Get smoothness indicator based on fluid mass density indicator = smoothness_indicator(discr, cv.mass, **kwargs) + # R=Grad(Q) volume part grad_q_vol = join_conserved_vectors(dim, obj_array_vectorize(discr.weak_grad, q)) + # R=Grad(Q) Q flux over interior faces q_flux_int = _facial_flux_q(discr, q_tpair=interior_trace_pair(discr, q)) + # R=Grad(Q) Q flux interior faces on partition boundaries q_flux_pb = sum(_facial_flux_q(discr, q_tpair=pb_tpair) for pb_tpair in cross_rank_trace_pairs(discr, q)) + # R=Grad(Q) Q flux domain boundary part (i.e. BCs) q_flux_db = 0 for btag in boundaries: q_tpair = TracePair( @@ -186,6 +195,7 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): exterior=boundaries[btag].exterior_q(discr, btag=btag, t=t, q=q, eos=eos)) q_flux_db = q_flux_db + _facial_flux_q(discr, q_tpair=q_tpair) + # Total Q flux across element boundaries q_bnd_flux = q_flux_int + q_flux_pb + q_flux_db # Compute R @@ -193,10 +203,14 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): -alpha * indicator * (grad_q_vol - discr.face_mass(q_bnd_flux)) ) + # RHS_av = div(R) volume part div_r_vol = discr.weak_div(r) + # RHS_av = div(R): grad(Q) flux interior faces part r_flux_int = _facial_flux_r(discr, r_tpair=interior_trace_pair(discr, r)) + # RHS_av = div(R): grad(Q) flux interior faces on the partition boundaries r_flux_pb = sum(_facial_flux_r(discr, r_tpair=pb_tpair) for pb_tpair in cross_rank_trace_pairs(discr, r)) + # RHS_av = div(R): grad(Q) flux domain boundary part (BCs) r_flux_db = 0 for btag in boundaries: r_tpair = TracePair( @@ -205,6 +219,7 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): exterior=boundaries[btag].exterior_grad_q(discr, btag=btag, t=t, grad_q=r, eos=eos)) r_flux_db = r_flux_db + _facial_flux_r(discr, r_tpair=r_tpair) + # Total grad(Q) flux element boundaries r_flux_bnd = r_flux_int + r_flux_pb + r_flux_db # Return the AV RHS term From 0495f3bd3f2008fcb438c4ec71a3af098beb8d87 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 15:53:20 -0500 Subject: [PATCH 048/106] Update examples/doublemach-mpi.py to get rank properly Co-authored-by: Matt Smith --- examples/doublemach-mpi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 4b3036799..588bcaaa7 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -147,7 +147,7 @@ def main(ctx_factory=cl.create_some_context): from mpi4py import MPI comm = MPI.COMM_WORLD - rank = comm.Get_rank + rank = comm.Get_rank() gen_grid = partial(get_doublemach_mesh) From b93411b354bda32a3db9c73465aca1d8856a4567 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 15:53:52 -0500 Subject: [PATCH 049/106] Update logic to check if file exists Co-authored-by: Matt Smith --- examples/doublemach-mpi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 588bcaaa7..7d336be96 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -74,7 +74,7 @@ def get_doublemach_mesh(): ) import os meshfile = "doubleMach.msh" - if os.path.exists(meshfile) is False: + if not os.path.exists(meshfile): mesh = generate_gmsh( ScriptSource(""" x0=1.0/6.0; From 3f336fd76125e6b4a6be8c0cea0c1417413054f4 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 15:54:18 -0500 Subject: [PATCH 050/106] Update documenatation Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 8cd872b64..8134a0a53 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -124,7 +124,7 @@ def _facial_flux_q(discr, q_tpair): def _facial_flux_r(discr, r_tpair): - """Compute facial flux for vector compontnent of grad(Q).""" + """Compute facial flux for vector component of grad(Q).""" r_int = r_tpair.int actx = r_int[0][0].array_context From 8fa696ec694dbbd6e5a8c6b24acaf2ac3fda5e49 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 15:54:53 -0500 Subject: [PATCH 051/106] Update documentation Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 8134a0a53..213aa1450 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -138,7 +138,7 @@ def _facial_flux_r(discr, r_tpair): def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): - r"""Compute artifical viscosity for the euler equations. + r"""Compute artificial viscosity for the Euler equations. Computes the the right-hand-side term for artificial viscosity. From de305d91ebf81cfe85dbf1f73ac527fd53766e4b Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 15:55:18 -0500 Subject: [PATCH 052/106] Update documentation Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 213aa1450..a799821d1 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -155,7 +155,7 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): vector of species masses for multi-component fluids. boundaries - Dicitionary of boundary functions, one for each valid boundary tag + Dictionary of boundary functions, one for each valid boundary tag t Time From 376ba33f2e55b33057740b5f47a78f333c8e79b2 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 15:55:45 -0500 Subject: [PATCH 053/106] Update documentation Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index a799821d1..466995aca 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -161,7 +161,7 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): Time alpha - The maximum artifical viscosity coeffiecent to be applied + The maximum artificial viscosity coefficient to be applied eos: mirgecom.eos.GasEOS Only used as a pass through to the boundary conditions. From 184e2cc1728516a200e4513e5a32c3f14fb2e5b3 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 15:57:11 -0500 Subject: [PATCH 054/106] Update documentation Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 466995aca..15ea7ac10 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -169,8 +169,7 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): Returns ------- numpy.ndarray - Agglomerated object array of DOF Arrays representing the RHS associated - with the artificial viscosity application. + The artificial viscosity operator applied to *q*. """ dim = discr.dim cv = split_conserved(dim, q) From 1fea6b686c7ec1c2fc5b23cbe3b8d759cae0c75d Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 16:00:08 -0500 Subject: [PATCH 055/106] Update documentation Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 15ea7ac10..c9584b853 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -281,7 +281,7 @@ def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): A optional argument that sets the controls the width of the transition between 0 to 1. s0 - A optional argument that sets the smoothness level to limit + An optional argument that sets the smoothness level to limit on. Logical values are [0,-infinity) where -infinity results in all cells being tagged and 0 results in none. From f17e4508105631f245f3d99f694ceaf86132b087 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 16:00:34 -0500 Subject: [PATCH 056/106] Update documentation Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index c9584b853..1f535bfef 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -282,7 +282,7 @@ def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): transition between 0 to 1. s0 An optional argument that sets the smoothness level to limit - on. Logical values are [0,-infinity) where -infinity results in + on. Values in the range $(-\infty,0]$ are allowed, where $-\infty$ results in all cells being tagged and 0 results in none. Returns From 9cd58d348c22e260be62460e431aab33e10fa167 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 16:00:56 -0500 Subject: [PATCH 057/106] Update documentation Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 1f535bfef..11143e3c1 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -273,9 +273,8 @@ def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): Parameters ---------- - u - A DOF Array of the field that is used to calculate the - smoothness indicator. + u: meshmode.dof_array.DOFArray + The field that is used to calculate the smoothness indicator. kappa A optional argument that sets the controls the width of the From cc2752a0e87692b5797d82c713e5de1daf0f6f87 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 16:01:18 -0500 Subject: [PATCH 058/106] Update documentation Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 11143e3c1..217177229 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -277,8 +277,7 @@ def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): The field that is used to calculate the smoothness indicator. kappa - A optional argument that sets the controls the width of the - transition between 0 to 1. + An optional argument that controls the width of the transition from 0 to 1. s0 An optional argument that sets the smoothness level to limit on. Values in the range $(-\infty,0]$ are allowed, where $-\infty$ results in From d78cdabd41ea178b2067243d5d53d746b9991e19 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 16:02:19 -0500 Subject: [PATCH 059/106] Update documentation Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 217177229..24ec14b22 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -286,8 +286,8 @@ def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): Returns ------- meshmode.dof_array.DOFArray - A DOF Array containing elementwise constant values between 0 and 1 - which indicate the smoothness of a given element. + The elementwise constant values between 0 and 1 which indicate the smoothness + of a given element. """ assert isinstance(u, DOFArray) From d55666c2a1a84adc0b36a6ab6e5d215e592edfc6 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 16:03:15 -0500 Subject: [PATCH 060/106] Update documentation Co-authored-by: Matt Smith --- mirgecom/initializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index e6bbc2370..00cb6a1af 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -268,7 +268,7 @@ class DoubleMachReflection: - Woodward and Collela - The inital condition is defined + The initial condition is defined .. math:: From 06d171c2c74b49e0f39db59dd8b9876d5befaa44 Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 20:16:36 -0700 Subject: [PATCH 061/106] Fix flake8/docstyle issue --- mirgecom/artificial_viscosity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 24ec14b22..35db68006 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -269,7 +269,7 @@ def compute_smoothness_indicator(): def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): - """Calculate the smoothness indicator. + r"""Calculate the smoothness indicator. Parameters ---------- From 974bcd47752630f73c6b9a536352b4bc128a5b2c Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 26 Apr 2021 20:25:23 -0700 Subject: [PATCH 062/106] Clean up doublemach case documentation and remove dim as parameter. --- examples/doublemach-mpi.py | 2 +- mirgecom/initializers.py | 48 ++++++++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 7d336be96..17d538466 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -122,7 +122,7 @@ def main(ctx_factory=cl.create_some_context): current_dt = 1.0e-4 current_t = 0 eos = IdealSingleGas() - initializer = DoubleMachReflection(dim) + initializer = DoubleMachReflection() casename = "doubleMach" from grudge import sym diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 00cb6a1af..35d001627 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -272,46 +272,70 @@ class DoubleMachReflection: .. math:: - (\rho,u,v,P) = + {\rho}(x < x_s(y,t)) &= \gamma \rho_j\\ + {\rho}(x > x_s(y,t)) &= \gamma\\ + {\rho}{V_x}(x < x_s(y,t)) &= u_p \cos(\pi/6)\\ + {\rho}{V_x}(x > x_s(y,t)) &= 0\\ + {\rho}{V_y}(x > x_s(y,t)) &= u_p \sin(\pi/6)\\ + {\rho}{V_y}(x > x_s(y,t)) &= 0\\ + {\rho}E(x < x_s(y,t)) &= (\gamma-1)p_j\\ + {\rho}E(x > x_s(y,t)) &= (\gamma-1) - This function only serves as an initial condition + where the shock position is given, + + .. math:: + + x_s = x_0 + y/\sqrt{3} + 2 u_s t/\sqrt{3} + + and the normal shock jump relations are + + .. math:: + + \rho_j &= \frac{(\gamma + 1) u_s^2}{(\gamma-1) u_s^2 + 2} \\ + p_j &= \frac{2 \gamma u_s^2 - (\gamma - 1)}{\gamma+1} \\ + u_p &= 2 \frac{u_s^2-1}{(\gamma+1) u_s} + + The initial shock location is given by $x_0$ and $u_s$ is the shock speed. + This function serves as an initial condition as well as boundary conditions + for $t>0$ .. automethod:: __init__ .. automethod:: __call__ """ def __init__( - self, dim=2, shock_location=1.0/6.0, shock_speed=4.0 + self, shock_location=1.0/6.0, shock_speed=4.0 ): """Initialize initial condition options. Parameters ---------- - dim: int - dimension of domain, must be 2 shock_location: float - location of shock + initial location of shock shock_speed: float shock speed, Mach number """ self._shock_location = shock_location - self._dim = dim self._shock_speed = shock_speed def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): - """ - Create the 1D Sod's shock solution at locations *x_vec*. + r""" + Create the initial condition for the double Mach reflection case at + locations *x_vec*. Also provides boundary conditions for solution at + times $t>0$. Parameters ---------- t: float - Current time at which the solution is desired (unused) + Current time of solution when called as a boundary condition x_vec: numpy.ndarray Nodal coordinates eos: :class:`mirgecom.eos.GasEOS` Equation of state class to be used in construction of soln (if needed) """ - assert self._dim == 2, "only defined for dim=2" + # Fail if numdim is other than 2 + if(len(x_vec)) != 2: + raise ValueError("Case only defined for 2 dimensions") gm1 = eos.gamma() - 1.0 gp1 = eos.gamma() + 1.0 @@ -354,7 +378,7 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): mom = mass * vel energy = rhoe + .5*mass*np.dot(vel, vel) - return join_conserved(dim=self._dim, mass=mass, energy=energy, momentum=mom) + return join_conserved(dim=2, mass=mass, energy=energy, momentum=mom) class Lump: From f3e6a6110968876e40be153abdb8fb5787b32ecd Mon Sep 17 00:00:00 2001 From: Mike Campbell Date: Tue, 27 Apr 2021 11:12:19 -0500 Subject: [PATCH 063/106] Tweak the doublemach docs and implementation just a bit (#15) * Tweak the doublemach docs and implementation just a bit to remove some unneeded stuff. * tweak verbiage per @w-hagen suggestion to be more correct and complete --- doc/misc.rst | 3 ++- mirgecom/initializers.py | 52 +++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/doc/misc.rst b/doc/misc.rst index e5423c112..b9bf6a445 100644 --- a/doc/misc.rst +++ b/doc/misc.rst @@ -65,4 +65,5 @@ References `(DOI) `__ .. [Persson_2012] P. Persson and J. Peraire, AIAA 44 \ `(DOI) `__ - +.. [Woodward_1984] Woodward and Colella, Journal of Computational Physics, 54 \ + `(DOI) `__ diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 35d001627..0caa5c6c5 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -266,9 +266,8 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): class DoubleMachReflection: r"""Implement the double shock reflection problem. - - Woodward and Collela - - The initial condition is defined + The double shock reflection solution is crafted after [Woodward_1984]_ + and is defined by: .. math:: @@ -279,7 +278,7 @@ class DoubleMachReflection: {\rho}{V_y}(x > x_s(y,t)) &= u_p \sin(\pi/6)\\ {\rho}{V_y}(x > x_s(y,t)) &= 0\\ {\rho}E(x < x_s(y,t)) &= (\gamma-1)p_j\\ - {\rho}E(x > x_s(y,t)) &= (\gamma-1) + {\rho}E(x > x_s(y,t)) &= (\gamma-1), where the shock position is given, @@ -296,8 +295,6 @@ class DoubleMachReflection: u_p &= 2 \frac{u_s^2-1}{(\gamma+1) u_s} The initial shock location is given by $x_0$ and $u_s$ is the shock speed. - This function serves as an initial condition as well as boundary conditions - for $t>0$ .. automethod:: __init__ .. automethod:: __call__ @@ -306,7 +303,7 @@ class DoubleMachReflection: def __init__( self, shock_location=1.0/6.0, shock_speed=4.0 ): - """Initialize initial condition options. + """Initialize double shock reflection parameters. Parameters ---------- @@ -320,14 +317,18 @@ def __init__( def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): r""" - Create the initial condition for the double Mach reflection case at - locations *x_vec*. Also provides boundary conditions for solution at - times $t>0$. + Create double mach reflection solution at locations *x_vec*. + + At times $t > 0$, calls to this routine create an advanced solution + under the assumption of constant normal shock speed *shock_speed*. + The advanced solution *is not* the exact solution, but is appropriate + for use as an exact boundary solution on the top and upstream (left) + side of the domain. Parameters ---------- t: float - Current time of solution when called as a boundary condition + Time at which to compute the solution x_vec: numpy.ndarray Nodal coordinates eos: :class:`mirgecom.eos.GasEOS` @@ -344,29 +345,23 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): y_rel = x_vec[1] actx = x_rel.array_context - zeros = 0*x_rel - - shock_location = zeros + self._shock_location - shock_speed = zeros + self._shock_speed - t = zeros + t - # Normal Shock Relations shock_speed_2 = self._shock_speed * self._shock_speed rho_jump = gp1 * shock_speed_2 / (gm1 * shock_speed_2 + 2.) p_jump = (2. * eos.gamma() * shock_speed_2 - gm1) / gp1 up = 2. * (shock_speed_2 - 1.) / (gp1 * self._shock_speed) - rhol = zeros + eos.gamma() * rho_jump - rhor = zeros + eos.gamma() - ul = zeros + up * np.cos(np.pi/6.0) - ur = zeros + 0.0 - vl = zeros - up * np.sin(np.pi/6.0) - vr = zeros + 0.0 - rhoel = zeros + gmn1 * p_jump - rhoer = zeros + gmn1 * 1.0 - - xinter = (shock_location + y_rel/np.sqrt(3.0) - + 2.0*shock_speed*t/np.sqrt(3.0)) + rhol = eos.gamma() * rho_jump + rhor = eos.gamma() + ul = up * np.cos(np.pi/6.0) + ur = 0.0 + vl = up * np.sin(np.pi/6.0) + vr = 0.0 + rhoel = gmn1 * p_jump + rhoer = gmn1 * 1.0 + + xinter = (self._shock_location + y_rel/np.sqrt(3.0) + + 2.0*self._shock_speed*t/np.sqrt(3.0)) sigma = 0.05 xtanh = 1.0/sigma*(x_rel-xinter) mass = rhol/2.0*(actx.np.tanh(-xtanh)+1.0)+rhor/2.0*(actx.np.tanh(xtanh)+1.0) @@ -374,6 +369,7 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): + rhoer/2.0*(actx.np.tanh(xtanh)+1.0)) u = ul/2.0*(actx.np.tanh(-xtanh)+1.0)+ur/2.0*(actx.np.tanh(xtanh)+1.0) v = vl/2.0*(actx.np.tanh(-xtanh)+1.0)+vr/2.0*(actx.np.tanh(xtanh)+1.0) + vel = make_obj_array([u, v]) mom = mass * vel energy = rhoe + .5*mass*np.dot(vel, vel) From fbe4de37231785c0583b079093aef024d6b66a7d Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Tue, 27 Apr 2021 12:37:12 -0500 Subject: [PATCH 064/106] Remove superfluous isinstance check Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 35db68006..f6374d4f0 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -110,15 +110,11 @@ def _facial_flux_q(discr, q_tpair): q_int = q_tpair.int actx = q_int[0].array_context - flux_dis = q_tpair.avg - if isinstance(flux_dis, np.ndarray): - flux_dis = flux_dis.reshape(-1, 1) - normal = thaw(actx, discr.normal(q_tpair.dd)) # This uses a central scalar flux along nhat: # flux = 1/2 * (Q- + Q+) * nhat - flux_out = flux_dis * normal + flux_out = np.outer(q_tpair.avg, normal) return discr.project(q_tpair.dd, "all_faces", flux_out) From 7dfa8143c5162dada86b5d819469fe53d42128ff Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Tue, 27 Apr 2021 10:39:44 -0700 Subject: [PATCH 065/106] Use added grudge functionality to get modal solution --- mirgecom/artificial_viscosity.py | 36 ++++---------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index f6374d4f0..a0e5daeb3 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -92,13 +92,12 @@ """ import numpy as np -import loopy as lp -from modepy import vandermonde from pytools.obj_array import obj_array_vectorize from meshmode.dof_array import thaw, DOFArray from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa from grudge.eager import interior_trace_pair, cross_rank_trace_pairs from grudge.symbolic.primitives import TracePair +from grudge.dof_desc import DD_VOLUME_MODAL, DD_VOLUME from mirgecom.fluid import ( split_conserved, join_conserved_vectors @@ -230,22 +229,6 @@ def artificial_viscosity(discr, t, eos, boundaries, q, alpha, **kwargs): q=q, alpha=alpha, t=t) -def linear_operator_kernel(): - """Apply linear operator to all elements.""" - from meshmode.array_context import make_loopy_program - - knl = make_loopy_program( - """{[iel,idof,j]: - 0<=iel Date: Tue, 27 Apr 2021 10:52:00 -0700 Subject: [PATCH 066/106] Updated AV documentation to reflect new use of cv-specific fluid functions --- mirgecom/artificial_viscosity.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index a0e5daeb3..26b92cfcd 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -144,10 +144,9 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): Parameters ---------- q - State array which expects the quantity to be limited on to be listed - first in the array. For the Euler equations this could be the canonical - conserved variables (mass, energy, mometum) for the fluid along with a - vector of species masses for multi-component fluids. + State array of the canonical conserved variables (mass, energy, momentum) + for the fluid along with a vector of species masses for multi-component + fluids. boundaries Dictionary of boundary functions, one for each valid boundary tag From 88f35307ee612d81fac0d24237182a40ba39cd05 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Wed, 28 Apr 2021 10:53:59 -0500 Subject: [PATCH 067/106] remove commented out import Co-authored-by: Thomas H. Gibson --- mirgecom/boundary.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 65be0ed17..d44d8050e 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -35,7 +35,6 @@ import numpy as np from meshmode.dof_array import thaw from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa -# from mirgecom.eos import IdealSingleGas from grudge.symbolic.primitives import TracePair from mirgecom.fluid import ( split_conserved, From bde00282367898931ca1c926705440f72cb22e7d Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Wed, 28 Apr 2021 17:32:38 -0700 Subject: [PATCH 068/106] Fix sign error in doublemach case --- mirgecom/initializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 0caa5c6c5..6e27c6621 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -355,7 +355,7 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): rhor = eos.gamma() ul = up * np.cos(np.pi/6.0) ur = 0.0 - vl = up * np.sin(np.pi/6.0) + vl = - up * np.sin(np.pi/6.0) vr = 0.0 rhoel = gmn1 * p_jump rhoer = gmn1 * 1.0 From 13d26191e7fc618c59905bb5bf81f5eb307fd5f7 Mon Sep 17 00:00:00 2001 From: Mike Campbell Date: Thu, 29 Apr 2021 14:22:15 -0500 Subject: [PATCH 069/106] Replace join_conserved_vectors with np.stack per @majosm suggestion. (#16) * Replace join_conserved_vectors with np.stack per @majosm suggestion. * Make it work for scalar Q * Clean up grad_q boundary routine after array shape corrections. * Update docs per @w-hagen review comments. * Nudge doc precision --- mirgecom/artificial_viscosity.py | 61 ++++++++++++++++++++------------ mirgecom/boundary.py | 26 ++++---------- test/test_av.py | 18 +++------- 3 files changed, 49 insertions(+), 56 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 26b92cfcd..3df91c417 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -98,42 +98,45 @@ from grudge.eager import interior_trace_pair, cross_rank_trace_pairs from grudge.symbolic.primitives import TracePair from grudge.dof_desc import DD_VOLUME_MODAL, DD_VOLUME -from mirgecom.fluid import ( - split_conserved, - join_conserved_vectors -) def _facial_flux_q(discr, q_tpair): """Compute facial flux for each scalar component of Q.""" - q_int = q_tpair.int - actx = q_int[0].array_context + flux_dis = q_tpair.avg + if isinstance(flux_dis, np.ndarray): + actx = flux_dis[0].array_context + flux_dis = flux_dis.reshape(-1, 1) + else: + actx = flux_dis.array_context normal = thaw(actx, discr.normal(q_tpair.dd)) # This uses a central scalar flux along nhat: # flux = 1/2 * (Q- + Q+) * nhat - flux_out = np.outer(q_tpair.avg, normal) + flux_out = flux_dis * normal return discr.project(q_tpair.dd, "all_faces", flux_out) def _facial_flux_r(discr, r_tpair): """Compute facial flux for vector component of grad(Q).""" - r_int = r_tpair.int - actx = r_int[0][0].array_context + flux_dis = r_tpair.avg + if isinstance(flux_dis[0], np.ndarray): + actx = flux_dis[0][0].array_context + else: + actx = flux_dis[0].array_context normal = thaw(actx, discr.normal(r_tpair.dd)) # This uses a central vector flux along nhat: # flux = 1/2 * (grad(Q)- + grad(Q)+) .dot. nhat - flux_out = r_tpair.avg @ normal + flux_out = flux_dis @ normal return discr.project(r_tpair.dd, "all_faces", flux_out) def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): - r"""Compute artificial viscosity for the Euler equations. + r"""Compute the artificial viscosity right-hand-side. Computes the the right-hand-side term for artificial viscosity. @@ -143,36 +146,48 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): Parameters ---------- - q - State array of the canonical conserved variables (mass, energy, momentum) + q: :class:`~meshmode.dof_array.DOFArray` or :class:`~numpy.ndarray` + + Single :class:`~meshmode.dof_array.DOFArray` for a scalar or an object array + (:class:`~numpy.ndarray`) for a vector of + :class:`~meshmode.dof_array.DOFArray` on which to operate. + + When used with fluid solvers, *q* is expected to be the fluid state array + of the canonical conserved variables (mass, energy, momentum) for the fluid along with a vector of species masses for multi-component fluids. - boundaries + boundaries: float + Dictionary of boundary functions, one for each valid boundary tag - t + t: float + Time - alpha + alpha: float + The maximum artificial viscosity coefficient to be applied - eos: mirgecom.eos.GasEOS + eos: :class:`~mirgecom.eos.GasEOS` + Only used as a pass through to the boundary conditions. Returns ------- numpy.ndarray + The artificial viscosity operator applied to *q*. """ - dim = discr.dim - cv = split_conserved(dim, q) - - # Get smoothness indicator based on fluid mass density - indicator = smoothness_indicator(discr, cv.mass, **kwargs) + # Get smoothness indicator based on first component + indicator_field = q[0] if isinstance(q, np.ndarray) else q + indicator = smoothness_indicator(discr, indicator_field, **kwargs) # R=Grad(Q) volume part - grad_q_vol = join_conserved_vectors(dim, obj_array_vectorize(discr.weak_grad, q)) + if isinstance(q, np.ndarray): + grad_q_vol = np.stack(obj_array_vectorize(discr.weak_grad, q), axis=0) + else: + grad_q_vol = discr.weak_grad(q) # R=Grad(Q) Q flux over interior faces q_flux_int = _facial_flux_q(discr, q_tpair=interior_trace_pair(discr, q)) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index d44d8050e..2d3cc292b 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -38,8 +38,7 @@ from grudge.symbolic.primitives import TracePair from mirgecom.fluid import ( split_conserved, - join_conserved, - join_conserved_vectors + join_conserved ) @@ -172,9 +171,9 @@ def exterior_grad_q(self, discr, grad_q, btag, **kwargs): """Get the exterior grad(Q) on the boundary.""" # Grab some boundary-relevant data num_equations, dim = grad_q.shape - num_species = num_equations - dim - 2 cv = split_conserved(dim, grad_q) actx = cv.mass[0].array_context + # Grab a unit normal to the boundary normal = thaw(actx, discr.normal(btag)) @@ -182,23 +181,12 @@ def exterior_grad_q(self, discr, grad_q, btag, **kwargs): int_soln = discr.project("vol", btag, grad_q) int_cv = split_conserved(dim, int_soln) - # create result array to fill - result = np.empty(shape=grad_q.shape, dtype=object) - - # flip signs on mass and energy - # to apply a neumann condition on q - result[0] = -int_cv.mass - result[1] = -int_cv.energy - # Subtract 2*wall-normal component of q # to enforce q=0 on the wall - # flip remaining components to set a neumann condition s_mom_normcomp = np.outer(normal, np.dot(int_cv.momentum, normal)) - s_mom_flux = 2*s_mom_normcomp - int_cv.momentum - for idim in range(dim): - result[2+idim] = s_mom_flux[idim] - - for ispec in range(num_species): - result[dim+2+ispec] = -int_cv.species_mass[ispec] + s_mom_flux = int_cv.momentum - 2*s_mom_normcomp - return join_conserved_vectors(dim, result) + # flip components to set a neumann condition + return join_conserved(dim, mass=-int_cv.mass, energy=-int_cv.energy, + momentum=-s_mom_flux, + species_mass=-int_cv.species_mass) diff --git a/test/test_av.py b/test/test_av.py index fa6a7e9e3..152d32a30 100644 --- a/test/test_av.py +++ b/test/test_av.py @@ -29,13 +29,9 @@ import numpy as np import pyopencl as cl import pytest -from pytools.obj_array import make_obj_array from meshmode.array_context import PyOpenCLArrayContext from meshmode.dof_array import thaw from meshmode.mesh import BTAG_ALL -from mirgecom.fluid import ( - join_conserved, -) from mirgecom.artificial_viscosity import ( av_operator, smoothness_indicator @@ -183,28 +179,22 @@ def test_artificial_viscosity(ctx_factory, dim, order): boundaries = {BTAG_ALL: DummyBoundary()} # Uniform field return 0 rhs - mass = zeros + 1.0 - energy = zeros + 1.0 - momentum = make_obj_array([zeros + 0 for _ in range(dim)]) - q = join_conserved(dim, mass=mass, energy=energy, momentum=momentum) + q = zeros + 1.0 rhs = av_operator(discr, t=0, eos=None, boundaries=boundaries, q=q, alpha=1.0, s0=-np.inf) err = discr.norm(rhs, np.inf) assert err < tolerance # Linear field return 0 rhs - mass = nodes[0] - energy = 2.5 + zeros - q = join_conserved(dim, mass=mass, energy=energy, momentum=momentum) + q = nodes[0] rhs = av_operator(discr, t=0, eos=None, boundaries=boundaries, q=q, alpha=1.0, s0=-np.inf) err = discr.norm(rhs, np.inf) assert err < tolerance # Quadratic field return constant 2 - mass = np.dot(nodes, nodes) - q = join_conserved(dim, mass=mass, energy=energy, momentum=momentum) + q = np.dot(nodes, nodes) rhs = av_operator(discr, t=0, eos=None, boundaries=boundaries, q=q, alpha=1.0, s0=-np.inf) - err = discr.norm(2.*dim-rhs[0], np.inf) + err = discr.norm(2.*dim-rhs, np.inf) assert err < tolerance From b3556c9b210a17c867bdc1e720e93db26ddd2d31 Mon Sep 17 00:00:00 2001 From: Mike Campbell Date: Thu, 29 Apr 2021 18:27:02 -0500 Subject: [PATCH 070/106] Rename vars more precisely in AV boundary routine. (#17) * Rename vars more precisely in AV boundary routine. * Correct mistaken variable identity. --- mirgecom/boundary.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 2d3cc292b..0bf4764f2 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -178,15 +178,15 @@ def exterior_grad_q(self, discr, grad_q, btag, **kwargs): normal = thaw(actx, discr.normal(btag)) # Get the interior soln - int_soln = discr.project("vol", btag, grad_q) - int_cv = split_conserved(dim, int_soln) + gradq_int = discr.project("vol", btag, grad_q) + gradq_comp = split_conserved(dim, gradq_int) # Subtract 2*wall-normal component of q # to enforce q=0 on the wall - s_mom_normcomp = np.outer(normal, np.dot(int_cv.momentum, normal)) - s_mom_flux = int_cv.momentum - 2*s_mom_normcomp + s_mom_normcomp = np.outer(normal, np.dot(gradq_comp.momentum, normal)) + s_mom_flux = gradq_comp.momentum - 2*s_mom_normcomp # flip components to set a neumann condition - return join_conserved(dim, mass=-int_cv.mass, energy=-int_cv.energy, + return join_conserved(dim, mass=-gradq_comp.mass, energy=-gradq_comp.energy, momentum=-s_mom_flux, - species_mass=-int_cv.species_mass) + species_mass=-gradq_comp.species_mass) From ef9c67e27592049e2ae1a134c9aeaa0eebdd85c3 Mon Sep 17 00:00:00 2001 From: "Thomas H. Gibson" Date: Thu, 29 Apr 2021 18:27:42 -0500 Subject: [PATCH 071/106] Make artificial viscosity documentation more general (#18) * Make artificial viscosity documentation more general * One line header for artificial viscosity module --- doc/operators/artificial_viscosity.rst | 4 ++++ doc/operators/gas-dynamics.rst | 1 - doc/operators/operators.rst | 1 + mirgecom/artificial_viscosity.py | 27 ++++++++++++++------------ 4 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 doc/operators/artificial_viscosity.rst diff --git a/doc/operators/artificial_viscosity.rst b/doc/operators/artificial_viscosity.rst new file mode 100644 index 000000000..9b583612a --- /dev/null +++ b/doc/operators/artificial_viscosity.rst @@ -0,0 +1,4 @@ +Artificial Viscosity +==================== + +.. automodule:: mirgecom.artificial_viscosity diff --git a/doc/operators/gas-dynamics.rst b/doc/operators/gas-dynamics.rst index 48aa91507..d1949554a 100644 --- a/doc/operators/gas-dynamics.rst +++ b/doc/operators/gas-dynamics.rst @@ -8,4 +8,3 @@ Gas Dynamics .. automodule:: mirgecom.flux .. automodule:: mirgecom.boundary .. automodule:: mirgecom.euler -.. automodule:: mirgecom.artificial_viscosity diff --git a/doc/operators/operators.rst b/doc/operators/operators.rst index c0b40c7fe..0907c286d 100644 --- a/doc/operators/operators.rst +++ b/doc/operators/operators.rst @@ -6,4 +6,5 @@ Operators wave-eq diffusion + artificial_viscosity gas-dynamics diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 3df91c417..5a134c01a 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -1,27 +1,30 @@ -r""":mod:`mirgecom.artificial_viscosity` Artificial viscocity for Euler. +r""":mod:`mirgecom.artificial_viscosity` Artificial viscosity for hyperbolic systems. -Euler Equations with artificial viscosity term: +Consider the following system of conservation laws of the form: .. math:: - \partial_t \mathbf{Q} = -\nabla\cdot\mathbf{F}^I + - \nabla\cdot{\varepsilon\nabla\mathbf{Q}} + \partial_t \mathbf{Q} + \nabla\cdot\mathbf{F} = 0, -where: +where $\mathbf{Q}$ is the state vector and $\mathbf{F}$ is the vector of +fluxes. This module applies an artificial viscosity term by augmenting +the governing equations in the following way: + +.. math:: -- fluid state: $\mathbf{Q} = [\rho, \rho{E}, \rho\mathbf{V}, \rho\mathbf{Y}]$ -- inviscid fluxes: $\mathbf{F}^I$ -- artifical viscosity coefficient: $\varepsilon$ + \partial_t \mathbf{Q} + \nabla\cdot\mathbf{F} = + \nabla\cdot{\varepsilon\nabla\mathbf{Q}}, -To evalutate the second order derivative the problem is recast as a set of first - order problems: +where $\varepsilon$ is the artificial viscosity coefficient. +To evalutate the second order derivative numerically, the problem +is recast as a set of first order problems: .. math:: - \partial_t{\mathbf{Q}} &= \nabla\cdot\mathbf{R} -\nabla\cdot\mathbf{F}^I \\ + \partial_t{\mathbf{Q}} + \nabla\cdot\mathbf{F} &= \nabla\cdot\mathbf{R} \\ \mathbf{R} &= \varepsilon\nabla\mathbf{Q} -where $\mathbf{R}$ is an intermediate variable, and the artitifial viscosity +where $\mathbf{R}$ is an auxiliary variable, and the artitifial viscosity coefficient, $\varepsilon$, is spatially dependent and calculated using the smoothness indicator of [Persson_2012]_: From 961a5bb42156d36887f5cd671512a165c607fd3e Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Thu, 29 Apr 2021 18:31:23 -0500 Subject: [PATCH 072/106] Fixed spelling Co-authored-by: Matt Smith --- mirgecom/artificial_viscosity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 5a134c01a..4001d4e34 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -24,7 +24,7 @@ \partial_t{\mathbf{Q}} + \nabla\cdot\mathbf{F} &= \nabla\cdot\mathbf{R} \\ \mathbf{R} &= \varepsilon\nabla\mathbf{Q} -where $\mathbf{R}$ is an auxiliary variable, and the artitifial viscosity +where $\mathbf{R}$ is an auxiliary variable, and the artificial viscosity coefficient, $\varepsilon$, is spatially dependent and calculated using the smoothness indicator of [Persson_2012]_: @@ -40,7 +40,7 @@ - $u_{N_{p-1}}$ is the truncated modal represention to the polynomial order $p-1$ - The $L_2$ inner product on an element is denoted $\langle \cdot,\cdot \rangle_e$ -The elementwise viscoisty is then calculated: +The elementwise viscosity is then calculated: .. math:: From ea3dc359abbd2e8f852b4f60ff4a77dbec3e0ac2 Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Thu, 29 Apr 2021 22:32:11 -0500 Subject: [PATCH 073/106] Remove join_conserved_vectors Co-authored-by: Mike Campbell --- mirgecom/fluid.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/mirgecom/fluid.py b/mirgecom/fluid.py index ef2e64909..655e2abe8 100644 --- a/mirgecom/fluid.py +++ b/mirgecom/fluid.py @@ -6,7 +6,6 @@ .. autoclass:: ConservedVars .. autofunction:: split_conserved .. autofunction:: join_conserved -.. autofunction:: join_conserved_vectors Helper Functions ^^^^^^^^^^^^^^^^ @@ -300,21 +299,6 @@ def join_conserved(dim, mass, energy, momentum, return result -def join_conserved_vectors(dim, ary): - r"""Create a 2D array of shape(len(ary), dim).""" - neq = len(ary) - nspecies = neq - (dim+2) - retval = np.empty(shape=(neq, dim), dtype=object) - cv = split_conserved(dim, ary) - retval[0] = cv.mass - retval[1] = cv.energy - for i in range(dim): - retval[2+i] = ary[2+i] - for i in range(nspecies): - retval[dim+2+i] = ary[dim+2+i] - return retval - - def velocity_gradient(discr, cv, grad_cv): r""" Compute the gradient of fluid velocity. From 70a469664a417f211dd1dd4126ecaf6bb6644c11 Mon Sep 17 00:00:00 2001 From: "Thomas H. Gibson" Date: Thu, 6 May 2021 14:13:04 -0500 Subject: [PATCH 074/106] Rewrite shock indicator, cache program and mode computations (#20) --- mirgecom/artificial_viscosity.py | 80 +++++++++++++++++--------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 4001d4e34..cf1cd8ae3 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -95,6 +95,8 @@ """ import numpy as np + +from pytools import memoize_in, keyed_memoize_in from pytools.obj_array import obj_array_vectorize from meshmode.dof_array import thaw, DOFArray from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa @@ -246,24 +248,6 @@ def artificial_viscosity(discr, t, eos, boundaries, q, alpha, **kwargs): q=q, alpha=alpha, t=t) -def compute_smoothness_indicator(): - """Compute the smoothness indicator for all elements.""" - from meshmode.array_context import make_loopy_program - - knl = make_loopy_program( - """{[iel,idof,j,k]: - 0<=iel Date: Thu, 6 May 2021 14:20:31 -0500 Subject: [PATCH 075/106] Update double mach example (#22) --- examples/doublemach-mpi.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 17d538466..e58ea34c6 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -1,4 +1,4 @@ -"""Demonstrate doublemach reflection.""" +"""Demonstrate double mach reflection.""" __copyright__ = """ Copyright (C) 2020 University of Illinois Board of Trustees @@ -31,6 +31,7 @@ from meshmode.array_context import PyOpenCLArrayContext from meshmode.dof_array import thaw from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa +from grudge.dof_desc import DTAG_BOUNDARY from grudge.eager import EagerDGDiscretization from grudge.shortcuts import make_visualizer @@ -124,14 +125,13 @@ def main(ctx_factory=cl.create_some_context): eos = IdealSingleGas() initializer = DoubleMachReflection() casename = "doubleMach" - from grudge import sym boundaries = { - sym.DTAG_BOUNDARY("ic1"): PrescribedBoundary(initializer), - sym.DTAG_BOUNDARY("ic2"): PrescribedBoundary(initializer), - sym.DTAG_BOUNDARY("ic3"): PrescribedBoundary(initializer), - sym.DTAG_BOUNDARY("wall"): AdiabaticSlipBoundary(), - sym.DTAG_BOUNDARY("out"): AdiabaticSlipBoundary(), + DTAG_BOUNDARY("ic1"): PrescribedBoundary(initializer), + DTAG_BOUNDARY("ic2"): PrescribedBoundary(initializer), + DTAG_BOUNDARY("ic3"): PrescribedBoundary(initializer), + DTAG_BOUNDARY("wall"): AdiabaticSlipBoundary(), + DTAG_BOUNDARY("out"): AdiabaticSlipBoundary(), } constant_cfl = False nstatus = 10 From 445c5c81dbf1f2e9777ec1593f1fe60713bff3ee Mon Sep 17 00:00:00 2001 From: Matt Smith Date: Thu, 6 May 2021 14:25:18 -0500 Subject: [PATCH 076/106] Clean up object array handling in flux routines (#19) * clean up object array handling in flux routines * add note about get_array_container_context --- mirgecom/artificial_viscosity.py | 38 +++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index cf1cd8ae3..273d7fb74 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -105,37 +105,49 @@ from grudge.dof_desc import DD_VOLUME_MODAL, DD_VOLUME +# FIXME: Remove when get_array_container_context is added to meshmode +def _get_actx(obj): + if isinstance(obj, TracePair): + return _get_actx(obj.int) + if isinstance(obj, np.ndarray): + return _get_actx(obj[0]) + elif isinstance(obj, DOFArray): + return obj.array_context + else: + raise ValueError("Unknown type; can't retrieve array context.") + + +# Tweak the behavior of np.outer to return a lower-dimensional object if either/both +# of the arguments are scalars (np.outer always returns a matrix) +def _outer(a, b): + if isinstance(a, np.ndarray) and isinstance(b, np.ndarray): + return np.outer(a, b) + else: + return a*b + + def _facial_flux_q(discr, q_tpair): """Compute facial flux for each scalar component of Q.""" - flux_dis = q_tpair.avg - if isinstance(flux_dis, np.ndarray): - actx = flux_dis[0].array_context - flux_dis = flux_dis.reshape(-1, 1) - else: - actx = flux_dis.array_context + actx = _get_actx(q_tpair) normal = thaw(actx, discr.normal(q_tpair.dd)) # This uses a central scalar flux along nhat: # flux = 1/2 * (Q- + Q+) * nhat - flux_out = flux_dis * normal + flux_out = _outer(q_tpair.avg, normal) return discr.project(q_tpair.dd, "all_faces", flux_out) def _facial_flux_r(discr, r_tpair): """Compute facial flux for vector component of grad(Q).""" - flux_dis = r_tpair.avg - if isinstance(flux_dis[0], np.ndarray): - actx = flux_dis[0][0].array_context - else: - actx = flux_dis[0].array_context + actx = _get_actx(r_tpair) normal = thaw(actx, discr.normal(r_tpair.dd)) # This uses a central vector flux along nhat: # flux = 1/2 * (grad(Q)- + grad(Q)+) .dot. nhat - flux_out = flux_dis @ normal + flux_out = r_tpair.avg @ normal return discr.project(r_tpair.dd, "all_faces", flux_out) From e2d7dddfc99ee5b6887408ebd44d2904c6bf9503 Mon Sep 17 00:00:00 2001 From: Mike Campbell Date: Fri, 7 May 2021 15:03:35 -0500 Subject: [PATCH 077/106] Sooth the bugbear. --- mirgecom/initializers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 2a82c1d86..1152f018c 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -319,7 +319,7 @@ def __init__( self._shock_location = shock_location self._shock_speed = shock_speed - def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): + def __call__(self, x_vec, *, t=0, eos=None, **kwargs): r""" Create double mach reflection solution at locations *x_vec*. @@ -341,6 +341,8 @@ def __call__(self, x_vec, *, t=0, eos=IdealSingleGas()): # Fail if numdim is other than 2 if(len(x_vec)) != 2: raise ValueError("Case only defined for 2 dimensions") + if eos is None: + eos=IdealSingleGas() gm1 = eos.gamma() - 1.0 gp1 = eos.gamma() + 1.0 From 3a61993e026a7f45fc55987e64077eaf5c8b0324 Mon Sep 17 00:00:00 2001 From: Mike Campbell Date: Fri, 7 May 2021 15:09:01 -0500 Subject: [PATCH 078/106] Unpoke the bugbear. --- mirgecom/initializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 1152f018c..34512a2bb 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -342,7 +342,7 @@ def __call__(self, x_vec, *, t=0, eos=None, **kwargs): if(len(x_vec)) != 2: raise ValueError("Case only defined for 2 dimensions") if eos is None: - eos=IdealSingleGas() + eos = IdealSingleGas() gm1 = eos.gamma() - 1.0 gp1 = eos.gamma() + 1.0 From 3b88176c5f1c2f9edc1dfcf8730273bdff5db18b Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Mon, 10 May 2021 14:07:21 -0500 Subject: [PATCH 079/106] Pull AV boundaries into NS. --- mirgecom/artificial_viscosity.py | 48 +++++--------- mirgecom/boundary.py | 106 +++++++++++++++++++++++++++---- mirgecom/euler.py | 2 +- mirgecom/flux.py | 31 +++++++++ 4 files changed, 141 insertions(+), 46 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 273d7fb74..d0977e837 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -206,22 +206,15 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): else: grad_q_vol = discr.weak_grad(q) - # R=Grad(Q) Q flux over interior faces - q_flux_int = _facial_flux_q(discr, q_tpair=interior_trace_pair(discr, q)) - # R=Grad(Q) Q flux interior faces on partition boundaries - q_flux_pb = sum(_facial_flux_q(discr, q_tpair=pb_tpair) - for pb_tpair in cross_rank_trace_pairs(discr, q)) - # R=Grad(Q) Q flux domain boundary part (i.e. BCs) - q_flux_db = 0 - for btag in boundaries: - q_tpair = TracePair( - btag, - interior=discr.project("vol", btag, q), - exterior=boundaries[btag].exterior_q(discr, btag=btag, t=t, - q=q, eos=eos)) - q_flux_db = q_flux_db + _facial_flux_q(discr, q_tpair=q_tpair) - # Total Q flux across element boundaries - q_bnd_flux = q_flux_int + q_flux_pb + q_flux_db + # Total flux of fluid soln Q across element boundaries + q_bnd_flux = (_facial_flux_q(discr, q_tpair=interior_trace_pair(discr, q)) + + sum(_facial_flux_q(discr, q_tpair=pb_tpair) + for pb_tpair in cross_rank_trace_pairs(discr, q))) + q_bnd_flux2 = sum(bnd.q_boundary_flux(discr, btag, q=q, eos=eos, **kwargs) + for btag, bnd in boundaries.items()) + if isinstance(q, np.ndarray): + q_bnd_flux2 = np.stack(q_bnd_flux2) + q_bnd_flux = q_bnd_flux + q_bnd_flux2 # Compute R r = discr.inverse_mass( @@ -230,25 +223,16 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): # RHS_av = div(R) volume part div_r_vol = discr.weak_div(r) - # RHS_av = div(R): grad(Q) flux interior faces part - r_flux_int = _facial_flux_r(discr, r_tpair=interior_trace_pair(discr, r)) - # RHS_av = div(R): grad(Q) flux interior faces on the partition boundaries - r_flux_pb = sum(_facial_flux_r(discr, r_tpair=pb_tpair) + # Total flux of grad(Q) across element boundaries + r_bnd_flux = (_facial_flux_r(discr, r_tpair=interior_trace_pair(discr, r)) + + sum(_facial_flux_r(discr, r_tpair=pb_tpair) for pb_tpair in cross_rank_trace_pairs(discr, r)) - # RHS_av = div(R): grad(Q) flux domain boundary part (BCs) - r_flux_db = 0 - for btag in boundaries: - r_tpair = TracePair( - btag, - interior=discr.project("vol", btag, r), - exterior=boundaries[btag].exterior_grad_q(discr, btag=btag, t=t, - grad_q=r, eos=eos)) - r_flux_db = r_flux_db + _facial_flux_r(discr, r_tpair=r_tpair) - # Total grad(Q) flux element boundaries - r_flux_bnd = r_flux_int + r_flux_pb + r_flux_db + + sum(bnd.s_boundary_flux(discr, btag, grad_q=r, eos=eos, + **kwargs) + for btag, bnd in boundaries.items())) # Return the AV RHS term - return discr.inverse_mass(-div_r_vol + discr.face_mass(r_flux_bnd)) + return discr.inverse_mass(-div_r_vol + discr.face_mass(r_bnd_flux)) def artificial_viscosity(discr, t, eos, boundaries, q, alpha, **kwargs): diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 61de39d31..bd681a3a9 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -98,7 +98,7 @@ class FluidBC(FluidBoundary): .. automethod:: boundary_pair """ - def q_boundary_flux(self, discr, btag, eos, q, **kwargs): + def q_boundary_flux(self, discr, btag, q, eos, **kwargs): """Get the flux through boundary *btag* for each scalar in *q*.""" raise NotImplementedError() @@ -106,19 +106,19 @@ def s_boundary_flux(self, discr, btag, q, eos, **kwargs): r"""Get $\nabla\mathbf{Q}$ flux across the boundary faces.""" raise NotImplementedError() - def t_boundary_flux(self, discr, btag, eos, q, **kwargs): + def t_boundary_flux(self, discr, btag, q, eos, **kwargs): """Get the "temperature flux" through boundary *btag*.""" raise NotImplementedError() - def inviscid_boundary_flux(self, discr, btag, eos, q, **kwargs): + def inviscid_boundary_flux(self, discr, btag, q, eos, **kwargs): """Get the inviscid part of the physical flux across the boundary *btag*.""" raise NotImplementedError() - def viscous_boundary_flux(self, discr, btag, eos, q, grad_q, grad_t, **kwargs): + def viscous_boundary_flux(self, discr, btag, q, grad_q, grad_t, eos, **kwargs): """Get the viscous part of the physical flux across the boundary *btag*.""" raise NotImplementedError() - def boundary_pair(self, discr, btag, eos, u, **kwargs): + def boundary_pair(self, discr, btag, u, eos, **kwargs): """Get the interior and exterior solution (*u*) on the boundary.""" raise NotImplementedError() @@ -132,7 +132,10 @@ class PrescribedInviscidBoundary(FluidBC): """ def __init__(self, inviscid_boundary_flux_func=None, boundary_pair_func=None, - inviscid_facial_flux_func=None, fluid_solution_func=None): + inviscid_facial_flux_func=None, fluid_solution_func=None, + fluid_solution_flux_func=None, scalar_numerical_flux_func=None, + fluid_solution_gradient_func=None, + fluid_solution_gradient_flux_func=None): """Initialize the PrescribedInviscidBoundary and methods.""" self._bnd_pair_func = boundary_pair_func self._inviscid_bnd_flux_func = inviscid_boundary_flux_func @@ -140,8 +143,25 @@ def __init__(self, inviscid_boundary_flux_func=None, boundary_pair_func=None, if not self._inviscid_facial_flux_func: self._inviscid_facial_flux_func = inviscid_facial_flux self._fluid_soln_func = fluid_solution_func + self._fluid_soln_flux_func = fluid_solution_flux_func + self._scalar_num_flux_func = scalar_numerical_flux_func + from mirgecom.flux import central_scalar_flux + if not self._scalar_num_flux_func: + self._scalar_num_flux_func = central_scalar_flux + self._fluid_soln_grad_func = fluid_solution_gradient_func + self._fluid_soln_grad_flux_func = fluid_solution_gradient_flux_func + from mirgecom.flux import central_vector_flux + if not self._fluid_soln_grad_flux_func: + self._fluid_soln_grad_flux_func = central_vector_flux + + def _boundary_quantity(self, discr, btag, quantity, **kwargs): + """Get a boundary quantity on local boundary, or projected to "all_faces".""" + if "local" in kwargs: + if kwargs["local"]: + return quantity + return discr.project(btag, "all_faces", quantity) - def boundary_pair(self, discr, q, btag, **kwargs): + def boundary_pair(self, discr, btag, q, **kwargs): """Get the interior and exterior solution on the boundary.""" if self._bnd_pair_func: return self._bnd_pair_func(discr, q=q, btag=btag, **kwargs) @@ -165,9 +185,53 @@ def inviscid_boundary_flux(self, discr, btag, q, eos, **kwargs): int_soln = discr.project("vol", btag, q) return self._inviscid_bnd_flux_func(nodes, normal=nhat, q=int_soln, eos=eos, **kwargs) - bnd_tpair = self.boundary_pair(discr, q, btag, eos=eos, **kwargs) + bnd_tpair = self.boundary_pair(discr, btag=btag, q=q, eos=eos, **kwargs) return self._inviscid_facial_flux_func(discr, eos=eos, q_tpair=bnd_tpair) + def q_boundary_flux(self, discr, btag, q, **kwargs): + """Get the flux through boundary *btag* for each scalar in *q*.""" + if isinstance(q, np.ndarray): + actx = q[0].array_context + else: + actx = q.array_context + boundary_discr = discr.discr_from_dd(btag) + nodes = thaw(actx, boundary_discr.nodes()) + nhat = thaw(actx, discr.normal(btag)) + if self._fluid_soln_flux_func: + q_minus = discr.project("vol", btag, q) + flux_weak = self._fluid_soln_flux_func(nodes, q=q_minus, nhat=nhat, + **kwargs) + else: + bnd_pair = self.boundary_pair(discr, btag=btag, q=q, **kwargs) + flux_weak = self._scalar_num_flux_func(bnd_pair, normal=nhat) + + return self._boundary_quantity(discr, btag=btag, quantity=flux_weak, + **kwargs) + + def s_boundary_flux(self, discr, btag, grad_q, **kwargs): + r"""Get $\nabla\mathbf{Q}$ flux across the boundary faces.""" + grad_shape = grad_q.shape + if len(grad_shape) > 1: + actx = grad_q[0][0].array_context + else: + actx = grad_q[0].array_context + + boundary_discr = discr.discr_from_dd(btag) + nodes = thaw(actx, boundary_discr.nodes()) + nhat = thaw(actx, discr.normal(btag)) + grad_q_minus = discr.project("vol", btag, grad_q) + if self._fluid_soln_grad_func: + grad_q_plus = self._fluid_soln_grad_func(nodes, nhat=nhat, + grad_q=grad_q_minus, **kwargs) + else: + grad_q_plus = grad_q_minus + bnd_grad_pair = TracePair(btag, interior=grad_q_minus, exterior=grad_q_plus) + + return self._boundary_quantity( + discr, btag, self._fluid_soln_grad_flux_func(bnd_grad_pair, nhat), + **kwargs + ) + class PrescribedBoundary(PrescribedInviscidBoundary): """Boundary condition prescribes boundary soln with user-specified function. @@ -212,10 +276,6 @@ def exterior_q(self, discr, q, btag, **kwargs): dir_soln = discr.project("vol", btag, q) return dir_soln - def exterior_grad_q(self, discr, grad_q, btag, **kwargs): - """Get the grad_q on the exterior of the boundary.""" - return discr.project("vol", btag, grad_q) - class AdiabaticSlipBoundary(PrescribedInviscidBoundary): r"""Boundary condition implementing inviscid slip boundary. @@ -238,7 +298,9 @@ class AdiabaticSlipBoundary(PrescribedInviscidBoundary): def __init__(self): """Initialize AdiabaticSlipBoundary.""" PrescribedInviscidBoundary.__init__( - self, boundary_pair_func=self.adiabatic_slip_pair) + self, boundary_pair_func=self.adiabatic_slip_pair, + fluid_solution_gradient_func=self.exterior_grad_q + ) def adiabatic_slip_pair(self, discr, q, btag, **kwargs): """Get the interior and exterior solution on the boundary. @@ -279,6 +341,24 @@ def adiabatic_slip_pair(self, discr, q, btag, **kwargs): return TracePair(btag, interior=int_soln, exterior=bndry_soln) + def exterior_grad_q(self, nodes, nhat, grad_q, **kwargs): + """Get the exterior grad(Q) on the boundary.""" + # Grab some boundary-relevant data + num_equations, dim = grad_q.shape + + # Get the interior soln + gradq_comp = split_conserved(dim, grad_q) + + # Subtract 2*wall-normal component of q + # to enforce q=0 on the wall + s_mom_normcomp = np.outer(nhat, np.dot(gradq_comp.momentum, nhat)) + s_mom_flux = gradq_comp.momentum - 2*s_mom_normcomp + + # flip components to set a neumann condition + return join_conserved(dim, mass=-gradq_comp.mass, energy=-gradq_comp.energy, + momentum=-s_mom_flux, + species_mass=-gradq_comp.species_mass) + class IsothermalNoSlipBoundary(FluidBC): r"""Isothermal no-slip viscous wall boundary. diff --git a/mirgecom/euler.py b/mirgecom/euler.py index 2123843bc..0bef5679f 100644 --- a/mirgecom/euler.py +++ b/mirgecom/euler.py @@ -108,7 +108,7 @@ def euler_operator(discr, eos, boundaries, q, t=0.0): inviscid_facial_flux(discr, eos=eos, q_tpair=interior_trace_pair(discr, q)) + sum(inviscid_facial_flux(discr, eos=eos, q_tpair=part_tpair) for part_tpair in cross_rank_trace_pairs(discr, q)) - + sum(boundaries[btag].inviscid_boundary_flux(discr, btag, eos=eos, q=q) + + sum(boundaries[btag].inviscid_boundary_flux(discr, btag=btag, q=q, eos=eos) for btag in boundaries) ) diff --git a/mirgecom/flux.py b/mirgecom/flux.py index cbe911cf6..99695e59d 100644 --- a/mirgecom/flux.py +++ b/mirgecom/flux.py @@ -72,6 +72,37 @@ def central_scalar_flux(trace_pair, normal): return trace_pair.avg*normal +def central_vector_flux(trace_pair, normal): + r"""Compute a central vector flux. + + The central vector flux, $h$, is calculated as: + + .. math:: + + h(\mathbf{v}^-, \mathbf{v}^+; \mathbf{n}) = \frac{1}{2} + \left(\mathbf{v}^{+}+\mathbf{v}^{-}\right) \cdot \hat{n} + + where $\mathbf{v}^-, \matbhf{v}^+$, are the vectors on the interior and exterior + of the face across which the central flux is to be calculated, and $\hat{n}$ is + the unit normal to the face. + + Parameters + ---------- + trace_pair: `grudge.sym.TracePair` + Trace pair for the face upon which flux calculation is to be performed + normal: numpy.ndarray + object array of :class:`meshmode.dof_array.DOFArray` with outward-pointing + normals + + Returns + ------- + numpy.ndarray + object array of `meshmode.dof_array.DOFArray` with the central scalar flux + for each scalar component. + """ + return trace_pair.avg@normal + + def lfr_flux(q_tpair, f_tpair, normal, lam): r"""Compute Lax-Friedrichs/Rusanov flux after [Hesthaven_2008]_, Section 6.6. From 59df6df08c6d782443f685a1761ee933b4199e77 Mon Sep 17 00:00:00 2001 From: Matt Smith Date: Mon, 10 May 2021 19:33:13 -0500 Subject: [PATCH 080/106] AV misc fixes (#23) * remove call to deprecated create_parallel_grid * remove use of deprecated n parameter * add boundary_kwargs to av_operator * raise exception instead of asserting --- examples/doublemach-mpi.py | 7 ++++--- mirgecom/artificial_viscosity.py | 30 +++++++++++++++--------------- test/test_av.py | 11 ++++------- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index e58ea34c6..18e6cee49 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -44,7 +44,7 @@ from mirgecom.simutil import ( inviscid_sim_timestep, sim_checkpoint, - create_parallel_grid, + generate_and_distribute_mesh, ExactSolutionMismatch, ) from mirgecom.io import make_init_message @@ -151,7 +151,7 @@ def main(ctx_factory=cl.create_some_context): gen_grid = partial(get_doublemach_mesh) - local_mesh, global_nelements = create_parallel_grid(comm, gen_grid) + local_mesh, global_nelements = generate_and_distribute_mesh(comm, gen_grid) local_nelements = local_mesh.nelements @@ -198,7 +198,8 @@ def my_rhs(t, state): return inviscid_operator( discr, q=state, t=t, boundaries=boundaries, eos=eos ) + av_operator( - discr, t=t, q=state, boundaries=boundaries, alpha=alpha, eos=eos, + discr, q=state, boundaries=boundaries, + boundary_kwargs={"t": t, "eos": eos}, alpha=alpha, s0=s0, kappa=kappa ) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 273d7fb74..cbc5f0bce 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -152,7 +152,7 @@ def _facial_flux_r(discr, r_tpair): return discr.project(r_tpair.dd, "all_faces", flux_out) -def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): +def av_operator(discr, boundaries, q, alpha, boundary_kwargs=None, **kwargs): r"""Compute the artificial viscosity right-hand-side. Computes the the right-hand-side term for artificial viscosity. @@ -178,17 +178,13 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): Dictionary of boundary functions, one for each valid boundary tag - t: float - - Time - alpha: float - The maximum artificial viscosity coefficient to be applied + The maximum artificial viscosity coefficient to be applied - eos: :class:`~mirgecom.eos.GasEOS` + boundary_kwargs: :class:`dict` - Only used as a pass through to the boundary conditions. + dictionary of extra arguments to pass through to the boundary conditions Returns ------- @@ -196,6 +192,9 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): The artificial viscosity operator applied to *q*. """ + if boundary_kwargs is None: + boundary_kwargs = dict() + # Get smoothness indicator based on first component indicator_field = q[0] if isinstance(q, np.ndarray) else q indicator = smoothness_indicator(discr, indicator_field, **kwargs) @@ -217,8 +216,8 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): q_tpair = TracePair( btag, interior=discr.project("vol", btag, q), - exterior=boundaries[btag].exterior_q(discr, btag=btag, t=t, - q=q, eos=eos)) + exterior=boundaries[btag].exterior_q(discr, btag=btag, q=q, + **boundary_kwargs)) q_flux_db = q_flux_db + _facial_flux_q(discr, q_tpair=q_tpair) # Total Q flux across element boundaries q_bnd_flux = q_flux_int + q_flux_pb + q_flux_db @@ -241,8 +240,8 @@ def av_operator(discr, t, eos, boundaries, q, alpha, **kwargs): r_tpair = TracePair( btag, interior=discr.project("vol", btag, r), - exterior=boundaries[btag].exterior_grad_q(discr, btag=btag, t=t, - grad_q=r, eos=eos)) + exterior=boundaries[btag].exterior_grad_q(discr, btag=btag, grad_q=r, + **boundary_kwargs)) r_flux_db = r_flux_db + _facial_flux_r(discr, r_tpair=r_tpair) # Total grad(Q) flux element boundaries r_flux_bnd = r_flux_int + r_flux_pb + r_flux_db @@ -256,8 +255,8 @@ def artificial_viscosity(discr, t, eos, boundaries, q, alpha, **kwargs): from warnings import warn warn("Do not call artificial_viscosity; it is now called av_operator. This" "function will disappear in 2021", DeprecationWarning, stacklevel=2) - return av_operator(discr=discr, eos=eos, boundaries=boundaries, - q=q, alpha=alpha, t=t) + return av_operator(discr=discr, boundaries=boundaries, + boundary_kwargs={"t": t, "eos": eos}, q=q, alpha=alpha, **kwargs) def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): @@ -281,7 +280,8 @@ def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): The elementwise constant values between 0 and 1 which indicate the smoothness of a given element. """ - assert isinstance(u, DOFArray) + if not isinstance(u, DOFArray): + raise ValueError("u argument must be a DOFArray.") actx = u.array_context diff --git a/test/test_av.py b/test/test_av.py index 152d32a30..0390bc960 100644 --- a/test/test_av.py +++ b/test/test_av.py @@ -169,7 +169,7 @@ def test_artificial_viscosity(ctx_factory, dim, order): from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh( - a=(-1.0, )*dim, b=(1.0, )*dim, n=(nel_1d, ) * dim + a=(-1.0, )*dim, b=(1.0, )*dim, nelements_per_axis=(nel_1d, )*dim ) discr = EagerDGDiscretization(actx, mesh, order=order) @@ -180,21 +180,18 @@ def test_artificial_viscosity(ctx_factory, dim, order): # Uniform field return 0 rhs q = zeros + 1.0 - rhs = av_operator(discr, t=0, eos=None, boundaries=boundaries, - q=q, alpha=1.0, s0=-np.inf) + rhs = av_operator(discr, boundaries=boundaries, q=q, alpha=1.0, s0=-np.inf) err = discr.norm(rhs, np.inf) assert err < tolerance # Linear field return 0 rhs q = nodes[0] - rhs = av_operator(discr, t=0, eos=None, boundaries=boundaries, - q=q, alpha=1.0, s0=-np.inf) + rhs = av_operator(discr, boundaries=boundaries, q=q, alpha=1.0, s0=-np.inf) err = discr.norm(rhs, np.inf) assert err < tolerance # Quadratic field return constant 2 q = np.dot(nodes, nodes) - rhs = av_operator(discr, t=0, eos=None, boundaries=boundaries, - q=q, alpha=1.0, s0=-np.inf) + rhs = av_operator(discr, boundaries=boundaries, q=q, alpha=1.0, s0=-np.inf) err = discr.norm(2.*dim-rhs, np.inf) assert err < tolerance From c0578f26c0a956da648bc3c298b563b511dfef2a Mon Sep 17 00:00:00 2001 From: Wyatt Hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 10 May 2021 17:49:55 -0700 Subject: [PATCH 081/106] Rename modes_active_flag --- mirgecom/artificial_viscosity.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index cbc5f0bce..cb677d1f2 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -296,11 +296,11 @@ def indicator_prg(): "{[kdof]: 0 <= kdof < ndiscr_nodes_in}" ], """ - result[iel,idof] = sum(kdof, vec[iel, kdof] \ - * vec[iel, kdof] \ - * modes[kdof]) / \ - sum(jdof, vec[iel, jdof] \ - * vec[iel, jdof] \ + result[iel,idof] = sum(kdof, vec[iel, kdof] \ + * vec[iel, kdof] \ + * modes_active_flag[kdof]) / \ + sum(jdof, vec[iel, jdof] \ + * vec[iel, jdof] \ + 1.0e-12 / ndiscr_nodes_in) """, name="smooth_comp", @@ -327,7 +327,7 @@ def highest_mode(grp): actx.call_loopy( indicator_prg(), vec=uhat[grp.index], - modes=highest_mode(grp))["result"] + modes_active_flag=highest_mode(grp))["result"] for grp in discr.discr_from_dd("vol").groups ) ) From 893fd224a5c8313ec8e1f4434bee2261e5c8090d Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Tue, 11 May 2021 08:55:09 -0500 Subject: [PATCH 082/106] Account for slight interface change in tests. --- test/test_bc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_bc.py b/test/test_bc.py index 13321cf7b..fa761fc7a 100644 --- a/test/test_bc.py +++ b/test/test_bc.py @@ -91,8 +91,8 @@ def test_slipwall_identity(actx_factory, dim): from functools import partial bnd_norm = partial(discr.norm, p=np.inf, dd=BTAG_ALL) - bnd_pair = wall.boundary_pair(discr, uniform_state, t=0.0, - btag=BTAG_ALL, eos=eos) + bnd_pair = wall.boundary_pair(discr, btag=BTAG_ALL, q=uniform_state, + eos=eos, t=0.0) bnd_cv_int = split_conserved(dim, bnd_pair.int) bnd_cv_ext = split_conserved(dim, bnd_pair.ext) @@ -156,8 +156,8 @@ def test_slipwall_flux(actx_factory, dim, order): from mirgecom.initializers import Uniform initializer = Uniform(dim=dim, velocity=vel) uniform_state = initializer(nodes) - bnd_pair = wall.boundary_pair(discr, uniform_state, t=0.0, - btag=BTAG_ALL, eos=eos) + bnd_pair = wall.boundary_pair(discr, btag=BTAG_ALL, q=uniform_state, + eos=eos, t=0.0) # Check the total velocity component normal # to each surface. It should be zero. The From 8fc775fedc5bb56f9666bc6e0807085a1909d1f7 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Tue, 11 May 2021 09:55:27 -0500 Subject: [PATCH 083/106] Update doublemach to use Navier-Stokes, update inviscid boundaries st they can be used in NS --- examples/autoignition-mpi.py | 2 +- examples/doublemach-mpi.py | 14 +++++++-- examples/nsmix-mpi.py | 2 +- mirgecom/boundary.py | 55 +++++++++++++++++++++++++++++++++++- mirgecom/initializers.py | 46 ++++++++++++++++-------------- mirgecom/navierstokes.py | 17 ++++++----- mirgecom/viscous.py | 4 +-- test/test_init.py | 4 +-- 8 files changed, 106 insertions(+), 38 deletions(-) diff --git a/examples/autoignition-mpi.py b/examples/autoignition-mpi.py index 078ebec9c..cb5c99e4b 100644 --- a/examples/autoignition-mpi.py +++ b/examples/autoignition-mpi.py @@ -175,7 +175,7 @@ def main(ctx_factory=cl.create_some_context): my_boundary = AdiabaticSlipBoundary() boundaries = {BTAG_ALL: my_boundary} - current_state = initializer(eos=eos, x_vec=nodes, t=0) + current_state = initializer(eos=eos, x_vec=nodes, time=0) # Inspection at physics debugging time if debug: diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index e58ea34c6..a1f18cf7c 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -23,6 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ + import logging import pyopencl as cl import pyopencl.tools as cl_tools @@ -36,7 +37,8 @@ from grudge.shortcuts import make_visualizer -from mirgecom.euler import inviscid_operator, split_conserved +from mirgecom.navierstokes import ns_operator +from mirgecom.fluid import split_conserved from mirgecom.artificial_viscosity import ( av_operator, smoothness_indicator @@ -55,6 +57,7 @@ from mirgecom.boundary import AdiabaticSlipBoundary, PrescribedBoundary from mirgecom.initializers import DoubleMachReflection from mirgecom.eos import IdealSingleGas +from mirgecom.transport import SimpleTransport logger = logging.getLogger(__name__) @@ -122,7 +125,12 @@ def main(ctx_factory=cl.create_some_context): current_cfl = 0.1 current_dt = 1.0e-4 current_t = 0 - eos = IdealSingleGas() + # {{{ Initialize simple transport model + kappa = 1e-5 + sigma = 1e-5 + transport_model = SimpleTransport(viscosity=sigma, thermal_conductivity=kappa) + # }}} + eos = IdealSingleGas(transport_model=transport_model) initializer = DoubleMachReflection() casename = "doubleMach" @@ -195,7 +203,7 @@ def main(ctx_factory=cl.create_some_context): ) def my_rhs(t, state): - return inviscid_operator( + return ns_operator( discr, q=state, t=t, boundaries=boundaries, eos=eos ) + av_operator( discr, t=t, q=state, boundaries=boundaries, alpha=alpha, eos=eos, diff --git a/examples/nsmix-mpi.py b/examples/nsmix-mpi.py index 2ff7b888a..7797bceaa 100644 --- a/examples/nsmix-mpi.py +++ b/examples/nsmix-mpi.py @@ -193,7 +193,7 @@ def main(ctx_factory=cl.create_some_context): # my_boundary = AdiabaticSlipBoundary() my_boundary = IsothermalNoSlipBoundary(wall_temperature=can_t) visc_bnds = {BTAG_ALL: my_boundary} - current_state = initializer(eos=eos, x_vec=nodes, t=0) + current_state = initializer(eos=eos, x_vec=nodes, time=0) # Inspection at physics debugging time if debug: diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index bd681a3a9..36ae7e914 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -135,7 +135,8 @@ def __init__(self, inviscid_boundary_flux_func=None, boundary_pair_func=None, inviscid_facial_flux_func=None, fluid_solution_func=None, fluid_solution_flux_func=None, scalar_numerical_flux_func=None, fluid_solution_gradient_func=None, - fluid_solution_gradient_flux_func=None): + fluid_solution_gradient_flux_func=None, + fluid_temperature_func=None): """Initialize the PrescribedInviscidBoundary and methods.""" self._bnd_pair_func = boundary_pair_func self._inviscid_bnd_flux_func = inviscid_boundary_flux_func @@ -153,6 +154,7 @@ def __init__(self, inviscid_boundary_flux_func=None, boundary_pair_func=None, from mirgecom.flux import central_vector_flux if not self._fluid_soln_grad_flux_func: self._fluid_soln_grad_flux_func = central_vector_flux + self._fluid_temperature_func = fluid_temperature_func def _boundary_quantity(self, discr, btag, quantity, **kwargs): """Get a boundary quantity on local boundary, or projected to "all_faces".""" @@ -232,6 +234,57 @@ def s_boundary_flux(self, discr, btag, grad_q, **kwargs): **kwargs ) + def t_boundary_flux(self, discr, btag, q, eos, **kwargs): + """Get the "temperature flux" through boundary *btag*.""" + q_minus = discr.project("vol", btag, q) + cv_minus = split_conserved(discr.dim, q_minus) + t_minus = eos.temperature(cv_minus) + if self._fluid_temperature_func: + actx = q[0].array_context + boundary_discr = discr.discr_from_dd(btag) + nodes = thaw(actx, boundary_discr.nodes()) + t_plus = self._fluid_temperature_func(nodes, q=q_minus, + temperature=t_minus, eos=eos, + **kwargs) + else: + t_plus = -t_minus + # t_plus = 0*t_minus + self._wall_temp + actx = cv_minus.mass.array_context + nhat = thaw(actx, discr.normal(btag)) + bnd_tpair = TracePair(btag, interior=t_minus, exterior=t_plus) + + return self._boundary_quantity(discr, btag, + self._scalar_num_flux_func(bnd_tpair, nhat), + **kwargs) + + def viscous_boundary_flux(self, discr, btag, eos, q, grad_q, grad_t, **kwargs): + """Get the viscous part of the physical flux across the boundary *btag*.""" + q_tpair = self.boundary_pair(discr, btag=btag, q=q, eos=eos, **kwargs) + cv_minus = split_conserved(discr.dim, q_tpair.int) + + grad_q_minus = discr.project("vol", btag, grad_q) + grad_q_tpair = TracePair(btag, interior=grad_q_minus, exterior=grad_q_minus) + + t_minus = eos.temperature(cv_minus) + if self._fluid_temperature_func: + actx = q[0].array_context + boundary_discr = discr.discr_from_dd(btag) + nodes = thaw(actx, boundary_discr.nodes()) + t_plus = self._fluid_temperature_func(nodes, q=q_tpair.exterior, + temperature=t_minus, eos=eos, + **kwargs) + else: + t_plus = -t_minus + + t_tpair = TracePair(btag, interior=t_minus, exterior=t_plus) + + grad_t_minus = discr.project("vol", btag, grad_t) + grad_t_tpair = TracePair(btag, interior=grad_t_minus, exterior=grad_t_minus) + + from mirgecom.viscous import viscous_facial_flux + return viscous_facial_flux(discr, eos, q_tpair, grad_q_tpair, + t_tpair, grad_t_tpair) + class PrescribedBoundary(PrescribedInviscidBoundary): """Boundary condition prescribes boundary soln with user-specified function. diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 35a5135bb..20c72a979 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -131,7 +131,7 @@ def __init__( self._center = np.array(center) self._velocity = np.array(velocity) - def __call__(self, x_vec, *, t=0, eos=None, **kwargs): + def __call__(self, x_vec, *, time=0, eos=None, **kwargs): """ Create the isentropic vortex solution at time *t* at locations *x_vec*. @@ -141,13 +141,14 @@ def __call__(self, x_vec, *, t=0, eos=None, **kwargs): Parameters ---------- - t: float + time: float Current time at which the solution is desired. x_vec: numpy.ndarray Nodal coordinates eos: mirgecom.eos.IdealSingleGas Equation of state class to supply method for gas *gamma*. """ + t = time if eos is None: eos = IdealSingleGas() vortex_loc = self._center + t * self._velocity @@ -226,13 +227,13 @@ def __init__( if self._xdir >= self._dim: self._xdir = self._dim - 1 - def __call__(self, x_vec, *, t=0, eos=None, **kwargs): + def __call__(self, x_vec, *, eos=None, time=0, **kwargs): """ Create the 1D Sod's shock solution at locations *x_vec*. Parameters ---------- - t: float + time: float Current time at which the solution is desired (unused) x_vec: numpy.ndarray Nodal coordinates @@ -319,7 +320,7 @@ def __init__( self._shock_location = shock_location self._shock_speed = shock_speed - def __call__(self, x_vec, *, t=0, eos=None, **kwargs): + def __call__(self, x_vec, *, eos=None, time=0, **kwargs): r""" Create double mach reflection solution at locations *x_vec*. @@ -331,13 +332,14 @@ def __call__(self, x_vec, *, t=0, eos=None, **kwargs): Parameters ---------- - t: float + time: float Time at which to compute the solution x_vec: numpy.ndarray Nodal coordinates eos: :class:`mirgecom.eos.GasEOS` Equation of state class to be used in construction of soln (if needed) """ + t = time # Fail if numdim is other than 2 if(len(x_vec)) != 2: raise ValueError("Case only defined for 2 dimensions") @@ -449,7 +451,7 @@ def __init__( self._rho0 = rho0 self._rhoamp = rhoamp - def __call__(self, x_vec, *, t=0, eos=None, **kwargs): + def __call__(self, x_vec, *, eos=None, time=0, **kwargs): """ Create the lump-of-mass solution at time *t* and locations *x_vec*. @@ -458,13 +460,14 @@ def __call__(self, x_vec, *, t=0, eos=None, **kwargs): Parameters ---------- - t: float + time: float Current time at which the solution is desired x_vec: numpy.ndarray Nodal coordinates eos: :class:`mirgecom.eos.IdealSingleGas` Equation of state class with method to supply gas *gamma*. """ + t = time if eos is None: eos = IdealSingleGas() if x_vec.shape != (self._dim,): @@ -489,7 +492,7 @@ def __call__(self, x_vec, *, t=0, eos=None, **kwargs): return join_conserved(dim=self._dim, mass=mass, energy=energy, momentum=mom) - def exact_rhs(self, discr, q, t=0.0): + def exact_rhs(self, discr, q, time=0.0): """ Create the RHS for the lump-of-mass solution at time *t*, locations *x_vec*. @@ -501,9 +504,10 @@ def exact_rhs(self, discr, q, t=0.0): q State array which expects at least the canonical conserved quantities (mass, energy, momentum) for the fluid at each point. - t: float + time: float Time at which RHS is desired """ + t = time actx = q[0].array_context nodes = thaw(actx, discr.nodes()) lump_loc = self._center + t * self._velocity @@ -621,7 +625,7 @@ def __init__( self._spec_centers = spec_centers self._spec_amplitudes = spec_amplitudes - def __call__(self, x_vec, *, t=0, eos=None, **kwargs): + def __call__(self, x_vec, *, eos=None, time=0, **kwargs): """ Create a multi-component lump solution at time *t* and locations *x_vec*. @@ -631,13 +635,14 @@ def __call__(self, x_vec, *, t=0, eos=None, **kwargs): Parameters ---------- - t: float + time: float Current time at which the solution is desired x_vec: numpy.ndarray Nodal coordinates eos: :class:`mirgecom.eos.IdealSingleGas` Equation of state class with method to supply gas *gamma*. """ + t = time if eos is None: eos = IdealSingleGas() if x_vec.shape != (self._dim,): @@ -666,7 +671,7 @@ def __call__(self, x_vec, *, t=0, eos=None, **kwargs): return join_conserved(dim=self._dim, mass=mass, energy=energy, momentum=mom, species_mass=species_mass) - def exact_rhs(self, discr, q, t=0.0): + def exact_rhs(self, discr, q, time=0.0): """ Create a RHS for multi-component lump soln at time *t*, locations *x_vec*. @@ -678,9 +683,10 @@ def exact_rhs(self, discr, q, t=0.0): q State array which expects at least the canonical conserved quantities (mass, energy, momentum) for the fluid at each point. - t: float + time: float Time at which RHS is desired """ + t = time actx = q[0].array_context nodes = thaw(actx, discr.nodes()) loc_update = t * self._velocity @@ -760,8 +766,6 @@ def __call__(self, x_vec, q, eos=None, **kwargs): Parameters ---------- - t: float - Current time at which the solution is desired (unused) x_vec: numpy.ndarray Nodal coordinates eos: :class:`mirgecom.eos.GasEOS` @@ -839,13 +843,13 @@ def __init__( self._e = e self._dim = dim - def __call__(self, x_vec, *, t=0, eos=None, **kwargs): + def __call__(self, x_vec, *, eos=None, time=0, **kwargs): """ Create a uniform flow solution at locations *x_vec*. Parameters ---------- - t: float + time: float Current time at which the solution is desired (unused) x_vec: numpy.ndarray Nodal coordinates @@ -934,7 +938,7 @@ def __init__( self._temperature = temperature self._massfracs = massfractions - def __call__(self, x_vec, eos, *, t=0.0, **kwargs): + def __call__(self, x_vec, eos, *, time=0.0, **kwargs): """ Create the mixture state at locations *x_vec* (t is ignored). @@ -947,8 +951,8 @@ def __call__(self, x_vec, eos, *, t=0.0, **kwargs): these functions: `eos.get_density` `eos.get_internal_energy` - t: float - Time is ignored by this solution intitializer + time: float + Time is ignored by this solution intitializer (unused) """ if x_vec.shape != (self._dim,): raise ValueError(f"Position vector has unexpected dimensionality," diff --git a/mirgecom/navierstokes.py b/mirgecom/navierstokes.py index 3fa80f2b5..4a3969f88 100644 --- a/mirgecom/navierstokes.py +++ b/mirgecom/navierstokes.py @@ -131,7 +131,8 @@ def scalar_flux_interior(int_tpair): return discr.project(int_tpair.dd, "all_faces", flux_weak) def get_q_flux_bnd(btag): - return boundaries[btag].q_boundary_flux(discr, btag, eos, q, time=t) + return boundaries[btag].q_boundary_flux(discr, btag=btag, q=q, eos=eos, + time=t) q_int_tpair = interior_trace_pair(discr, q) q_part_pairs = cross_rank_trace_pairs(discr, q) @@ -144,7 +145,9 @@ def get_q_flux_bnd(btag): # Temperature gradient for conductive heat flux: [Ihme_2014]_ eqn (3b) # - now computed, *not* communicated def get_t_flux_bnd(btag): - return boundaries[btag].t_boundary_flux(discr, btag, eos, q, time=t) + return boundaries[btag].t_boundary_flux(discr, btag=btag, q=q, eos=eos, + time=t) + gas_t = eos.temperature(cv) t_int_tpair = TracePair("int_faces", interior=eos.temperature( @@ -162,12 +165,12 @@ def get_t_flux_bnd(btag): # inviscid parts def finv_interior_face(q_tpair): - return inviscid_facial_flux(discr, eos, q_tpair) + return inviscid_facial_flux(discr, eos=eos, q_tpair=q_tpair) # inviscid part of bcs applied here def finv_domain_boundary(btag): - return boundaries[btag].inviscid_boundary_flux(discr, btag, eos=eos, q=q, - time=t) + return boundaries[btag].inviscid_boundary_flux(discr, btag=btag, eos=eos, + q=q, time=t) # viscous parts s_int_pair = interior_trace_pair(discr, grad_q) @@ -200,8 +203,8 @@ def visc_bnd_flux(btag): # NS RHS return dg_div_low( discr, ( # volume part - viscous_flux(discr, eos, q=q, grad_q=grad_q, t=gas_t, grad_t=grad_t) - - inviscid_flux(discr, eos, q)), + viscous_flux(discr, eos=eos, q=q, grad_q=grad_q, t=gas_t, grad_t=grad_t) + - inviscid_flux(discr, eos=eos, q=q)), elbnd_flux( # viscous boundary discr, fvisc_interior_face, visc_bnd_flux, (q_int_tpair, s_int_pair, t_int_tpair, delt_int_pair), diff --git a/mirgecom/viscous.py b/mirgecom/viscous.py index 5e8f26217..2e8f04216 100644 --- a/mirgecom/viscous.py +++ b/mirgecom/viscous.py @@ -81,10 +81,10 @@ def diffusive_flux(discr, eos, q, grad_q): fractions ${Y}_{\alpha}$. """ cv = split_conserved(discr.dim, q) - grad_cv = split_conserved(discr.dim, grad_q) nspecies = len(cv.species_mass) - transport = eos.transport_model() + grad_cv = split_conserved(discr.dim, grad_q) + transport = eos.transport_model() grad_y = species_mass_fraction_gradient(discr, cv, grad_cv) d = transport.species_diffusivity(eos, cv) diff --git a/test/test_init.py b/test/test_init.py index 36c718348..e26d42cae 100644 --- a/test/test_init.py +++ b/test/test_init.py @@ -218,7 +218,7 @@ def test_shock_init(ctx_factory): nodes = thaw(actx, discr.nodes()) initr = SodShock1D() - initsoln = initr(t=0.0, x_vec=nodes) + initsoln = initr(time=0.0, x_vec=nodes) print("Sod Soln:", initsoln) xpl = 1.0 xpr = 0.1 @@ -259,7 +259,7 @@ def test_uniform(ctx_factory, dim): from mirgecom.initializers import Uniform initr = Uniform(dim=dim) - initsoln = initr(t=0.0, x_vec=nodes) + initsoln = initr(time=0.0, x_vec=nodes) tol = 1e-15 ssoln = split_conserved(dim, initsoln) From 194bd46e082bec83d6eb90bb5b36450dfd7027ce Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Tue, 11 May 2021 11:43:14 -0500 Subject: [PATCH 084/106] Tweak a bit for new interface and VTU overwrite for vortex example. --- examples/vortex-mpi.py | 2 +- test/test_euler.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/vortex-mpi.py b/examples/vortex-mpi.py index f13949fdb..9ab2a0839 100644 --- a/examples/vortex-mpi.py +++ b/examples/vortex-mpi.py @@ -178,7 +178,7 @@ def my_checkpoint(step, t, dt, state): exact_soln=initializer, vizname=casename, step=step, t=t, dt=dt, nstatus=nstatus, nviz=nviz, exittol=exittol, constant_cfl=constant_cfl, comm=comm, - vis_timer=vis_timer) + vis_timer=vis_timer, overwrite=True) try: (current_step, current_t, current_state) = \ diff --git a/test/test_euler.py b/test/test_euler.py index ac8572696..dffd7ba91 100644 --- a/test/test_euler.py +++ b/test/test_euler.py @@ -848,7 +848,7 @@ def rhs(t, q): logger.info("Writing final dump.") maxerr = max(write_soln(False)) else: - expected_result = initializer(nodes, t=t) + expected_result = initializer(nodes, time=t) maxerr = discr.norm(fields - expected_result, np.inf) logger.info(f"Max Error: {maxerr}") From 389c22e1352d36e6c6bb8351bee62d033ff5f843 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Tue, 11 May 2021 13:24:52 -0500 Subject: [PATCH 085/106] Fix some cosmetics only. --- examples/heat-source-mpi.py | 1 - mirgecom/viscous.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/heat-source-mpi.py b/examples/heat-source-mpi.py index b683498cd..196654a61 100644 --- a/examples/heat-source-mpi.py +++ b/examples/heat-source-mpi.py @@ -44,7 +44,6 @@ @mpi_entry_point def main(): - """Drive the example.""" cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue, diff --git a/mirgecom/viscous.py b/mirgecom/viscous.py index 2e8f04216..5e8f26217 100644 --- a/mirgecom/viscous.py +++ b/mirgecom/viscous.py @@ -81,10 +81,10 @@ def diffusive_flux(discr, eos, q, grad_q): fractions ${Y}_{\alpha}$. """ cv = split_conserved(discr.dim, q) - nspecies = len(cv.species_mass) - grad_cv = split_conserved(discr.dim, grad_q) + nspecies = len(cv.species_mass) transport = eos.transport_model() + grad_y = species_mass_fraction_gradient(discr, cv, grad_cv) d = transport.species_diffusivity(eos, cv) From 657aec60b10688daf520558778f625f35764befa Mon Sep 17 00:00:00 2001 From: w-hagen <26756513+w-hagen@users.noreply.github.com> Date: Mon, 17 May 2021 13:10:10 -0500 Subject: [PATCH 086/106] Fix passing of time variable to boundary (#342) --- examples/doublemach-mpi.py | 2 +- mirgecom/euler.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 771d98a15..901bbadd1 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -207,7 +207,7 @@ def my_rhs(t, state): discr, q=state, t=t, boundaries=boundaries, eos=eos ) + av_operator( discr, q=state, boundaries=boundaries, - boundary_kwargs={"t": t, "eos": eos}, alpha=alpha, + boundary_kwargs={"time": t, "eos": eos}, alpha=alpha, s0=s0, kappa=kappa ) diff --git a/mirgecom/euler.py b/mirgecom/euler.py index 0bef5679f..bab4daa16 100644 --- a/mirgecom/euler.py +++ b/mirgecom/euler.py @@ -108,7 +108,8 @@ def euler_operator(discr, eos, boundaries, q, t=0.0): inviscid_facial_flux(discr, eos=eos, q_tpair=interior_trace_pair(discr, q)) + sum(inviscid_facial_flux(discr, eos=eos, q_tpair=part_tpair) for part_tpair in cross_rank_trace_pairs(discr, q)) - + sum(boundaries[btag].inviscid_boundary_flux(discr, btag=btag, q=q, eos=eos) + + sum(boundaries[btag].inviscid_boundary_flux(discr, btag=btag, q=q, eos=eos, + time=t) for btag in boundaries) ) From 6fc2200c59399fb8a809055ecffd25191879b916 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Wed, 19 May 2021 11:20:50 -0500 Subject: [PATCH 087/106] Add AV interface routine to Moving Noslip. --- mirgecom/boundary.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index bd7ae4f04..d3579458d 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -419,6 +419,7 @@ class AdiabaticNoslipMovingBoundary(PrescribedInviscidBoundary): .. automethod:: adiabatic_noslip_pair .. automethod:: exterior_soln + .. automethod:: exterior_grad_q """ def __init__(self, wall_velocity=None, dim=2): @@ -460,6 +461,10 @@ def exterior_soln(self, discr, q, btag, **kwargs): return bndry_soln + def exterior_grad_q(self, nodes, nhat, grad_q, **kwargs): + """Get the exterior solution on the boundary.""" + return(-grad_q) + class IsothermalNoSlipBoundary(FluidBC): r"""Isothermal no-slip viscous wall boundary. From 9226ef48d673a65c77372f67962b3cceb9a31a65 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Sun, 23 May 2021 13:11:09 -0500 Subject: [PATCH 088/106] Merge down Wyatts BC catch #352 --- mirgecom/boundary.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 5d9b59508..8737e5a6e 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -353,7 +353,8 @@ class AdiabaticSlipBoundary(PrescribedInviscidBoundary): def __init__(self): """Initialize AdiabaticSlipBoundary.""" PrescribedInviscidBoundary.__init__( - self, boundary_pair_func=self.adiabatic_slip_pair + self, boundary_pair_func=self.adiabatic_slip_pair, + fluid_solution_gradient_func=self.exterior_grad_q ) def adiabatic_slip_pair(self, discr, q, btag, **kwargs): @@ -425,7 +426,8 @@ class AdiabaticNoslipMovingBoundary(PrescribedInviscidBoundary): def __init__(self, wall_velocity=None, dim=2): """Initialize boundary device.""" PrescribedInviscidBoundary.__init__( - self, boundary_pair_func=self.adiabatic_noslip_pair + self, boundary_pair_func=self.adiabatic_noslip_pair, + fluid_solution_gradient_func=self.exterior_grad_q ) # Check wall_velocity (assumes dim is correct) if wall_velocity is None: From f1dbc3e63d2b6387acfb0d5f2a465e22fcc776f6 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Wed, 2 Jun 2021 16:01:26 -0500 Subject: [PATCH 089/106] Check for CV type. --- mirgecom/artificial_viscosity.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 0bb1b7d10..3c13a4e6e 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -213,6 +213,8 @@ def av_operator(discr, boundaries, q, alpha, boundary_kwargs=None, **kwargs): for btag, bnd in boundaries.items()) if isinstance(q, np.ndarray): q_bnd_flux2 = np.stack(q_bnd_flux2) + if isinstance(q_bnd_flux2, ConservedVars): + q_bnd_flux2 = q_bnd_flux2.join() q_bnd_flux = q_bnd_flux + q_bnd_flux2 # Compute R From 1bb8357332d99431f52bd7a894dba8e7f0a98e16 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Mon, 7 Jun 2021 11:21:44 -0500 Subject: [PATCH 090/106] Fix "indento" that makes doublemach hang at the end! --- examples/doublemach-mpi.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 901bbadd1..356318622 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -250,12 +250,12 @@ def my_checkpoint(step, t, dt, state): # if current_t != checkpoint_t: if rank == 0: logger.info("Checkpointing final state ...") - my_checkpoint( - current_step, - t=current_t, - dt=(current_t - checkpoint_t), - state=current_state, - ) + my_checkpoint( + current_step, + t=current_t, + dt=(current_t - checkpoint_t), + state=current_state, + ) if current_t - t_final < 0: raise ValueError("Simulation exited abnormally") From ece824f53c85a26328673042b41f7427dd1c2b85 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Wed, 9 Jun 2021 06:03:55 -0500 Subject: [PATCH 091/106] Initial stab at using CV array container inside AV on NS. --- examples/doublemach-mpi.py | 15 +++++++------ mirgecom/artificial_viscosity.py | 10 ++++----- mirgecom/boundary.py | 27 +++++++++++++++++++++++ mirgecom/initializers.py | 2 +- test/test_av.py | 38 +++++++++++++++++++++++++------- 5 files changed, 70 insertions(+), 22 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 901bbadd1..7a9885b75 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -38,7 +38,6 @@ from mirgecom.navierstokes import ns_operator -from mirgecom.fluid import split_conserved from mirgecom.artificial_viscosity import ( av_operator, smoothness_indicator @@ -54,7 +53,10 @@ from mirgecom.integrators import rk4_step from mirgecom.steppers import advance_state -from mirgecom.boundary import AdiabaticSlipBoundary, PrescribedBoundary +from mirgecom.boundary import ( + AdiabaticNoslipMovingBoundary, + PrescribedBoundary +) from mirgecom.initializers import DoubleMachReflection from mirgecom.eos import IdealSingleGas from mirgecom.transport import SimpleTransport @@ -138,8 +140,8 @@ def main(ctx_factory=cl.create_some_context): DTAG_BOUNDARY("ic1"): PrescribedBoundary(initializer), DTAG_BOUNDARY("ic2"): PrescribedBoundary(initializer), DTAG_BOUNDARY("ic3"): PrescribedBoundary(initializer), - DTAG_BOUNDARY("wall"): AdiabaticSlipBoundary(), - DTAG_BOUNDARY("out"): AdiabaticSlipBoundary(), + DTAG_BOUNDARY("wall"): AdiabaticNoslipMovingBoundary(), + DTAG_BOUNDARY("out"): AdiabaticNoslipMovingBoundary(), } constant_cfl = False nstatus = 10 @@ -212,14 +214,13 @@ def my_rhs(t, state): ) def my_checkpoint(step, t, dt, state): - cv = split_conserved(dim, state) - tagged_cells = smoothness_indicator(discr, cv.mass, s0=s0, kappa=kappa) + tagged_cells = smoothness_indicator(discr, state.mass, s0=s0, kappa=kappa) viz_fields = [("tagged cells", tagged_cells)] return sim_checkpoint( discr, visualizer, eos, - q=state, + cv=state, vizname=casename, step=step, t=t, diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 3c13a4e6e..3fa687766 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -209,12 +209,10 @@ def av_operator(discr, boundaries, q, alpha, boundary_kwargs=None, **kwargs): q_bnd_flux = (_facial_flux_q(discr, q_tpair=interior_trace_pair(discr, q)) + sum(_facial_flux_q(discr, q_tpair=pb_tpair) for pb_tpair in cross_rank_trace_pairs(discr, q))) - q_bnd_flux2 = sum(bnd.q_boundary_flux(discr, btag, q=q, **boundary_kwargs) + q_bnd_flux2 = sum(bnd.soln_gradient_flux(discr, btag, soln=q, **boundary_kwargs) for btag, bnd in boundaries.items()) - if isinstance(q, np.ndarray): - q_bnd_flux2 = np.stack(q_bnd_flux2) - if isinstance(q_bnd_flux2, ConservedVars): - q_bnd_flux2 = q_bnd_flux2.join() + # if isinstance(q, np.ndarray): + # q_bnd_flux2 = np.stack(q_bnd_flux2) q_bnd_flux = q_bnd_flux + q_bnd_flux2 # Compute R @@ -228,7 +226,7 @@ def av_operator(discr, boundaries, q, alpha, boundary_kwargs=None, **kwargs): r_bnd_flux = (_facial_flux_r(discr, r_tpair=interior_trace_pair(discr, r)) + sum(_facial_flux_r(discr, r_tpair=pb_tpair) for pb_tpair in cross_rank_trace_pairs(discr, r)) - + sum(bnd.s_boundary_flux(discr, btag, grad_q=r, **boundary_kwargs) + + sum(bnd.av_flux(discr, btag, diffusion=r, **boundary_kwargs) for btag, bnd in boundaries.items())) # Return the AV RHS term diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 912e05ae1..522bb8daa 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -129,6 +129,8 @@ class PrescribedInviscidBoundary(FluidBC): .. automethod:: __init__ .. automethod:: boundary_pair .. automethod:: inviscid_boundary_flux + .. automethod:: soln_gradient_flux + .. automethod:: av_flux """ def __init__(self, inviscid_boundary_flux_func=None, boundary_pair_func=None, @@ -207,6 +209,11 @@ def q_boundary_flux(self, discr, btag, cv, **kwargs): return self._boundary_quantity(discr, btag=btag, quantity=flux_weak, **kwargs) + def soln_gradient_flux(self, discr, btag, soln, **kwargs): + """Get the flux for solution gradient with AV API.""" + cv = make_conserved(discr.dim, q=soln) + return self.q_boundary_flux(discr, btag, cv, **kwargs).join() + def s_boundary_flux(self, discr, btag, grad_cv, **kwargs): r"""Get $\nabla\mathbf{Q}$ flux across the boundary faces.""" actx = grad_cv.array_context @@ -227,6 +234,11 @@ def s_boundary_flux(self, discr, btag, grad_cv, **kwargs): **kwargs ) + def av_flux(self, discr, btag, diffusion, **kwargs): + """Get the diffusive fluxes for the AV operator API.""" + diff_cv = make_conserved(discr.dim, q=diffusion) + return self.s_boundary_flux(discr, btag, diff_cv, **kwargs).join() + def t_boundary_flux(self, discr, btag, cv, eos, **kwargs): """Get the "temperature flux" through boundary *btag*.""" cv_minus = discr.project("vol", btag, cv) @@ -379,6 +391,21 @@ def adiabatic_slip_pair(self, discr, cv, btag, **kwargs): momentum=ext_mom, species_mass=int_cv.species_mass) return TracePair(btag, interior=int_cv, exterior=ext_cv) + def exterior_grad_q(self, nodes, nhat, grad_cv, **kwargs): + """Get the exterior grad(Q) on the boundary.""" + # Grab some boundary-relevant data + num_equations, dim = grad_cv.mass.shape + + # Subtract 2*wall-normal component of q + # to enforce q=0 on the wall + s_mom_normcomp = np.outer(nhat, np.dot(grad_cv.momentum, nhat)) + s_mom_flux = grad_cv.momentum - 2*s_mom_normcomp + + # flip components to set a neumann condition + return make_conserved(dim, mass=-grad_cv.mass, energy=-grad_cv.energy, + momentum=-s_mom_flux, + species_mass=-grad_cv.species_mass) + class AdiabaticNoslipMovingBoundary(PrescribedInviscidBoundary): r"""Boundary condition implementing a noslip moving boundary. diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index f3b317256..048958dcb 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -382,7 +382,7 @@ def __call__(self, x_vec, *, eos=None, time=0, **kwargs): mom = mass * vel energy = rhoe + .5*mass*np.dot(vel, vel) - return join_conserved(dim=2, mass=mass, energy=energy, momentum=mom) + return make_conserved(dim=2, mass=mass, energy=energy, momentum=mom) class Lump: diff --git a/test/test_av.py b/test/test_av.py index 0390bc960..626893753 100644 --- a/test/test_av.py +++ b/test/test_av.py @@ -36,7 +36,6 @@ av_operator, smoothness_indicator ) -from mirgecom.boundary import DummyBoundary from grudge.eager import EagerDGDiscretization from pyopencl.tools import ( # noqa pytest_generate_tests_for_pyopencl as pytest_generate_tests, @@ -176,22 +175,45 @@ def test_artificial_viscosity(ctx_factory, dim, order): nodes = thaw(actx, discr.nodes()) zeros = discr.zeros(actx) - boundaries = {BTAG_ALL: DummyBoundary()} + class TestBoundary: + def soln_gradient_flux(self, disc, btag, soln, **kwargs): + soln_int = disc.project("vol", btag, soln) + from grudge.trace_pair import TracePair + bnd_pair = TracePair(btag, + interior=soln_int, + exterior=soln_int) + nhat = thaw(actx, disc.normal(btag)) + from mirgecom.flux import central_scalar_flux + flux_weak = central_scalar_flux(bnd_pair, normal=nhat) + return disc.project(btag, "all_faces", flux_weak) + + def av_flux(self, disc, btag, diffusion, **kwargs): + nhat = thaw(actx, disc.normal(btag)) + grad_soln_minus = discr.project("vol", btag, diffusion) + grad_soln_plus = grad_soln_minus + from grudge.trace_pair import TracePair + bnd_grad_pair = TracePair(btag, interior=grad_soln_minus, + exterior=grad_soln_plus) + from mirgecom.flux import central_vector_flux + flux_weak = central_vector_flux(bnd_grad_pair, normal=nhat) + return disc.project(btag, "all_faces", flux_weak) + + boundaries = {BTAG_ALL: TestBoundary()} # Uniform field return 0 rhs - q = zeros + 1.0 - rhs = av_operator(discr, boundaries=boundaries, q=q, alpha=1.0, s0=-np.inf) + soln = zeros + 1.0 + rhs = av_operator(discr, boundaries=boundaries, q=soln, alpha=1.0, s0=-np.inf) err = discr.norm(rhs, np.inf) assert err < tolerance # Linear field return 0 rhs - q = nodes[0] - rhs = av_operator(discr, boundaries=boundaries, q=q, alpha=1.0, s0=-np.inf) + soln = nodes[0] + rhs = av_operator(discr, boundaries=boundaries, q=soln, alpha=1.0, s0=-np.inf) err = discr.norm(rhs, np.inf) assert err < tolerance # Quadratic field return constant 2 - q = np.dot(nodes, nodes) - rhs = av_operator(discr, boundaries=boundaries, q=q, alpha=1.0, s0=-np.inf) + soln = np.dot(nodes, nodes) + rhs = av_operator(discr, boundaries=boundaries, q=soln, alpha=1.0, s0=-np.inf) err = discr.norm(2.*dim-rhs, np.inf) assert err < tolerance From 8f41a32b9fcacc9f88e860a39993622bd6562a37 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Wed, 9 Jun 2021 06:32:03 -0500 Subject: [PATCH 092/106] Update ns api in doublemach example --- examples/doublemach-mpi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 7a9885b75..3fac69948 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -206,9 +206,9 @@ def main(ctx_factory=cl.create_some_context): def my_rhs(t, state): return ns_operator( - discr, q=state, t=t, boundaries=boundaries, eos=eos + discr, cv=state, t=t, boundaries=boundaries, eos=eos ) + av_operator( - discr, q=state, boundaries=boundaries, + discr, q=state.join(), boundaries=boundaries, boundary_kwargs={"time": t, "eos": eos}, alpha=alpha, s0=s0, kappa=kappa ) From 1c81b7dcd7ccf042f332c50c5451c76ecd5c8aae Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Wed, 9 Jun 2021 07:12:42 -0500 Subject: [PATCH 093/106] Use explicit named args in call to s_bnd_flux --- mirgecom/boundary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 522bb8daa..92a2d30b4 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -237,7 +237,7 @@ def s_boundary_flux(self, discr, btag, grad_cv, **kwargs): def av_flux(self, discr, btag, diffusion, **kwargs): """Get the diffusive fluxes for the AV operator API.""" diff_cv = make_conserved(discr.dim, q=diffusion) - return self.s_boundary_flux(discr, btag, diff_cv, **kwargs).join() + return self.s_boundary_flux(discr, btag, grad_cv=diff_cv, **kwargs).join() def t_boundary_flux(self, discr, btag, cv, eos, **kwargs): """Get the "temperature flux" through boundary *btag*.""" From 68d52e70097574463cb9e52f5410ba0a6fe2e0f5 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Wed, 9 Jun 2021 10:04:33 -0500 Subject: [PATCH 094/106] Wriggle into place with new data structures. --- examples/doublemach-mpi.py | 18 ++++++++++-------- mirgecom/boundary.py | 6 +++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 3fac69948..2316bb03a 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -37,6 +37,7 @@ from grudge.shortcuts import make_visualizer +from mirgecom.fluid import make_conserved from mirgecom.navierstokes import ns_operator from mirgecom.artificial_viscosity import ( av_operator, @@ -207,10 +208,10 @@ def main(ctx_factory=cl.create_some_context): def my_rhs(t, state): return ns_operator( discr, cv=state, t=t, boundaries=boundaries, eos=eos - ) + av_operator( + ) + make_conserved(dim, q=av_operator( discr, q=state.join(), boundaries=boundaries, boundary_kwargs={"time": t, "eos": eos}, alpha=alpha, - s0=s0, kappa=kappa + s0=s0, kappa=kappa) ) def my_checkpoint(step, t, dt, state): @@ -251,12 +252,13 @@ def my_checkpoint(step, t, dt, state): # if current_t != checkpoint_t: if rank == 0: logger.info("Checkpointing final state ...") - my_checkpoint( - current_step, - t=current_t, - dt=(current_t - checkpoint_t), - state=current_state, - ) + + my_checkpoint( + current_step, + t=current_t, + dt=(current_t - checkpoint_t), + state=current_state, + ) if current_t - t_final < 0: raise ValueError("Simulation exited abnormally") diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index 92a2d30b4..3603ce767 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -216,7 +216,7 @@ def soln_gradient_flux(self, discr, btag, soln, **kwargs): def s_boundary_flux(self, discr, btag, grad_cv, **kwargs): r"""Get $\nabla\mathbf{Q}$ flux across the boundary faces.""" - actx = grad_cv.array_context + actx = grad_cv.mass[0].array_context boundary_discr = discr.discr_from_dd(btag) nodes = thaw(actx, boundary_discr.nodes()) nhat = thaw(actx, discr.normal(btag)) @@ -450,9 +450,9 @@ def exterior_soln(self, discr, cv, btag, **kwargs): return make_conserved(dim=dim, mass=int_cv.mass, energy=int_cv.energy, momentum=ext_mom) - def exterior_grad_q(self, nodes, nhat, grad_q, **kwargs): + def exterior_grad_q(self, nodes, nhat, grad_cv, **kwargs): """Get the exterior solution on the boundary.""" - return(-grad_q) + return(-grad_cv) class IsothermalNoSlipBoundary(PrescribedInviscidBoundary): From bb607c715ca730e6994a2945e2a1499396d7fbe4 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Wed, 9 Jun 2021 10:29:42 -0500 Subject: [PATCH 095/106] Try to update everything for new API --- mirgecom/fluid.py | 3 +-- mirgecom/initializers.py | 12 +++--------- mirgecom/inviscid.py | 8 ++------ 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/mirgecom/fluid.py b/mirgecom/fluid.py index 537705a7f..86ddb5f79 100644 --- a/mirgecom/fluid.py +++ b/mirgecom/fluid.py @@ -426,7 +426,7 @@ def species_mass_fraction_gradient(discr, cv, grad_cv): return grad_y -def compute_wavespeed(dim, eos, cv: ConservedVars): +def compute_wavespeed(eos, cv: ConservedVars): r"""Return the wavespeed in the flow. The wavespeed is calculated as: @@ -438,6 +438,5 @@ def compute_wavespeed(dim, eos, cv: ConservedVars): where $\mathbf{v}$ is the flow velocity and c is the speed of sound in the fluid. """ actx = cv.array_context - v = cv.momentum / cv.mass return actx.np.sqrt(np.dot(v, v)) + eos.sound_speed(cv) diff --git a/mirgecom/initializers.py b/mirgecom/initializers.py index 048958dcb..b6220e2dc 100644 --- a/mirgecom/initializers.py +++ b/mirgecom/initializers.py @@ -227,14 +227,12 @@ def __init__( if self._xdir >= self._dim: self._xdir = self._dim - 1 - def __call__(self, x_vec, *, eos=None, time=0, **kwargs): + def __call__(self, x_vec, *, eos=None, **kwargs): """ Create the 1D Sod's shock solution at locations *x_vec*. Parameters ---------- - time: float - Current time at which the solution is desired (unused) x_vec: numpy.ndarray Nodal coordinates eos: :class:`mirgecom.eos.IdealSingleGas` @@ -843,14 +841,12 @@ def __init__( self._e = e self._dim = dim - def __call__(self, x_vec, *, eos=None, time=0, **kwargs): + def __call__(self, x_vec, *, eos=None, **kwargs): """ Create a uniform flow solution at locations *x_vec*. Parameters ---------- - time: float - Current time at which the solution is desired (unused) x_vec: numpy.ndarray Nodal coordinates eos: :class:`mirgecom.eos.IdealSingleGas` @@ -938,7 +934,7 @@ def __init__( self._temperature = temperature self._massfracs = massfractions - def __call__(self, x_vec, eos, *, time=0.0, **kwargs): + def __call__(self, x_vec, eos, **kwargs): """ Create the mixture state at locations *x_vec* (t is ignored). @@ -951,8 +947,6 @@ def __call__(self, x_vec, eos, *, time=0.0, **kwargs): these functions: `eos.get_density` `eos.get_internal_energy` - time: float - Time is ignored by this solution intitializer (unused) """ if x_vec.shape != (self._dim,): raise ValueError(f"Position vector has unexpected dimensionality," diff --git a/mirgecom/inviscid.py b/mirgecom/inviscid.py index 0e8773903..3bfa9c1c7 100644 --- a/mirgecom/inviscid.py +++ b/mirgecom/inviscid.py @@ -90,23 +90,19 @@ def inviscid_facial_flux(discr, eos, cv_tpair, local=False): "all_faces"; remaining instead on the boundary restriction. """ actx = cv_tpair.int.array_context - dim = discr.dim flux_tpair = TracePair(cv_tpair.dd, interior=inviscid_flux(discr, eos, cv_tpair.int), exterior=inviscid_flux(discr, eos, cv_tpair.ext)) lam = actx.np.maximum( - compute_wavespeed(dim, eos=eos, cv=cv_tpair.int), - compute_wavespeed(dim, eos=eos, cv=cv_tpair.ext) + compute_wavespeed(eos=eos, cv=cv_tpair.int), + compute_wavespeed(eos=eos, cv=cv_tpair.ext) ) normal = thaw(actx, discr.normal(cv_tpair.dd)) # todo: user-supplied flux routine - # flux_weak = make_conserved( - # dim, q=lfr_flux(cv_tpair, flux_tpair, normal=normal, lam=lam) - # ) flux_weak = lfr_flux(cv_tpair, flux_tpair, normal=normal, lam=lam) if local is False: From e7deb73c2636258c815dc5eff544668099ce95d9 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Fri, 25 Jun 2021 12:21:58 -0500 Subject: [PATCH 096/106] Merge with main AV development --- mirgecom/artificial_viscosity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 3fa687766..b80e34783 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -317,8 +317,8 @@ def highest_mode(grp): indicator = actx.np.log10(indicator + 1.0e-12) # Compute artificial viscosity percentage based on indicator and set parameters - yesnol = indicator > (s0 - kappa) - yesnou = indicator > (s0 + kappa) + yesnol = actx.np.greater(indicator, (s0 - kappa)) + yesnou = actx.np.greater(indicator, (s0 + kappa)) sin_indicator = actx.np.where( yesnol, 0.5 * (1.0 + actx.np.sin(np.pi * (indicator - s0) / (2.0 * kappa))), From 9f1423698aeda20f63d2527a50587e4c840b17b3 Mon Sep 17 00:00:00 2001 From: Mike Campbell Date: Tue, 29 Jun 2021 11:12:43 -0500 Subject: [PATCH 097/106] Attempt to fix pylint issue. --- mirgecom/artificial_viscosity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index b80e34783..553cdb7c7 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -271,7 +271,7 @@ def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): @memoize_in(actx, (smoothness_indicator, "smooth_comp_knl")) def indicator_prg(): """Compute the smoothness indicator for all elements.""" - from meshmode.array_context import make_loopy_program + from array_context import make_loopy_program return make_loopy_program([ "{[iel]: 0 <= iel < nelements}", "{[idof]: 0 <= idof < ndiscr_nodes_in}", From d8a07fbceac69e392afa75eb3847d9d0a0ca1922 Mon Sep 17 00:00:00 2001 From: Mike Campbell Date: Tue, 29 Jun 2021 11:14:24 -0500 Subject: [PATCH 098/106] Attempt to fix pylint issues. --- mirgecom/filter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/filter.py b/mirgecom/filter.py index 618350785..2737970b9 100644 --- a/mirgecom/filter.py +++ b/mirgecom/filter.py @@ -146,7 +146,7 @@ def apply_spectral_filter(actx, modal_field, discr, cutoff, DOFArray or object array of DOFArrays """ - from meshmode.array_context import FirstAxisIsElementsTag + from meshmode.transform_metadata import FirstAxisIsElementsTag return DOFArray( actx, tuple(actx.einsum("j,ej->ej", From f445248dc318c7ed7cbd1d30e25d80079f8de219 Mon Sep 17 00:00:00 2001 From: Mike Campbell Date: Tue, 29 Jun 2021 11:33:20 -0500 Subject: [PATCH 099/106] Fix the pylint issue with a proper import. --- mirgecom/artificial_viscosity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 553cdb7c7..33093b7d7 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -271,7 +271,7 @@ def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): @memoize_in(actx, (smoothness_indicator, "smooth_comp_knl")) def indicator_prg(): """Compute the smoothness indicator for all elements.""" - from array_context import make_loopy_program + from arraycontext import make_loopy_program return make_loopy_program([ "{[iel]: 0 <= iel < nelements}", "{[idof]: 0 <= idof < ndiscr_nodes_in}", From e07d9a7fc8cd81421a8d615fa6286f31a6d875d2 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni <15399010+kaushikcfd@users.noreply.github.com> Date: Sat, 10 Jul 2021 10:35:02 -0500 Subject: [PATCH 100/106] Tag iel, idof with Concurrent(Element|DOF)InameTag (#419) Co-authored-by: Michael Campbell --- mirgecom/artificial_viscosity.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mirgecom/artificial_viscosity.py b/mirgecom/artificial_viscosity.py index 33093b7d7..4f58a8c3c 100644 --- a/mirgecom/artificial_viscosity.py +++ b/mirgecom/artificial_viscosity.py @@ -272,7 +272,10 @@ def smoothness_indicator(discr, u, kappa=1.0, s0=-6.0): def indicator_prg(): """Compute the smoothness indicator for all elements.""" from arraycontext import make_loopy_program - return make_loopy_program([ + from meshmode.transform_metadata import (ConcurrentElementInameTag, + ConcurrentDOFInameTag) + import loopy as lp + t_unit = make_loopy_program([ "{[iel]: 0 <= iel < nelements}", "{[idof]: 0 <= idof < ndiscr_nodes_in}", "{[jdof]: 0 <= jdof < ndiscr_nodes_in}", @@ -288,6 +291,8 @@ def indicator_prg(): """, name="smooth_comp", ) + return lp.tag_inames(t_unit, {"iel": ConcurrentElementInameTag(), + "idof": ConcurrentDOFInameTag()}) @keyed_memoize_in(actx, (smoothness_indicator, "highest_mode"), From f4f49cb0c811b9c0dd3ecf6c8ec391e97a9b54af Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Sat, 10 Jul 2021 12:28:04 -0500 Subject: [PATCH 101/106] Modernize doublemach example. --- examples/doublemach-mpi.py | 302 +++++++++++++++++++++++++++---------- 1 file changed, 225 insertions(+), 77 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index f5566b982..42a22a714 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -25,6 +25,7 @@ """ import logging +import numpy as np import pyopencl as cl import pyopencl.tools as cl_tools from functools import partial @@ -43,12 +44,6 @@ av_operator, smoothness_indicator ) -from mirgecom.simutil import ( - inviscid_sim_timestep, - sim_checkpoint, - generate_and_distribute_mesh, - ExactSolutionMismatch, -) from mirgecom.io import make_init_message from mirgecom.mpi import mpi_entry_point @@ -62,9 +57,26 @@ from mirgecom.eos import IdealSingleGas from mirgecom.transport import SimpleTransport +from logpyle import set_dt +from mirgecom.euler import extract_vars_for_logging, units_for_logging +from mirgecom.profiling import PyOpenCLProfilingArrayContext +from mirgecom.logging_quantities import ( + initialize_logmgr, + logmgr_add_many_discretization_quantities, + logmgr_add_device_name, + logmgr_add_device_memory_usage, + set_sim_state +) + logger = logging.getLogger(__name__) +class MyRuntimeError(RuntimeError): + """Simple exception to kill the simulation.""" + + pass + + def get_doublemach_mesh(): """Generate or import a grid using `gmsh`. @@ -112,13 +124,33 @@ def get_doublemach_mesh(): @mpi_entry_point -def main(ctx_factory=cl.create_some_context): +def main(ctx_factory=cl.create_some_context, use_leap=False, + use_profiling=False, rst_step=None, rst_name=None, + casename="doubleMach", use_logmgr=True): """Drive the example.""" cl_ctx = ctx_factory() - queue = cl.CommandQueue(cl_ctx) - actx = PyOpenCLArrayContext( - queue, allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)) - ) + + if casename is None: + casename = "mirgecom" + + from mpi4py import MPI + comm = MPI.COMM_WORLD + rank = comm.Get_rank() + nparts = comm.Get_size() + + logmgr = initialize_logmgr(use_logmgr, + filename=f"{casename}.sqlite", mode="wu", mpi_comm=comm) + + if use_profiling: + queue = cl.CommandQueue(cl_ctx, + properties=cl.command_queue_properties.PROFILING_ENABLE) + actx = PyOpenCLProfilingArrayContext(queue, + allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)), + logmgr=logmgr) + else: + queue = cl.CommandQueue(cl_ctx) + actx = PyOpenCLArrayContext(queue, + allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue))) dim = 2 order = 3 @@ -135,7 +167,6 @@ def main(ctx_factory=cl.create_some_context): # }}} eos = IdealSingleGas(transport_model=transport_model) initializer = DoubleMachReflection() - casename = "doubleMach" boundaries = { DTAG_BOUNDARY("ic1"): PrescribedBoundary(initializer), @@ -147,33 +178,70 @@ def main(ctx_factory=cl.create_some_context): constant_cfl = False nstatus = 10 nviz = 100 - rank = 0 - checkpoint_t = current_t current_step = 0 timestepper = rk4_step + nrestart = 100 + nhealth = 1 s0 = -6.0 kappa = 1.0 alpha = 2.0e-2 from mpi4py import MPI - comm = MPI.COMM_WORLD - rank = comm.Get_rank() - - gen_grid = partial(get_doublemach_mesh) - - local_mesh, global_nelements = generate_and_distribute_mesh(comm, gen_grid) - - local_nelements = local_mesh.nelements + rst_path = "restart_data/" + rst_pattern = ( + rst_path + "{cname}-{step:04d}-{rank:04d}.pkl" + ) + if rst_step: # read the grid from restart data + rst_fname = rst_pattern.format(cname=rst_name, step=rst_step, rank=rank) + + from mirgecom.restart import read_restart_data + restart_data = read_restart_data(actx, rst_fname) + local_mesh = restart_data["local_mesh"] + local_nelements = local_mesh.nelements + global_nelements = restart_data["global_nelements"] + assert restart_data["nparts"] == nparts + else: # generate the grid from scratch + gen_grid = partial(get_doublemach_mesh) + from mirgecom.simutil import generate_and_distribute_mesh + local_mesh, global_nelements = generate_and_distribute_mesh(comm, gen_grid) + local_nelements = local_mesh.nelements discr = EagerDGDiscretization(actx, local_mesh, order=order, mpi_communicator=comm) - nodes = thaw(actx, discr.nodes()) - current_state = initializer(nodes) + + if logmgr: + logmgr_add_device_name(logmgr, queue) + logmgr_add_device_memory_usage(logmgr, queue) + logmgr_add_many_discretization_quantities(logmgr, discr, dim, + extract_vars_for_logging, units_for_logging) + + logmgr.add_watches([ + ("step.max", "step = {value}, "), + ("t_sim.max", "sim time: {value:1.6e} s\n"), + ("min_pressure", "------- P (min, max) (Pa) = ({value:1.9e}, "), + ("max_pressure", "{value:1.9e})\n"), + ("min_temperature", "------- T (min, max) (K) = ({value:1.9e}, "), + ("max_temperature", "{value:1.9e})\n"), + ("t_step.max", "------- step walltime: {value:6g} s, "), + ("t_log.max", "log walltime: {value:6g} s") + ]) + + if rst_step: + current_t = restart_data["t"] + current_step = rst_step + current_state = restart_data["state"] + if logmgr: + from mirgecom.logging_quantities import logmgr_set_time + logmgr_set_time(logmgr, current_step, current_t) + else: + # Set the current state from time 0 + current_state = initializer(nodes) visualizer = make_visualizer(discr, discr.order if discr.dim == 2 else discr.order) + initname = initializer.__class__.__name__ eosname = eos.__class__.__name__ init_message = make_init_message( @@ -194,16 +262,123 @@ def main(ctx_factory=cl.create_some_context): if rank == 0: logger.info(init_message) - get_timestep = partial( - inviscid_sim_timestep, - discr=discr, - t=current_t, - dt=current_dt, - cfl=current_cfl, - eos=eos, - t_final=t_final, - constant_cfl=constant_cfl, - ) + def my_write_viz(step, t, state, dv=None, tagged_cells=None): + if dv is None: + dv = eos.dependent_vars(state) + if tagged_cells is None: + tagged_cells = smoothness_indicator(discr, state.mass, s0=s0, + kappa=kappa) + viz_fields = [("cv", state), + ("dv", dv), + ("tagged_cells", tagged_cells)] + from mirgecom.simutil import write_visfile + write_visfile(discr, viz_fields, visualizer, vizname=casename, + step=step, t=t, overwrite=True) + + def my_write_restart(step, t, state): + rst_fname = rst_pattern.format(cname=casename, step=step, rank=rank) + rst_data = { + "local_mesh": local_mesh, + "state": state, + "t": t, + "step": step, + "order": order, + "global_nelements": global_nelements, + "num_parts": nparts + } + from mirgecom.restart import write_restart_file + write_restart_file(actx, rst_data, rst_fname, comm) + + def my_health_check(state, dv): + # Note: This health check is tuned s.t. it is a test that + # the case gets the expected solution. If dt,t_final or + # other run parameters are changed, this check should + # be changed accordingly. + health_error = False + from mirgecom.simutil import check_naninf_local, check_range_local + if check_naninf_local(discr, "vol", dv.pressure): + health_error = True + logger.info(f"{rank=}: NANs/Infs in pressure data.") + + from mirgecom.simutil import allsync + if allsync(check_range_local(discr, "vol", dv.pressure, .9, 18.6), + comm, op=MPI.LOR): + health_error = True + from grudge.op import nodal_max, nodal_min + p_min = nodal_min(discr, "vol", dv.pressure) + p_max = nodal_max(discr, "vol", dv.pressure) + logger.info(f"Pressure range violation ({p_min=}, {p_max=})") + + if check_naninf_local(discr, "vol", dv.temperature): + health_error = True + logger.info(f"{rank=}: NANs/INFs in temperature data.") + + if allsync( + check_range_local(discr, "vol", dv.temperature, 2.48e-3, 1.071e-2), + comm, op=MPI.LOR): + health_error = True + from grudge.op import nodal_max, nodal_min + t_min = nodal_min(discr, "vol", dv.temperature) + t_max = nodal_max(discr, "vol", dv.temperature) + logger.info(f"Temperature range violation ({t_min=}, {t_max=})") + + return health_error + + def my_pre_step(step, t, dt, state): + try: + dv = None + + if logmgr: + logmgr.tick_before() + + from mirgecom.simutil import check_step + do_viz = check_step(step=step, interval=nviz) + do_restart = check_step(step=step, interval=nrestart) + do_health = check_step(step=step, interval=nhealth) + + if do_health: + dv = eos.dependent_vars(state) + from mirgecom.simutil import allsync + health_errors = allsync(my_health_check(state, dv), comm, + op=MPI.LOR) + if health_errors: + if rank == 0: + logger.info("Fluid solution failed health check.") + raise MyRuntimeError("Failed simulation health check.") + + if step == rst_step: # don't do viz or restart @ restart + do_viz = False + do_restart = False + + if do_restart: + my_write_restart(step=step, t=t, state=state) + + if do_viz: + if dv is None: + dv = eos.dependent_vars(state) + tagged_cells = smoothness_indicator(discr, state.mass, s0=s0, + kappa=kappa) + my_write_viz(step=step, t=t, state=state, dv=dv, + tagged_cells=tagged_cells) + + except MyRuntimeError: + if rank == 0: + logger.info("Errors detected; attempting graceful exit.") + my_write_viz(step=step, t=t, state=state) + my_write_restart(step=step, t=t, state=state) + raise + + t_remaining = max(0, t_final - t) + return state, min(dt, t_remaining) + + def my_post_step(step, t, dt, state): + # Logmgr needs to know about EOS, dt, dim? + # imo this is a design/scope flaw + if logmgr: + set_dt(logmgr, dt) + set_sim_state(logmgr, dim, state, eos) + logmgr.tick_after() + return state, dt def my_rhs(t, state): return ns_operator( @@ -214,53 +389,26 @@ def my_rhs(t, state): s0=s0, kappa=kappa) ) - def my_checkpoint(step, t, dt, state): - tagged_cells = smoothness_indicator(discr, state.mass, s0=s0, kappa=kappa) - viz_fields = [("tagged cells", tagged_cells)] - return sim_checkpoint( - discr, - visualizer, - eos, - cv=state, - vizname=casename, - step=step, - t=t, - dt=dt, - nstatus=nstatus, - nviz=nviz, - constant_cfl=constant_cfl, - comm=comm, - viz_fields=viz_fields, - overwrite=True, - ) - - try: - (current_step, current_t, current_state) = advance_state( - rhs=my_rhs, - timestepper=timestepper, - checkpoint=my_checkpoint, - get_timestep=get_timestep, - state=current_state, - t=current_t, - t_final=t_final, - ) - except ExactSolutionMismatch as ex: - current_step = ex.step - current_t = ex.t - current_state = ex.state + current_step, current_t, current_state = \ + advance_state(rhs=my_rhs, timestepper=timestepper, + pre_step_callback=my_pre_step, + post_step_callback=my_post_step, dt=current_dt, + state=current_state, t=current_t, t_final=t_final) - # if current_t != checkpoint_t: + # Dump the final data if rank == 0: logger.info("Checkpointing final state ...") - my_checkpoint( - current_step, - t=current_t, - dt=(current_t - checkpoint_t), - state=current_state, - ) + final_dv = eos.dependent_vars(current_state) + my_write_viz(step=current_step, t=current_t, state=current_state, dv=final_dv) + my_write_restart(step=current_step, t=current_t, state=current_state) + + if logmgr: + logmgr.close() + elif use_profiling: + print(actx.tabulate_profiling_data()) - if current_t - t_final < 0: - raise ValueError("Simulation exited abnormally") + finish_tol = 1e-16 + assert np.abs(current_t - t_final) < finish_tol if __name__ == "__main__": From 8830bb1ba879c1977d29406514fd612501c0d187 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Sat, 21 Aug 2021 08:40:52 -0500 Subject: [PATCH 102/106] Update from upstream --- test/test_av.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_av.py b/test/test_av.py index c3465e281..858afd7b4 100644 --- a/test/test_av.py +++ b/test/test_av.py @@ -194,8 +194,8 @@ def av_flux(self, disc, btag, diffusion, **kwargs): from grudge.trace_pair import TracePair bnd_grad_pair = TracePair(btag, interior=grad_soln_minus, exterior=grad_soln_plus) - from mirgecom.flux import gradient_flux_central - flux_weak = gradient_flux_central(bnd_grad_pair, normal=nhat) + from mirgecom.flux import divergence_flux_central + flux_weak = divergence_flux_central(bnd_grad_pair, normal=nhat) return disc.project(btag, "all_faces", flux_weak) boundaries = {BTAG_ALL: TestBoundary()} From 2cdf5b9e859b301cde2f36a130045b576463c9b7 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Sat, 21 Aug 2021 09:52:08 -0500 Subject: [PATCH 103/106] Add back gmsh to requirements --- examples/doublemach-mpi.py | 3 ++- requirements.txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 42a22a714..206973fe8 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -116,7 +116,8 @@ def get_doublemach_mesh(): Physical Curve('ic3') = {1}; Physical Curve('wall') = {2}; Physical Curve('out') = {5}; - """, "geo"), force_ambient_dim=2, dimensions=2, target_unit="M") + """, "geo"), force_ambient_dim=2, dimensions=2, target_unit="M", + output_file_name=meshfile) else: mesh = read_gmsh(meshfile, force_ambient_dim=2) diff --git a/requirements.txt b/requirements.txt index afefc2614..326fe7806 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,6 +7,7 @@ pymetis importlib-resources psutil pyyaml +gmsh # The following packages will be git cloned by emirge: --editable git+https://github.com/inducer/pymbolic.git#egg=pymbolic From 954348d2ab92638309eba136382a2aae321741e8 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Sun, 22 Aug 2021 20:38:35 -0500 Subject: [PATCH 104/106] Update doublemach example with developments from upstream --- examples/doublemach-mpi.py | 162 ++++++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 63 deletions(-) diff --git a/examples/doublemach-mpi.py b/examples/doublemach-mpi.py index 206973fe8..4cbf50efd 100644 --- a/examples/doublemach-mpi.py +++ b/examples/doublemach-mpi.py @@ -30,7 +30,12 @@ import pyopencl.tools as cl_tools from functools import partial -from meshmode.array_context import PyOpenCLArrayContext +from meshmode.array_context import ( + PyOpenCLArrayContext, + PytatoPyOpenCLArrayContext +) +from mirgecom.profiling import PyOpenCLProfilingArrayContext + from meshmode.dof_array import thaw from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa from grudge.dof_desc import DTAG_BOUNDARY @@ -38,7 +43,6 @@ from grudge.shortcuts import make_visualizer -from mirgecom.fluid import make_conserved from mirgecom.navierstokes import ns_operator from mirgecom.artificial_viscosity import ( av_operator, @@ -46,7 +50,7 @@ ) from mirgecom.io import make_init_message from mirgecom.mpi import mpi_entry_point - +from mirgecom.fluid import make_conserved from mirgecom.integrators import rk4_step from mirgecom.steppers import advance_state from mirgecom.boundary import ( @@ -56,10 +60,10 @@ from mirgecom.initializers import DoubleMachReflection from mirgecom.eos import IdealSingleGas from mirgecom.transport import SimpleTransport +from mirgecom.simutil import get_sim_timestep from logpyle import set_dt from mirgecom.euler import extract_vars_for_logging, units_for_logging -from mirgecom.profiling import PyOpenCLProfilingArrayContext from mirgecom.logging_quantities import ( initialize_logmgr, logmgr_add_many_discretization_quantities, @@ -125,9 +129,9 @@ def get_doublemach_mesh(): @mpi_entry_point -def main(ctx_factory=cl.create_some_context, use_leap=False, - use_profiling=False, rst_step=None, rst_name=None, - casename="doubleMach", use_logmgr=True): +def main(ctx_factory=cl.create_some_context, use_logmgr=True, + use_leap=False, use_profiling=False, casename=None, + rst_filename=None, actx_class=PyOpenCLArrayContext): """Drive the example.""" cl_ctx = ctx_factory() @@ -143,61 +147,39 @@ def main(ctx_factory=cl.create_some_context, use_leap=False, filename=f"{casename}.sqlite", mode="wu", mpi_comm=comm) if use_profiling: - queue = cl.CommandQueue(cl_ctx, - properties=cl.command_queue_properties.PROFILING_ENABLE) - actx = PyOpenCLProfilingArrayContext(queue, - allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)), - logmgr=logmgr) + queue = cl.CommandQueue( + cl_ctx, properties=cl.command_queue_properties.PROFILING_ENABLE) else: queue = cl.CommandQueue(cl_ctx) - actx = PyOpenCLArrayContext(queue, - allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue))) - dim = 2 - order = 3 - # Too many steps for CI - # t_final = 1.0e-2 + actx = actx_class( + queue, + allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue))) + + # Timestepping control + current_step = 0 + timestepper = rk4_step t_final = 1.0e-3 current_cfl = 0.1 current_dt = 1.0e-4 current_t = 0 - # {{{ Initialize simple transport model - kappa = 1e-5 - sigma = 1e-5 - transport_model = SimpleTransport(viscosity=sigma, thermal_conductivity=kappa) - # }}} - eos = IdealSingleGas(transport_model=transport_model) - initializer = DoubleMachReflection() - - boundaries = { - DTAG_BOUNDARY("ic1"): PrescribedBoundary(initializer), - DTAG_BOUNDARY("ic2"): PrescribedBoundary(initializer), - DTAG_BOUNDARY("ic3"): PrescribedBoundary(initializer), - DTAG_BOUNDARY("wall"): AdiabaticNoslipMovingBoundary(), - DTAG_BOUNDARY("out"): AdiabaticNoslipMovingBoundary(), - } constant_cfl = False + + # Some i/o frequencies nstatus = 10 nviz = 100 - current_step = 0 - timestepper = rk4_step nrestart = 100 nhealth = 1 - s0 = -6.0 - kappa = 1.0 - alpha = 2.0e-2 - from mpi4py import MPI - rst_path = "restart_data/" rst_pattern = ( rst_path + "{cname}-{step:04d}-{rank:04d}.pkl" ) - if rst_step: # read the grid from restart data - rst_fname = rst_pattern.format(cname=rst_name, step=rst_step, rank=rank) + if rst_filename: # read the grid from restart data + rst_filename = f"{rst_filename}-{rank:04d}.pkl" from mirgecom.restart import read_restart_data - restart_data = read_restart_data(actx, rst_fname) + restart_data = read_restart_data(actx, rst_filename) local_mesh = restart_data["local_mesh"] local_nelements = local_mesh.nelements global_nelements = restart_data["global_nelements"] @@ -208,10 +190,12 @@ def main(ctx_factory=cl.create_some_context, use_leap=False, local_mesh, global_nelements = generate_and_distribute_mesh(comm, gen_grid) local_nelements = local_mesh.nelements + order = 3 discr = EagerDGDiscretization(actx, local_mesh, order=order, mpi_communicator=comm) nodes = thaw(actx, discr.nodes()) + dim = 2 if logmgr: logmgr_add_device_name(logmgr, queue) logmgr_add_device_memory_usage(logmgr, queue) @@ -229,9 +213,30 @@ def main(ctx_factory=cl.create_some_context, use_leap=False, ("t_log.max", "log walltime: {value:6g} s") ]) - if rst_step: + # Solution setup and initialization + s0 = -6.0 + kappa = 1.0 + alpha = 2.0e-2 + # {{{ Initialize simple transport model + kappa_t = 1e-5 + sigma_v = 1e-5 + transport_model = SimpleTransport(viscosity=sigma_v, + thermal_conductivity=kappa_t) + # }}} + eos = IdealSingleGas(transport_model=transport_model) + initializer = DoubleMachReflection() + + boundaries = { + DTAG_BOUNDARY("ic1"): PrescribedBoundary(initializer), + DTAG_BOUNDARY("ic2"): PrescribedBoundary(initializer), + DTAG_BOUNDARY("ic3"): PrescribedBoundary(initializer), + DTAG_BOUNDARY("wall"): AdiabaticNoslipMovingBoundary(), + DTAG_BOUNDARY("out"): AdiabaticNoslipMovingBoundary(), + } + + if rst_filename: current_t = restart_data["t"] - current_step = rst_step + current_step = restart_data["step"] current_state = restart_data["state"] if logmgr: from mirgecom.logging_quantities import logmgr_set_time @@ -278,17 +283,18 @@ def my_write_viz(step, t, state, dv=None, tagged_cells=None): def my_write_restart(step, t, state): rst_fname = rst_pattern.format(cname=casename, step=step, rank=rank) - rst_data = { - "local_mesh": local_mesh, - "state": state, - "t": t, - "step": step, - "order": order, - "global_nelements": global_nelements, - "num_parts": nparts - } - from mirgecom.restart import write_restart_file - write_restart_file(actx, rst_data, rst_fname, comm) + if rst_fname != rst_filename: + rst_data = { + "local_mesh": local_mesh, + "state": state, + "t": t, + "step": step, + "order": order, + "global_nelements": global_nelements, + "num_parts": nparts + } + from mirgecom.restart import write_restart_file + write_restart_file(actx, rst_data, rst_fname, comm) def my_health_check(state, dv): # Note: This health check is tuned s.t. it is a test that @@ -347,10 +353,6 @@ def my_pre_step(step, t, dt, state): logger.info("Fluid solution failed health check.") raise MyRuntimeError("Failed simulation health check.") - if step == rst_step: # don't do viz or restart @ restart - do_viz = False - do_restart = False - if do_restart: my_write_restart(step=step, t=t, state=state) @@ -369,8 +371,10 @@ def my_pre_step(step, t, dt, state): my_write_restart(step=step, t=t, state=state) raise - t_remaining = max(0, t_final - t) - return state, min(dt, t_remaining) + dt = get_sim_timestep(discr, current_state, current_t, current_dt, + current_cfl, eos, t_final, constant_cfl) + + return state, dt def my_post_step(step, t, dt, state): # Logmgr needs to know about EOS, dt, dim? @@ -390,6 +394,9 @@ def my_rhs(t, state): s0=s0, kappa=kappa) ) + current_dt = get_sim_timestep(discr, current_state, current_t, current_dt, + current_cfl, eos, t_final, constant_cfl) + current_step, current_t, current_state = \ advance_state(rhs=my_rhs, timestepper=timestepper, pre_step_callback=my_pre_step, @@ -413,7 +420,36 @@ def my_rhs(t, state): if __name__ == "__main__": + import argparse + casename = "doublemach" + parser = argparse.ArgumentParser(description=f"MIRGE-Com Example: {casename}") + parser.add_argument("--lazy", action="store_true", + help="switch to a lazy computation mode") + parser.add_argument("--profiling", action="store_true", + help="turn on detailed performance profiling") + parser.add_argument("--log", action="store_true", default=True, + help="turn on logging") + parser.add_argument("--leap", action="store_true", + help="use leap timestepper") + parser.add_argument("--restart_file", help="root name of restart file") + parser.add_argument("--casename", help="casename to use for i/o") + args = parser.parse_args() + if args.profiling: + if args.lazy: + raise ValueError("Can't use lazy and profiling together.") + actx_class = PyOpenCLProfilingArrayContext + else: + actx_class = PytatoPyOpenCLArrayContext if args.lazy \ + else PyOpenCLArrayContext + logging.basicConfig(format="%(message)s", level=logging.INFO) - main() + if args.casename: + casename = args.casename + rst_filename = None + if args.restart_file: + rst_filename = args.restart_file + + main(use_logmgr=args.log, use_leap=args.leap, use_profiling=args.profiling, + casename=casename, rst_filename=rst_filename, actx_class=actx_class) # vim: foldmethod=marker From c65c653dfeee4791215abb42d46b92587138c785 Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Mon, 23 Aug 2021 07:21:46 -0500 Subject: [PATCH 105/106] Fix bug in av boundary routine --- mirgecom/boundary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirgecom/boundary.py b/mirgecom/boundary.py index b2a2fb6ca..18364b3d4 100644 --- a/mirgecom/boundary.py +++ b/mirgecom/boundary.py @@ -380,7 +380,7 @@ def adiabatic_slip_pair(self, discr, cv, btag, **kwargs): def exterior_grad_q(self, nodes, nhat, grad_cv, **kwargs): """Get the exterior grad(Q) on the boundary.""" # Grab some boundary-relevant data - num_equations, dim = grad_cv.mass.shape + dim, = grad_cv.mass.shape # Subtract 2*wall-normal component of q # to enforce q=0 on the wall From 9f1bc7cf30a591c59cf66e51903a28735f0429ee Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Tue, 14 Dec 2021 08:37:06 -0600 Subject: [PATCH 106/106] Try gmsh in conda instead. --- conda-env.yml | 1 + requirements.txt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/conda-env.yml b/conda-env.yml index 9b97d1fc5..c546b41bd 100644 --- a/conda-env.yml +++ b/conda-env.yml @@ -23,3 +23,4 @@ dependencies: - cantera - h5py * nompi_* # Make sure cantera does not pull in MPI through h5py - vtk +- gmsh diff --git a/requirements.txt b/requirements.txt index 88e1ff89a..4dc2b033d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,6 @@ pymetis importlib-resources psutil pyyaml -gmsh # The following packages will be git cloned by emirge: --editable git+https://github.com/inducer/pymbolic.git#egg=pymbolic