def test_symbolic_evaluation(actx_factory): """ Evaluate a symbolic expression by plugging in numbers and :class:`~meshmode.dof_array.DOFArray`s and compare the result to the equivalent quantity computed explicitly. """ actx = actx_factory() mesh = generate_regular_rect_mesh( a=(-np.pi/2,)*2, b=(np.pi/2,)*2, nelements_per_axis=(4,)*2) from grudge.eager import EagerDGDiscretization discr = EagerDGDiscretization(actx, mesh, order=2) nodes = thaw(actx, discr.nodes()) sym_coords = pmbl.make_sym_vector("x", 2) sym_f = ( pmbl.var("exp")(-pmbl.var("t")) * pmbl.var("cos")(sym_coords[0]) * pmbl.var("sin")(sym_coords[1])) t = 0.5 f = sym.EvaluationMapper({"t": t, "x": nodes})(sym_f) expected_f = np.exp(-t) * actx.np.cos(nodes[0]) * actx.np.sin(nodes[1]) assert actx.to_numpy(discr.norm(f - expected_f)/discr.norm(expected_f)) < 1e-12
def test_wave_stability(actx_factory, problem, timestep_scale, order, visualize=False): """Checks stability of the wave operator for a given problem setup. Adjust *timestep_scale* to get timestep close to stability limit. """ actx = actx_factory() p = problem sym_u, sym_v, sym_f, sym_rhs = sym_wave(p.dim, p.sym_phi) mesh = p.mesh_factory(8) from grudge.eager import EagerDGDiscretization discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) def sym_eval(expr, t): return sym.EvaluationMapper({"c": p.c, "x": nodes, "t": t})(expr) def get_rhs(t, w): result = wave_operator(discr, c=p.c, w=w) result[0] += sym_eval(sym_f, t) return result t = 0. u = sym_eval(sym_u, t) v = sym_eval(sym_v, t) fields = flat_obj_array(u, v) from mirgecom.integrators import rk4_step dt = timestep_scale / order**2 for istep in range(10): fields = rk4_step(fields, t, dt, get_rhs) t += dt expected_u = sym_eval(sym_u, 10 * dt) expected_v = sym_eval(sym_v, 10 * dt) expected_fields = flat_obj_array(expected_u, expected_v) if visualize: from grudge.shortcuts import make_visualizer vis = make_visualizer(discr, discr.order) vis.write_vtk_file("wave_stability.vtu", [ ("u", fields[0]), ("v", fields[1:]), ("u_expected", expected_fields[0]), ("v_expected", expected_fields[1:]), ]) err = discr.norm(fields - expected_fields, np.inf) max_err = discr.norm(expected_fields, np.inf) assert err < max_err
def test_pulse(ctx_factory, dim): """ Test of Gaussian pulse generator. If it looks, walks, and quacks like a Gaussian, then ... """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) nel_1d = 10 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, nelements_per_axis=(nel_1d, ) * dim) order = 1 print(f"Number of elements: {mesh.nelements}") discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) print(f"DIM = {dim}, {len(nodes)}") print(f"Nodes={nodes}") tol = 1e-15 from mirgecom.initializers import make_pulse amp = 1.0 w = .1 rms2 = w * w r0 = np.zeros(dim) r2 = np.dot(nodes, nodes) / rms2 pulse = make_pulse(amp=amp, r0=r0, w=w, r=nodes) print(f"Pulse = {pulse}") # does it return the expected exponential? pulse_check = actx.np.exp(-.5 * r2) print(f"exact: {pulse_check}") pulse_resid = pulse - pulse_check print(f"pulse residual: {pulse_resid}") assert (discr.norm(pulse_resid, np.inf) < tol) # proper scaling with amplitude? amp = 2.0 pulse = 0 pulse = make_pulse(amp=amp, r0=r0, w=w, r=nodes) pulse_resid = pulse - (pulse_check + pulse_check) assert (discr.norm(pulse_resid, np.inf) < tol) # proper scaling with r? amp = 1.0 rcheck = np.sqrt(2.0) * nodes pulse = make_pulse(amp=amp, r0=r0, w=w, r=rcheck) assert (discr.norm(pulse - (pulse_check * pulse_check), np.inf) < tol) # proper scaling with w? w = w / np.sqrt(2.0) pulse = make_pulse(amp=amp, r0=r0, w=w, r=nodes) assert (discr.norm(pulse - (pulse_check * pulse_check), np.inf) < tol)
def test_inviscid_flux_components(actx_factory, dim): """Test uniform pressure case. Checks that the Euler-internal inviscid flux routine :func:`mirgecom.inviscid.inviscid_flux` returns exactly the expected result with a constant pressure and no flow. Expected inviscid flux is: F(q) = <rhoV, (E+p)V, rho(V.x.V) + pI> Checks that only diagonal terms of the momentum flux: [ rho(V.x.V) + pI ] are non-zero and return the correctly calculated p. """ actx = actx_factory() eos = IdealSingleGas() p0 = 1.0 nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, nelements_per_axis=(nel_1d, ) * dim) order = 3 discr = EagerDGDiscretization(actx, mesh, order=order) eos = IdealSingleGas() logger.info(f"Number of {dim}d elems: {mesh.nelements}") # === this next block tests 1,2,3 dimensions, # with single and multiple nodes/states. The # purpose of this block is to ensure that when # all components of V = 0, the flux recovers # the expected values (and p0 within tolerance) # === with V = 0, fixed P = p0 tolerance = 1e-15 nodes = thaw(actx, discr.nodes()) mass = discr.zeros(actx) + np.dot(nodes, nodes) + 1.0 mom = make_obj_array([discr.zeros(actx) for _ in range(dim)]) p_exact = discr.zeros(actx) + p0 energy = p_exact / 0.4 + 0.5 * np.dot(mom, mom) / mass cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom) p = eos.pressure(cv) flux = inviscid_flux(discr, eos, cv) assert discr.norm(p - p_exact, np.inf) < tolerance logger.info(f"{dim}d flux = {flux}") # for velocity zero, these components should be == zero assert discr.norm(flux.mass, 2) == 0.0 assert discr.norm(flux.energy, 2) == 0.0 # The momentum diagonal should be p # Off-diagonal should be identically 0 assert discr.norm(flux.momentum - p0 * np.identity(dim), np.inf) < tolerance
def test_wave_accuracy(actx_factory, problem, order, visualize=False): """Checks accuracy of the wave operator for a given problem setup. """ actx = actx_factory() p = problem sym_u, sym_v, sym_f, sym_rhs = sym_wave(p.dim, p.sym_phi) from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() for n in [8, 10, 12] if p.dim == 3 else [8, 12, 16]: mesh = p.mesh_factory(n) from grudge.eager import EagerDGDiscretization discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) def sym_eval(expr, t): return sym.EvaluationMapper({"c": p.c, "x": nodes, "t": t})(expr) t_check = 1.23456789 u = sym_eval(sym_u, t_check) v = sym_eval(sym_v, t_check) fields = flat_obj_array(u, v) rhs = wave_operator(discr, c=p.c, w=fields) rhs[0] = rhs[0] + sym_eval(sym_f, t_check) expected_rhs = sym_eval(sym_rhs, t_check) rel_linf_err = actx.to_numpy( discr.norm(rhs - expected_rhs, np.inf) / discr.norm(expected_rhs, np.inf)) eoc_rec.add_data_point(1. / n, rel_linf_err) if visualize: from grudge.shortcuts import make_visualizer vis = make_visualizer(discr, discr.order) vis.write_vtk_file( "wave_accuracy_{order}_{n}.vtu".format(order=order, n=n), [ ("u", fields[0]), ("v", fields[1:]), ("rhs_u_actual", rhs[0]), ("rhs_v_actual", rhs[1:]), ("rhs_u_expected", expected_rhs[0]), ("rhs_v_expected", expected_rhs[1:]), ]) print("Approximation error:") print(eoc_rec) assert (eoc_rec.order_estimate() >= order - 0.5 or eoc_rec.max_error() < 1e-11)
def test_idealsingle_lump(ctx_factory): """Test EOS with mass lump. Tests that the IdealSingleGas EOS returns the correct (uniform) pressure for the Lump solution field. """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) dim = 2 nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=[(0.0, ), (-5.0, )], b=[(10.0, ), (5.0, )], n=(nel_1d, ) * dim) order = 3 logger.info(f"Number of elements {mesh.nelements}") discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) # Init soln with Vortex center = np.zeros(shape=(dim, )) velocity = np.zeros(shape=(dim, )) center[0] = 5 velocity[0] = 1 lump = Lump(center=center, velocity=velocity) eos = IdealSingleGas() lump_soln = lump(0, nodes) cv = split_conserved(dim, lump_soln) p = eos.pressure(cv) exp_p = 1.0 errmax = discr.norm(p - exp_p, np.inf) exp_ke = 0.5 * cv.mass ke = eos.kinetic_energy(cv) kerr = discr.norm(ke - exp_ke, np.inf) te = eos.total_energy(cv, p) terr = discr.norm(te - cv.energy, np.inf) logger.info(f"lump_soln = {lump_soln}") logger.info(f"pressure = {p}") assert errmax < 1e-15 assert kerr < 1e-15 assert terr < 1e-15
def test_species_mass_gradient(actx_factory, dim): """Test gradY structure and values against exact.""" actx = actx_factory() nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(1.0, ) * dim, b=(2.0, ) * dim, nelements_per_axis=(nel_1d, ) * dim) order = 1 discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) zeros = discr.zeros(actx) ones = zeros + 1 nspecies = 2 * dim mass = 2 * ones # make mass != 1 energy = zeros + 2.5 velocity = make_obj_array([ones for _ in range(dim)]) mom = mass * velocity # assemble y so that each one has simple, but unique grad components y = make_obj_array([ones for _ in range(nspecies)]) for idim in range(dim): ispec = 2 * idim y[ispec] = ispec * (idim * dim + 1) * sum([(iidim + 1) * nodes[iidim] for iidim in range(dim)]) y[ispec + 1] = -y[ispec] species_mass = mass * y cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom, species_mass=species_mass) from grudge.op import local_grad grad_cv = make_conserved(dim, q=local_grad(discr, cv.join())) from mirgecom.fluid import species_mass_fraction_gradient grad_y = species_mass_fraction_gradient(discr, cv, grad_cv) assert grad_y.shape == (nspecies, dim) from meshmode.dof_array import DOFArray assert type(grad_y[0, 0]) == DOFArray tol = 1e-11 for idim in range(dim): ispec = 2 * idim exact_grad = np.array([(ispec * (idim * dim + 1)) * (iidim + 1) for iidim in range(dim)]) assert discr.norm(grad_y[ispec] - exact_grad, np.inf) < tol assert discr.norm(grad_y[ispec + 1] + exact_grad, np.inf) < tol
def test_idealsingle_vortex(ctx_factory): r"""Test EOS with isentropic vortex. Tests that the IdealSingleGas EOS returns the correct pressure (p) for the Vortex2D solution field (i.e. $p = \rho^{\gamma}$). """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) dim = 2 nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=[(0.0, ), (-5.0, )], b=[(10.0, ), (5.0, )], n=(nel_1d, ) * dim) order = 3 logger.info(f"Number of elements {mesh.nelements}") discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) eos = IdealSingleGas() # Init soln with Vortex vortex = Vortex2D() vortex_soln = vortex(0, nodes) cv = split_conserved(dim, vortex_soln) gamma = eos.gamma() p = eos.pressure(cv) exp_p = cv.mass**gamma errmax = discr.norm(p - exp_p, np.inf) exp_ke = 0.5 * np.dot(cv.momentum, cv.momentum) / cv.mass ke = eos.kinetic_energy(cv) kerr = discr.norm(ke - exp_ke, np.inf) te = eos.total_energy(cv, p) terr = discr.norm(te - cv.energy, np.inf) logger.info(f"vortex_soln = {vortex_soln}") logger.info(f"pressure = {p}") assert errmax < 1e-15 assert kerr < 1e-15 assert terr < 1e-15
def test_inviscid_mom_flux_components(actx_factory, dim, livedim): r"""Test components of the momentum flux with constant pressure, V != 0. Checks that the flux terms are returned in the proper order by running only 1 non-zero velocity component at-a-time. """ actx = actx_factory() eos = IdealSingleGas() p0 = 1.0 nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh( a=(-0.5,) * dim, b=(0.5,) * dim, nelements_per_axis=(nel_1d,) * dim ) order = 3 discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) tolerance = 1e-15 for livedim in range(dim): mass = discr.zeros(actx) + 1.0 + np.dot(nodes, nodes) mom = make_obj_array([discr.zeros(actx) for _ in range(dim)]) mom[livedim] = mass p_exact = discr.zeros(actx) + p0 energy = ( p_exact / (eos.gamma() - 1.0) + 0.5 * np.dot(mom, mom) / mass ) cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom) p = eos.pressure(cv) assert discr.norm(p - p_exact, np.inf) < tolerance flux = inviscid_flux(discr, eos, cv) logger.info(f"{dim}d flux = {flux}") vel_exact = mom / mass # first two components should be nonzero in livedim only assert discr.norm(flux.mass - mom, np.inf) == 0 eflux_exact = (energy + p_exact)*vel_exact assert discr.norm(flux.energy - eflux_exact, np.inf) == 0 logger.info("Testing momentum") xpmomflux = mass*np.outer(vel_exact, vel_exact) + p_exact*np.identity(dim) assert discr.norm(flux.momentum - xpmomflux, np.inf) < tolerance
def test_vortex_init(ctx_factory): """ Simple test to check that Vortex2D initializer creates the expected solution field. """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) dim = 2 nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=[(0.0, ), (-5.0, )], b=[(10.0, ), (5.0, )], nelements_per_axis=(nel_1d, ) * dim) order = 3 logger.info(f"Number of elements: {mesh.nelements}") discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) # Init soln with Vortex vortex = Vortex2D() cv = vortex(nodes) gamma = 1.4 p = 0.4 * (cv.energy - 0.5 * np.dot(cv.momentum, cv.momentum) / cv.mass) exp_p = cv.mass**gamma errmax = discr.norm(p - exp_p, np.inf) logger.info(f"vortex_soln = {cv}") logger.info(f"pressure = {p}") assert errmax < 1e-15
def test_velocity_gradient_structure(actx_factory): """Test gradv data structure, verifying usability with other helper routines.""" from mirgecom.fluid import velocity_gradient actx = actx_factory() dim = 3 nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh( a=(1.0,) * dim, b=(2.0,) * dim, nelements_per_axis=(nel_1d,) * dim ) order = 1 discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) zeros = discr.zeros(actx) ones = zeros + 1.0 mass = 2*ones energy = zeros + 2.5 velocity_x = nodes[0] + 2*nodes[1] + 3*nodes[2] velocity_y = 4*nodes[0] + 5*nodes[1] + 6*nodes[2] velocity_z = 7*nodes[0] + 8*nodes[1] + 9*nodes[2] velocity = make_obj_array([velocity_x, velocity_y, velocity_z]) mom = mass * velocity cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom) from grudge.op import local_grad grad_cv = make_conserved(dim, q=local_grad(discr, cv.join())) grad_v = velocity_gradient(discr, cv, grad_cv) tol = 1e-11 exp_result = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] exp_trans = [[1, 4, 7], [2, 5, 8], [3, 6, 9]] exp_trace = 15 assert grad_v.shape == (dim, dim) from meshmode.dof_array import DOFArray assert type(grad_v[0, 0]) == DOFArray assert discr.norm(grad_v - exp_result, np.inf) < tol assert discr.norm(grad_v.T - exp_trans, np.inf) < tol assert discr.norm(np.trace(grad_v) - exp_trace, np.inf) < tol
def test_viscous_timestep(actx_factory, dim, mu, vel): """Test timestep size.""" actx = actx_factory() nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(1.0, ) * dim, b=(2.0, ) * dim, nelements_per_axis=(nel_1d, ) * dim) order = 1 discr = EagerDGDiscretization(actx, mesh, order=order) zeros = discr.zeros(actx) ones = zeros + 1.0 velocity = make_obj_array([zeros + vel for _ in range(dim)]) massval = 1 mass = massval * ones # I *think* this energy should yield c=1.0 energy = zeros + 1.0 / (1.4 * .4) mom = mass * velocity species_mass = None cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom, species_mass=species_mass) from grudge.dt_utils import characteristic_lengthscales chlen = characteristic_lengthscales(actx, discr) from grudge.op import nodal_min chlen_min = nodal_min(discr, "vol", chlen) mu = mu * chlen_min if mu < 0: mu = 0 tv_model = None else: tv_model = SimpleTransport(viscosity=mu) eos = IdealSingleGas() gas_model = GasModel(eos=eos, transport=tv_model) fluid_state = make_fluid_state(cv, gas_model) from mirgecom.viscous import get_viscous_timestep dt_field = get_viscous_timestep(discr, fluid_state) speed_total = fluid_state.wavespeed dt_expected = chlen / (speed_total + (mu / chlen)) error = (dt_expected - dt_field) / dt_expected assert actx.to_numpy(discr.norm(error, np.inf)) == 0
def test_lump_rhs(actx_factory, dim, order): """Test the inviscid rhs using the non-trivial mass lump case. The case is tested against the analytic expressions of the RHS. Checks several different orders and refinement levels to check error behavior. """ actx = actx_factory() tolerance = 1e-10 maxxerr = 0.0 from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() for nel_1d in [4, 8, 12]: from meshmode.mesh.generation import ( generate_regular_rect_mesh, ) mesh = generate_regular_rect_mesh( a=(-5, ) * dim, b=(5, ) * dim, nelements_per_axis=(nel_1d, ) * dim, ) logger.info(f"Number of elements: {mesh.nelements}") discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) # Init soln with Lump and expected RHS = 0 center = np.zeros(shape=(dim, )) velocity = np.zeros(shape=(dim, )) lump = Lump(dim=dim, center=center, velocity=velocity) lump_soln = lump(nodes) boundaries = { BTAG_ALL: PrescribedInviscidBoundary(fluid_solution_func=lump) } inviscid_rhs = euler_operator(discr, eos=IdealSingleGas(), boundaries=boundaries, cv=lump_soln, time=0.0) expected_rhs = lump.exact_rhs(discr, cv=lump_soln, time=0) err_max = discr.norm((inviscid_rhs - expected_rhs).join(), np.inf) if err_max > maxxerr: maxxerr = err_max eoc_rec.add_data_point(1.0 / nel_1d, err_max) logger.info(f"Max error: {maxxerr}") logger.info(f"Error for (dim,order) = ({dim},{order}):\n" f"{eoc_rec}") assert (eoc_rec.order_estimate() >= order - 0.5 or eoc_rec.max_error() < tolerance)
def test_viscous_stress_tensor(actx_factory, transport_model): """Test tau data structure and values against exact.""" actx = actx_factory() dim = 3 nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(1.0, ) * dim, b=(2.0, ) * dim, nelements_per_axis=(nel_1d, ) * dim) order = 1 discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) zeros = discr.zeros(actx) ones = zeros + 1.0 # assemble velocities for simple, unique grad components velocity_x = nodes[0] + 2 * nodes[1] + 3 * nodes[2] velocity_y = 4 * nodes[0] + 5 * nodes[1] + 6 * nodes[2] velocity_z = 7 * nodes[0] + 8 * nodes[1] + 9 * nodes[2] velocity = make_obj_array([velocity_x, velocity_y, velocity_z]) mass = 2 * ones energy = zeros + 2.5 mom = mass * velocity cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom) grad_cv = op.local_grad(discr, cv) if transport_model: tv_model = SimpleTransport(bulk_viscosity=1.0, viscosity=0.5) else: tv_model = PowerLawTransport() eos = IdealSingleGas() gas_model = GasModel(eos=eos, transport=tv_model) fluid_state = make_fluid_state(cv, gas_model) mu = tv_model.viscosity(eos, cv) lam = tv_model.volume_viscosity(eos, cv) # Exact answer for tau exp_grad_v = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) exp_grad_v_t = np.array([[1, 4, 7], [2, 5, 8], [3, 6, 9]]) exp_div_v = 15 exp_tau = (mu * (exp_grad_v + exp_grad_v_t) + lam * exp_div_v * np.eye(3)) from mirgecom.viscous import viscous_stress_tensor tau = viscous_stress_tensor(fluid_state, grad_cv) # The errors come from grad_v assert actx.to_numpy(discr.norm(tau - exp_tau, np.inf)) < 1e-12
def test_velocity_gradient_eoc(actx_factory, dim): """Test that the velocity gradient converges at the proper rate.""" from mirgecom.fluid import velocity_gradient actx = actx_factory() order = 3 from pytools.convergence import EOCRecorder eoc = EOCRecorder() nel_1d_0 = 4 for hn1 in [1, 2, 3, 4]: nel_1d = hn1 * nel_1d_0 h = 1/nel_1d from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh( a=(1.0,) * dim, b=(2.0,) * dim, nelements_per_axis=(nel_1d,) * dim ) discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) zeros = discr.zeros(actx) energy = zeros + 2.5 mass = nodes[dim-1]*nodes[dim-1] velocity = make_obj_array([actx.np.cos(nodes[i]) for i in range(dim)]) mom = mass*velocity q = join_conserved(dim, mass=mass, energy=energy, momentum=mom) cv = split_conserved(dim, q) grad_q = obj_array_vectorize(discr.grad, q) grad_cv = split_conserved(dim, grad_q) grad_v = velocity_gradient(discr, cv, grad_cv) def exact_grad_row(xdata, gdim, dim): exact_grad_row = make_obj_array([zeros for _ in range(dim)]) exact_grad_row[gdim] = -actx.np.sin(xdata) return exact_grad_row comp_err = make_obj_array([ discr.norm(grad_v[i] - exact_grad_row(nodes[i], i, dim), np.inf) for i in range(dim)]) err_max = comp_err.max() eoc.add_data_point(h, err_max) logger.info(eoc) assert ( eoc.order_estimate() >= order - 0.5 or eoc.max_error() < 1e-9 )
def test_uniform(ctx_factory, dim): """ Simple test to check that Uniform initializer creates the expected solution field. """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) nel_1d = 2 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, n=(nel_1d, ) * dim) order = 1 print(f"Number of elements: {mesh.nelements}") discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) print(f"DIM = {dim}, {len(nodes)}") print(f"Nodes={nodes}") from mirgecom.initializers import Uniform initr = Uniform(numdim=dim) initsoln = initr(t=0.0, x_vec=nodes) tol = 1e-15 ssoln = split_conserved(dim, initsoln) assert discr.norm(ssoln.mass - 1.0, np.inf) < tol assert discr.norm(ssoln.energy - 2.5, np.inf) < tol print(f"Uniform Soln:{initsoln}") eos = IdealSingleGas() cv = split_conserved(dim, initsoln) p = eos.pressure(cv) print(f"Press:{p}") assert discr.norm(p - 1.0, np.inf) < tol
def test_local_max_species_diffusivity(actx_factory, dim, array_valued): """Test the local maximum species diffusivity.""" actx = actx_factory() nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(1.0, ) * dim, b=(2.0, ) * dim, nelements_per_axis=(nel_1d, ) * dim) order = 1 discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) zeros = discr.zeros(actx) ones = zeros + 1.0 vel = .32 velocity = make_obj_array([zeros + vel for _ in range(dim)]) massval = 1 mass = massval * ones energy = zeros + 1.0 / (1.4 * .4) mom = mass * velocity species_mass = np.array([1., 2., 3.], dtype=object) cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom, species_mass=species_mass) d_alpha_input = np.array([.1, .2, .3]) if array_valued: f = 1 + 0.1 * actx.np.sin(nodes[0]) d_alpha_input *= f tv_model = SimpleTransport(species_diffusivity=d_alpha_input) eos = IdealSingleGas() d_alpha = tv_model.species_diffusivity(eos, cv) from mirgecom.viscous import get_local_max_species_diffusivity expected = .3 * ones if array_valued: expected *= f calculated = get_local_max_species_diffusivity(actx, d_alpha) assert actx.to_numpy(discr.norm(calculated - expected, np.inf)) == 0
def test_vortex_rhs(actx_factory, order): """Tests the inviscid rhs using the non-trivial 2D isentropic vortex case configured to yield rhs = 0. Checks several different orders and refinement levels to check error behavior. """ actx = actx_factory() dim = 2 from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() from meshmode.mesh.generation import generate_regular_rect_mesh for nel_1d in [16, 32, 64]: mesh = generate_regular_rect_mesh( a=(-5, ) * dim, b=(5, ) * dim, n=(nel_1d, ) * dim, ) logger.info(f"Number of {dim}d elements: {mesh.nelements}") discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) # Init soln with Vortex and expected RHS = 0 vortex = Vortex2D(center=[0, 0], velocity=[0, 0]) vortex_soln = vortex(0, nodes) boundaries = {BTAG_ALL: PrescribedBoundary(vortex)} inviscid_rhs = inviscid_operator(discr, eos=IdealSingleGas(), boundaries=boundaries, q=vortex_soln, t=0.0) err_max = discr.norm(inviscid_rhs, np.inf) eoc_rec.add_data_point(1.0 / nel_1d, err_max) message = (f"Error for (dim,order) = ({dim},{order}):\n" f"{eoc_rec}") logger.info(message) assert (eoc_rec.order_estimate() >= order - 0.5 or eoc_rec.max_error() < 1e-11)
def test_restart_cv(actx_factory, nspecies): """Test that restart can read a CV array container.""" actx = actx_factory() nel_1d = 4 dim = 3 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, nelements_per_axis=(nel_1d, ) * dim) order = 3 discr = EagerDGDiscretization(actx, mesh, order=order) from meshmode.dof_array import thaw nodes = thaw(actx, discr.nodes()) mass = nodes[0] energy = nodes[1] mom = make_obj_array([nodes[2] * (i + 3) for i in range(dim)]) species_mass = None if nspecies > 0: mass_fractions = make_obj_array( [i * nodes[0] for i in range(nspecies)]) species_mass = mass * mass_fractions rst_filename = f"test_{nspecies}.pkl" from mirgecom.fluid import make_conserved test_state = make_conserved(dim, mass=mass, energy=energy, momentum=mom, species_mass=species_mass) rst_data = {"state": test_state} from mirgecom.restart import write_restart_file write_restart_file(actx, rst_data, rst_filename) from mirgecom.restart import read_restart_data restart_data = read_restart_data(actx, rst_filename) resid = test_state - restart_data["state"] assert discr.norm(resid.join(), np.inf) == 0
def test_velocity_gradient_sanity(actx_factory, dim, mass_exp, vel_fac): """Test that the grad(v) returns {0, I} for v={constant, r_xyz}.""" from mirgecom.fluid import velocity_gradient actx = actx_factory() nel_1d = 16 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(1.0, ) * dim, b=(2.0, ) * dim, nelements_per_axis=(nel_1d, ) * dim) order = 3 discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) zeros = discr.zeros(actx) ones = zeros + 1.0 mass = 1 * ones for i in range(mass_exp): mass *= (mass + i) energy = zeros + 2.5 velocity = vel_fac * nodes mom = mass * velocity cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom) from grudge.op import local_grad grad_cv = make_conserved(dim, q=local_grad(discr, cv.join())) grad_v = velocity_gradient(discr, cv, grad_cv) tol = 1e-11 exp_result = vel_fac * np.eye(dim) * ones grad_v_err = [ discr.norm(grad_v[i] - exp_result[i], np.inf) for i in range(dim) ] assert max(grad_v_err) < tol
def test_lump_init(ctx_factory): """ Simple test to check that Lump initializer creates the expected solution field. """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) dim = 2 nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=[(0.0, ), (-5.0, )], b=[(10.0, ), (5.0, )], n=(nel_1d, ) * dim) order = 3 logger.info(f"Number of elements: {mesh.nelements}") discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) # Init soln with Vortex center = np.zeros(shape=(dim, )) velocity = np.zeros(shape=(dim, )) center[0] = 5 velocity[0] = 1 lump = Lump(center=center, velocity=velocity) lump_soln = lump(0, nodes) cv = split_conserved(dim, lump_soln) p = 0.4 * (cv.energy - 0.5 * np.dot(cv.momentum, cv.momentum) / cv.mass) exp_p = 1.0 errmax = discr.norm(p - exp_p, np.inf) logger.info(f"lump_soln = {lump_soln}") logger.info(f"pressure = {p}") assert errmax < 1e-15
def test_shock_init(ctx_factory): """ Simple test to check that Shock1D initializer creates the expected solution field. """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) nel_1d = 10 dim = 2 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=[(0.0, ), (1.0, )], b=[(-0.5, ), (0.5, )], nelements_per_axis=(nel_1d, ) * dim) order = 3 print(f"Number of elements: {mesh.nelements}") discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) initr = SodShock1D() initsoln = initr(time=0.0, x_vec=nodes) print("Sod Soln:", initsoln) xpl = 1.0 xpr = 0.1 tol = 1e-15 nodes_x = nodes[0] eos = IdealSingleGas() p = eos.pressure(initsoln) assert actx.to_numpy( discr.norm(actx.np.where(nodes_x < 0.5, p - xpl, p - xpr), np.inf)) < tol
def test_analytic_comparison(actx_factory): """Quick test of state comparison routine.""" from mirgecom.initializers import Vortex2D from mirgecom.simutil import compare_fluid_solutions actx = actx_factory() nel_1d = 4 dim = 2 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh( a=(1.0,) * dim, b=(2.0,) * dim, nelements_per_axis=(nel_1d,) * dim ) order = 2 discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(discr.nodes(), actx) zeros = discr.zeros(actx) ones = zeros + 1.0 mass = ones energy = ones velocity = 2 * nodes mom = mass * velocity vortex_init = Vortex2D() vortex_soln = vortex_init(x_vec=nodes, eos=IdealSingleGas()) cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom) resid = vortex_soln - cv expected_errors = [discr.norm(v, np.inf) for v in resid.join()] errors = compare_fluid_solutions(discr, cv, cv) assert max(errors) == 0 errors = compare_fluid_solutions(discr, cv, vortex_soln) assert errors == expected_errors
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): """Run the example.""" cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from mpi4py import MPI comm = MPI.COMM_WORLD num_parts = comm.Get_size() logmgr = initialize_logmgr(use_logmgr, filename="heat-source.sqlite", mode="wu", mpi_comm=comm) if use_profiling: queue = cl.CommandQueue( cl_ctx, properties=cl.command_queue_properties.PROFILING_ENABLE) else: queue = cl.CommandQueue(cl_ctx) actx = actx_class( queue, allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue))) from meshmode.distributed import MPIMeshDistributor, get_partition_by_pymetis mesh_dist = MPIMeshDistributor(comm) dim = 2 nel_1d = 16 t = 0 t_final = 0.0002 istep = 0 if mesh_dist.is_mananger_rank(): from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh( a=(-0.5,)*dim, b=(0.5,)*dim, nelements_per_axis=(nel_1d,)*dim, boundary_tag_to_face={ "dirichlet": ["+x", "-x"], "neumann": ["+y", "-y"] } ) print("%d elements" % mesh.nelements) part_per_element = get_partition_by_pymetis(mesh, num_parts) local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element, num_parts) del mesh else: local_mesh = mesh_dist.receive_mesh_part() order = 3 discr = EagerDGDiscretization(actx, local_mesh, order=order, mpi_communicator=comm) if dim == 2: # no deep meaning here, just a fudge factor dt = 0.0025/(nel_1d*order**2) else: raise ValueError("don't have a stable time step guesstimate") source_width = 0.2 from arraycontext import thaw nodes = thaw(discr.nodes(), actx) boundaries = { DTAG_BOUNDARY("dirichlet"): DirichletDiffusionBoundary(0.), DTAG_BOUNDARY("neumann"): NeumannDiffusionBoundary(0.) } u = discr.zeros(actx) if logmgr: logmgr_add_device_name(logmgr, queue) logmgr_add_device_memory_usage(logmgr, queue) logmgr.add_watches(["step.max", "t_step.max", "t_log.max"]) try: logmgr.add_watches(["memory_usage_python.max", "memory_usage_gpu.max"]) except KeyError: pass if use_profiling: logmgr.add_watches(["multiply_time.max"]) vis_timer = IntervalTimer("t_vis", "Time spent visualizing") logmgr.add_quantity(vis_timer) vis = make_visualizer(discr) def rhs(t, u): return ( diffusion_operator( discr, quad_tag=DISCR_TAG_BASE, alpha=1, boundaries=boundaries, u=u) + actx.np.exp(-np.dot(nodes, nodes)/source_width**2)) compiled_rhs = actx.compile(rhs) rank = comm.Get_rank() while t < t_final: if logmgr: logmgr.tick_before() if istep % 10 == 0: print(istep, t, actx.to_numpy(actx.np.linalg.norm(u[0]))) vis.write_vtk_file("fld-heat-source-mpi-%03d-%04d.vtu" % (rank, istep), [ ("u", u) ], overwrite=True) u = rk4_step(u, t, dt, compiled_rhs) t += dt istep += 1 if logmgr: set_dt(logmgr, dt) logmgr.tick_after() final_answer = discr.norm(u, np.inf) resid = abs(final_answer - 0.00020620711665201585) if resid > 1e-15: raise ValueError(f"Run did not produce the expected result {resid=}")
def main(): cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue, allocator=cl_tools.MemoryPool( cl_tools.ImmediateAllocator(queue))) from mpi4py import MPI comm = MPI.COMM_WORLD num_parts = comm.Get_size() from meshmode.distributed import MPIMeshDistributor, get_partition_by_pymetis mesh_dist = MPIMeshDistributor(comm) dim = 2 nel_1d = 16 if mesh_dist.is_mananger_rank(): from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, n=(nel_1d, ) * dim, boundary_tag_to_face={ "dirichlet": ["+x", "-x"], "neumann": ["+y", "-y"] }) print("%d elements" % mesh.nelements) part_per_element = get_partition_by_pymetis(mesh, num_parts) local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element, num_parts) del mesh else: local_mesh = mesh_dist.receive_mesh_part() order = 3 discr = EagerDGDiscretization(actx, local_mesh, order=order, mpi_communicator=comm) if dim == 2: # no deep meaning here, just a fudge factor dt = 0.0025 / (nel_1d * order**2) else: raise ValueError("don't have a stable time step guesstimate") source_width = 0.2 nodes = thaw(actx, discr.nodes()) u = discr.zeros(actx) vis = make_visualizer(discr, order + 3 if dim == 2 else order) boundaries = { grudge_sym.DTAG_BOUNDARY("dirichlet"): DirichletDiffusionBoundary(0.), grudge_sym.DTAG_BOUNDARY("neumann"): NeumannDiffusionBoundary(0.) } def rhs(t, u): return ( diffusion_operator(discr, alpha=1, boundaries=boundaries, u=u) + actx.np.exp(-np.dot(nodes, nodes) / source_width**2)) rank = comm.Get_rank() t = 0 t_final = 0.01 istep = 0 while True: if istep % 10 == 0: print(istep, t, discr.norm(u)) vis.write_vtk_file( "fld-heat-source-mpi-%03d-%04d.vtu" % (rank, istep), [("u", u)]) if t >= t_final: break u = rk4_step(u, t, dt, rhs) t += dt istep += 1
def main(): cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue, allocator=cl_tools.MemoryPool( cl_tools.ImmediateAllocator(queue))) comm = MPI.COMM_WORLD num_parts = comm.Get_size() from meshmode.distributed import MPIMeshDistributor, get_partition_by_pymetis mesh_dist = MPIMeshDistributor(comm) dim = 2 nel_1d = 16 if mesh_dist.is_mananger_rank(): from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, n=(nel_1d, ) * dim) print("%d elements" % mesh.nelements) part_per_element = get_partition_by_pymetis(mesh, num_parts) local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element, num_parts) del mesh else: local_mesh = mesh_dist.receive_mesh_part() order = 3 discr = EagerDGDiscretization(actx, local_mesh, order=order, mpi_communicator=comm) if dim == 2: # no deep meaning here, just a fudge factor dt = 0.75 / (nel_1d * order**2) elif dim == 3: # no deep meaning here, just a fudge factor dt = 0.45 / (nel_1d * order**2) else: raise ValueError("don't have a stable time step guesstimate") fields = flat_obj_array(bump(actx, discr), [discr.zeros(actx) for i in range(discr.dim)]) vis = make_visualizer(discr, order + 3 if dim == 2 else order) def rhs(t, w): return wave_operator(discr, c=1, w=w) rank = comm.Get_rank() t = 0 t_final = 3 istep = 0 while t < t_final: fields = rk4_step(fields, t, dt, rhs) if istep % 10 == 0: print(istep, t, discr.norm(fields[0])) vis.write_vtk_file( "fld-wave-eager-mpi-%03d-%04d.vtu" % (rank, istep), [ ("u", fields[0]), ("v", fields[1:]), ]) t += dt istep += 1
def _euler_flow_stepper(actx, parameters): """ Implements a generic time stepping loop for testing an inviscid flow. """ logging.basicConfig(format="%(message)s", level=logging.INFO) mesh = parameters["mesh"] t = parameters["time"] order = parameters["order"] t_final = parameters["tfinal"] initializer = parameters["initializer"] exittol = parameters["exittol"] casename = parameters["casename"] boundaries = parameters["boundaries"] eos = parameters["eos"] cfl = parameters["cfl"] dt = parameters["dt"] constantcfl = parameters["constantcfl"] nstepstatus = parameters["nstatus"] if t_final <= t: return (0.0) rank = 0 dim = mesh.dim istep = 0 discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) fields = initializer(0, nodes) sdt = get_inviscid_timestep(discr, eos=eos, cfl=cfl, q=fields) initname = initializer.__class__.__name__ eosname = eos.__class__.__name__ message = (f"Num {dim}d order-{order} elements: {mesh.nelements}\n" f"Timestep: {dt}\n" f"Final time: {t_final}\n" f"Status freq: {nstepstatus}\n" f"Initialization: {initname}\n" f"EOS: {eosname}") logger.info(message) vis = make_visualizer(discr, discr.order + 3 if dim == 2 else discr.order) def write_soln(write_status=True): cv = split_conserved(dim, fields) dv = eos.dependent_vars(cv) expected_result = initializer(t, nodes) result_resid = fields - expected_result maxerr = [ np.max(np.abs(result_resid[i].get())) for i in range(dim + 2) ] mindv = [np.min(dvfld.get()) for dvfld in dv] maxdv = [np.max(dvfld.get()) for dvfld in dv] if write_status is True: statusmsg = (f"Status: Step({istep}) Time({t})\n" f"------ P({mindv[0]},{maxdv[0]})\n" f"------ T({mindv[1]},{maxdv[1]})\n" f"------ dt,cfl = ({dt},{cfl})\n" f"------ Err({maxerr})") logger.info(statusmsg) io_fields = ["cv", split_conserved(dim, fields)] io_fields += eos.split_fields(dim, dv) io_fields.append(("exact_soln", expected_result)) io_fields.append(("residual", result_resid)) nameform = casename + "-{iorank:04d}-{iostep:06d}.vtu" visfilename = nameform.format(iorank=rank, iostep=istep) vis.write_vtk_file(visfilename, io_fields) return maxerr def rhs(t, q): return inviscid_operator(discr, eos=eos, boundaries=boundaries, q=q, t=t) while t < t_final: if constantcfl is True: dt = sdt else: cfl = dt / sdt if nstepstatus > 0: if istep % nstepstatus == 0: write_soln() fields = rk4_step(fields, t, dt, rhs) t += dt istep += 1 sdt = get_inviscid_timestep(discr, eos=eos, cfl=cfl, q=fields) if nstepstatus > 0: logger.info("Writing final dump.") maxerr = max(write_soln(False)) else: expected_result = initializer(t, nodes) maxerr = discr.norm(fields - expected_result, np.inf) logger.info(f"Max Error: {maxerr}") if maxerr > exittol: raise ValueError("Solution failed to follow expected result.") return (maxerr)
def test_uniform_rhs(actx_factory, dim, order): """Tests the inviscid rhs using a trivial constant/uniform state which should yield rhs = 0 to FP. The test is performed for 1, 2, and 3 dimensions. """ actx = actx_factory() tolerance = 1e-9 maxxerr = 0.0 from pytools.convergence import EOCRecorder eoc_rec0 = EOCRecorder() eoc_rec1 = EOCRecorder() # for nel_1d in [4, 8, 12]: for nel_1d in [4, 8]: from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, n=(nel_1d, ) * dim) logger.info(f"Number of {dim}d elements: {mesh.nelements}") discr = EagerDGDiscretization(actx, mesh, order=order) mass_input = discr.zeros(actx) + 1 energy_input = discr.zeros(actx) + 2.5 mom_input = make_obj_array( [discr.zeros(actx) for i in range(discr.dim)]) fields = join_conserved(dim, mass=mass_input, energy=energy_input, momentum=mom_input) expected_rhs = make_obj_array( [discr.zeros(actx) for i in range(len(fields))]) boundaries = {BTAG_ALL: DummyBoundary()} inviscid_rhs = inviscid_operator(discr, eos=IdealSingleGas(), boundaries=boundaries, q=fields, t=0.0) rhs_resid = inviscid_rhs - expected_rhs resid_split = split_conserved(dim, rhs_resid) rho_resid = resid_split.mass rhoe_resid = resid_split.energy mom_resid = resid_split.momentum rhs_split = split_conserved(dim, inviscid_rhs) rho_rhs = rhs_split.mass rhoe_rhs = rhs_split.energy rhov_rhs = rhs_split.momentum message = (f"rho_rhs = {rho_rhs}\n" f"rhoe_rhs = {rhoe_rhs}\n" f"rhov_rhs = {rhov_rhs}") logger.info(message) assert discr.norm(rho_resid, np.inf) < tolerance assert discr.norm(rhoe_resid, np.inf) < tolerance for i in range(dim): assert discr.norm(mom_resid[i], np.inf) < tolerance err_max = discr.norm(rhs_resid[i], np.inf) eoc_rec0.add_data_point(1.0 / nel_1d, err_max) assert (err_max < tolerance) if err_max > maxxerr: maxxerr = err_max # set a non-zero, but uniform velocity component for i in range(len(mom_input)): mom_input[i] = discr.zeros(actx) + (-1.0)**i boundaries = {BTAG_ALL: DummyBoundary()} inviscid_rhs = inviscid_operator(discr, eos=IdealSingleGas(), boundaries=boundaries, q=fields, t=0.0) rhs_resid = inviscid_rhs - expected_rhs resid_split = split_conserved(dim, rhs_resid) rho_resid = resid_split.mass rhoe_resid = resid_split.energy mom_resid = resid_split.momentum assert discr.norm(rho_resid, np.inf) < tolerance assert discr.norm(rhoe_resid, np.inf) < tolerance for i in range(dim): assert discr.norm(mom_resid[i], np.inf) < tolerance err_max = discr.norm(rhs_resid[i], np.inf) eoc_rec1.add_data_point(1.0 / nel_1d, err_max) assert (err_max < tolerance) if err_max > maxxerr: maxxerr = err_max message = (f"V == 0 Errors:\n{eoc_rec0}" f"V != 0 Errors:\n{eoc_rec1}") print(message) assert (eoc_rec0.order_estimate() >= order - 0.5 or eoc_rec0.max_error() < 1e-9) assert (eoc_rec1.order_estimate() >= order - 0.5 or eoc_rec1.max_error() < 1e-9)
def test_diffusion_obj_array_vectorize(actx_factory): """ Checks that the diffusion operator can be called with either scalars or object arrays for `u`. """ actx = actx_factory() p = get_decaying_trig(1, 2.) assert isinstance(p.sym_alpha, Number) sym_u1 = p.sym_u sym_u2 = 2 * p.sym_u sym_diffusion_u1 = sym_diffusion(p.dim, p.sym_alpha, sym_u1) sym_diffusion_u2 = sym_diffusion(p.dim, p.sym_alpha, sym_u2) n = 128 mesh = p.get_mesh(n) from grudge.eager import EagerDGDiscretization discr = EagerDGDiscretization(actx, mesh, order=4) nodes = thaw(actx, discr.nodes()) t = 1.23456789 def sym_eval(expr): return sym.EvaluationMapper({"x": nodes, "t": t})(expr) alpha = sym_eval(p.sym_alpha) u1 = sym_eval(sym_u1) u2 = sym_eval(sym_u2) boundaries = p.get_boundaries(discr, actx, t) diffusion_u1 = diffusion_operator(discr, quad_tag=DISCR_TAG_BASE, alpha=alpha, boundaries=boundaries, u=u1) assert isinstance(diffusion_u1, DOFArray) expected_diffusion_u1 = sym_eval(sym_diffusion_u1) rel_linf_err = (discr.norm(diffusion_u1 - expected_diffusion_u1, np.inf) / discr.norm(expected_diffusion_u1, np.inf)) assert rel_linf_err < 1.e-5 boundaries_vector = [boundaries, boundaries] u_vector = make_obj_array([u1, u2]) diffusion_u_vector = diffusion_operator(discr, quad_tag=DISCR_TAG_BASE, alpha=alpha, boundaries=boundaries_vector, u=u_vector) assert isinstance(diffusion_u_vector, np.ndarray) assert diffusion_u_vector.shape == (2, ) expected_diffusion_u_vector = make_obj_array( [sym_eval(sym_diffusion_u1), sym_eval(sym_diffusion_u2)]) rel_linf_err = ( discr.norm(diffusion_u_vector - expected_diffusion_u_vector, np.inf) / discr.norm(expected_diffusion_u_vector, np.inf)) assert rel_linf_err < 1.e-5
def main(snapshot_pattern="wave-eager-{step:04d}-{rank:04d}.pkl", restart_step=None): """Drive the example.""" cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue, allocator=cl_tools.MemoryPool( cl_tools.ImmediateAllocator(queue))) from mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() num_parts = comm.Get_size() if restart_step is None: from meshmode.distributed import MPIMeshDistributor, get_partition_by_pymetis mesh_dist = MPIMeshDistributor(comm) dim = 2 nel_1d = 16 if mesh_dist.is_mananger_rank(): from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, nelements_per_axis=(nel_1d, ) * dim) print("%d elements" % mesh.nelements) part_per_element = get_partition_by_pymetis(mesh, num_parts) local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element, num_parts) del mesh else: local_mesh = mesh_dist.receive_mesh_part() fields = None else: from mirgecom.restart import read_restart_data restart_data = read_restart_data( actx, snapshot_pattern.format(step=restart_step, rank=rank)) local_mesh = restart_data["local_mesh"] nel_1d = restart_data["nel_1d"] assert comm.Get_size() == restart_data["num_parts"] order = 3 discr = EagerDGDiscretization(actx, local_mesh, order=order, mpi_communicator=comm) if local_mesh.dim == 2: # no deep meaning here, just a fudge factor dt = 0.7 / (nel_1d * order**2) elif dim == 3: # no deep meaning here, just a fudge factor dt = 0.4 / (nel_1d * order**2) else: raise ValueError("don't have a stable time step guesstimate") t_final = 3 if restart_step is None: t = 0 istep = 0 fields = flat_obj_array(bump(actx, discr), [discr.zeros(actx) for i in range(discr.dim)]) else: t = restart_data["t"] istep = restart_step assert istep == restart_step restart_fields = restart_data["fields"] old_order = restart_data["order"] if old_order != order: old_discr = EagerDGDiscretization(actx, local_mesh, order=old_order, mpi_communicator=comm) from meshmode.discretization.connection import make_same_mesh_connection connection = make_same_mesh_connection( actx, discr.discr_from_dd("vol"), old_discr.discr_from_dd("vol")) fields = connection(restart_fields) else: fields = restart_fields vis = make_visualizer(discr) def rhs(t, w): return wave_operator(discr, c=1, w=w) while t < t_final: # restart must happen at beginning of step if istep % 100 == 0 and ( # Do not overwrite the restart file that we just read. istep != restart_step): from mirgecom.restart import write_restart_file write_restart_file(actx, restart_data={ "local_mesh": local_mesh, "order": order, "fields": fields, "t": t, "step": istep, "nel_1d": nel_1d, "num_parts": num_parts }, filename=snapshot_pattern.format(step=istep, rank=rank), comm=comm) if istep % 10 == 0: print(istep, t, discr.norm(fields[0])) vis.write_parallel_vtk_file( comm, "fld-wave-eager-mpi-%03d-%04d.vtu" % (rank, istep), [ ("u", fields[0]), ("v", fields[1:]), ]) fields = rk4_step(fields, t, dt, rhs) t += dt istep += 1