def test_nodal_reductions(actx_factory): actx = actx_factory() from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=1) mesh = builder.get_mesh(4, builder.mesh_order) dcoll = DiscretizationCollection(actx, mesh, order=builder.order) x = thaw(dcoll.nodes(), actx) def f(x): return -actx.np.sin(10 * x[0]) def g(x): return actx.np.cos(2 * x[0]) def h(x): return -actx.np.tan(5 * x[0]) fields = make_obj_array([f(x), g(x), h(x)]) f_ref = actx.to_numpy(flatten(fields[0])) g_ref = actx.to_numpy(flatten(fields[1])) h_ref = actx.to_numpy(flatten(fields[2])) concat_fields = np.concatenate([f_ref, g_ref, h_ref]) for inner_grudge_op, np_op in [(op.nodal_sum, np.sum), (op.nodal_max, np.max), (op.nodal_min, np.min)]: # FIXME: Remove this once all grudge reductions return device scalars def grudge_op(dcoll, dd, vec): res = inner_grudge_op(dcoll, dd, vec) from numbers import Number if not isinstance(res, Number): return actx.to_numpy(res) else: return res # Componentwise reduction checks assert np.isclose(grudge_op(dcoll, "vol", fields[0]), np_op(f_ref), rtol=1e-13) assert np.isclose(grudge_op(dcoll, "vol", fields[1]), np_op(g_ref), rtol=1e-13) assert np.isclose(grudge_op(dcoll, "vol", fields[2]), np_op(h_ref), rtol=1e-13) # Test nodal reductions work on object arrays assert np.isclose(grudge_op(dcoll, "vol", fields), np_op(concat_fields), rtol=1e-13)
def test_nodal_reductions_with_container(actx_factory): actx = actx_factory() from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=2) mesh = builder.get_mesh(4, builder.mesh_order) dcoll = DiscretizationCollection(actx, mesh, order=builder.order) x = thaw(dcoll.nodes(), actx) def f(x): return -actx.np.sin(10 * x[0]) * actx.np.cos(2 * x[1]) def g(x): return actx.np.cos(2 * x[0]) * actx.np.sin(10 * x[1]) def h(x): return -actx.np.tan(5 * x[0]) * actx.np.tan(0.5 * x[1]) mass = f(x) + g(x) momentum = make_obj_array([f(x) / g(x), h(x)]) enthalpy = h(x) - g(x) ary_container = MyContainer(name="container", mass=mass, momentum=momentum, enthalpy=enthalpy) mass_ref = actx.to_numpy(flatten(mass)) momentum_ref = np.concatenate( [actx.to_numpy(mom_i) for mom_i in flatten(momentum)]) enthalpy_ref = actx.to_numpy(flatten(enthalpy)) concat_fields = np.concatenate([mass_ref, momentum_ref, enthalpy_ref]) for grudge_op, np_op in [(op.nodal_sum, np.sum), (op.nodal_max, np.max), (op.nodal_min, np.min)]: assert np.isclose(actx.to_numpy(grudge_op(dcoll, "vol", ary_container)), np_op(concat_fields), rtol=1e-13) # Check norm reduction assert np.isclose(actx.to_numpy(op.norm(dcoll, ary_container, np.inf)), np.linalg.norm(concat_fields, ord=np.inf), rtol=1e-13)
def test_non_geometric_factors(actx_factory, name): from grudge.dt_utils import dt_non_geometric_factors actx = actx_factory() # {{{ cases if name == "interval": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=1) elif name == "box2d": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=2) elif name == "box3d": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=3) else: raise ValueError("unknown geometry name: %s" % name) # }}} factors = [] degrees = list(range(1, 8)) for degree in degrees: mesh = builder.get_mesh(1, degree) dcoll = DiscretizationCollection(actx, mesh, order=degree) factors.append(min(dt_non_geometric_factors(dcoll))) # Crude estimate, factors should behave like 1/N**2 factors = np.asarray(factors) lower_bounds = 1 / (np.asarray(degrees)**2) upper_bounds = 6.295 * lower_bounds assert all(lower_bounds <= factors) assert all(factors <= upper_bounds)
def test_geometric_factors_regular_refinement(actx_factory, name): from grudge.dt_utils import dt_geometric_factors actx = actx_factory() # {{{ cases if name == "interval": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=1) elif name == "box2d": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=2) elif name == "box3d": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=3) else: raise ValueError("unknown geometry name: %s" % name) # }}} min_factors = [] for resolution in builder.resolutions: mesh = builder.get_mesh(resolution, builder.mesh_order) dcoll = DiscretizationCollection(actx, mesh, order=builder.order) min_factors.append( actx.to_numpy( op.nodal_min(dcoll, "vol", thaw(dt_geometric_factors(dcoll), actx)))) # Resolution is doubled each refinement, so the ratio of consecutive # geometric factors should satisfy: gfi+1 / gfi = 2 min_factors = np.asarray(min_factors) ratios = min_factors[:-1] / min_factors[1:] assert np.all(np.isclose(ratios, 2))
def test_elementwise_reductions(actx_factory): actx = actx_factory() from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=1) nelements = 4 mesh = builder.get_mesh(nelements, builder.mesh_order) dcoll = DiscretizationCollection(actx, mesh, order=builder.order) x = thaw(dcoll.nodes(), actx) def f(x): return actx.np.sin(x[0]) field = f(x) mins = [] maxs = [] sums = [] for gidx, grp_f in enumerate(field): min_res = np.empty(grp_f.shape) max_res = np.empty(grp_f.shape) sum_res = np.empty(grp_f.shape) for eidx in range(dcoll._volume_discr.groups[gidx].nelements): element_data = actx.to_numpy(grp_f[eidx]) min_res[eidx, :] = np.min(element_data) max_res[eidx, :] = np.max(element_data) sum_res[eidx, :] = np.sum(element_data) mins.append(actx.from_numpy(min_res)) maxs.append(actx.from_numpy(max_res)) sums.append(actx.from_numpy(sum_res)) from meshmode.dof_array import DOFArray, flat_norm ref_mins = DOFArray(actx, data=tuple(mins)) ref_maxs = DOFArray(actx, data=tuple(maxs)) ref_sums = DOFArray(actx, data=tuple(sums)) elem_mins = op.elementwise_min(dcoll, field) elem_maxs = op.elementwise_max(dcoll, field) elem_sums = op.elementwise_sum(dcoll, field) assert flat_norm(elem_mins - ref_mins, ord=np.inf) < 1.e-15 assert flat_norm(elem_maxs - ref_maxs, ord=np.inf) < 1.e-15 assert flat_norm(elem_sums - ref_sums, ord=np.inf) < 1.e-15
def test_mass_surface_area(actx_factory, name): actx = actx_factory() # {{{ cases if name == "2-1-ellipse": from mesh_data import EllipseMeshBuilder builder = EllipseMeshBuilder(radius=3.1, aspect_ratio=2.0) surface_area = _ellipse_surface_area(builder.radius, builder.aspect_ratio) elif name == "spheroid": from mesh_data import SpheroidMeshBuilder builder = SpheroidMeshBuilder() surface_area = _spheroid_surface_area(builder.radius, builder.aspect_ratio) elif name == "box2d": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=2) surface_area = 1.0 elif name == "box3d": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=3) surface_area = 1.0 else: raise ValueError("unknown geometry name: %s" % name) # }}} # {{{ convergence from pytools.convergence import EOCRecorder eoc = EOCRecorder() for resolution in builder.resolutions: mesh = builder.get_mesh(resolution, builder.mesh_order) discr = DiscretizationCollection(actx, mesh, order=builder.order) volume_discr = discr.discr_from_dd(dof_desc.DD_VOLUME) logger.info("ndofs: %d", volume_discr.ndofs) logger.info("nelements: %d", volume_discr.mesh.nelements) # {{{ compute surface area dd = dof_desc.DD_VOLUME sym_op = sym.NodalSum(dd)(sym.MassOperator(dd, dd)(sym.Ones(dd))) approx_surface_area = bind(discr, sym_op)(actx) logger.info("surface: got {:.5e} / expected {:.5e}".format( approx_surface_area, surface_area)) area_error = abs(approx_surface_area - surface_area) / abs(surface_area) # }}} h_max = bind( discr, sym.h_max_from_volume(discr.ambient_dim, dim=discr.dim, dd=dd))(actx) eoc.add_data_point(h_max, area_error + 1.0e-16) # }}} logger.info("surface area error\n%s", str(eoc)) assert eoc.max_error() < 1.0e-14 \ or eoc.order_estimate() > builder.order
def test_mass_surface_area(actx_factory, name): actx = actx_factory() # {{{ cases if name == "2-1-ellipse": from mesh_data import EllipseMeshBuilder builder = EllipseMeshBuilder(radius=3.1, aspect_ratio=2.0) surface_area = _ellipse_surface_area(builder.radius, builder.aspect_ratio) elif name == "spheroid": from mesh_data import SpheroidMeshBuilder builder = SpheroidMeshBuilder() surface_area = _spheroid_surface_area(builder.radius, builder.aspect_ratio) elif name == "box2d": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=2) surface_area = 1.0 elif name == "box3d": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=3) surface_area = 1.0 else: raise ValueError("unknown geometry name: %s" % name) # }}} # {{{ convergence from pytools.convergence import EOCRecorder eoc = EOCRecorder() for resolution in builder.resolutions: mesh = builder.get_mesh(resolution, builder.mesh_order) dcoll = DiscretizationCollection(actx, mesh, order=builder.order) volume_discr = dcoll.discr_from_dd(dof_desc.DD_VOLUME) logger.info("ndofs: %d", volume_discr.ndofs) logger.info("nelements: %d", volume_discr.mesh.nelements) # {{{ compute surface area dd = dof_desc.DD_VOLUME ones_volm = volume_discr.zeros(actx) + 1 approx_surface_area = actx.to_numpy(op.integral(dcoll, dd, ones_volm)) logger.info("surface: got {:.5e} / expected {:.5e}".format( approx_surface_area, surface_area)) area_error = abs(approx_surface_area - surface_area) / abs(surface_area) # }}} # compute max element size from grudge.dt_utils import h_max_from_volume h_max = h_max_from_volume(dcoll) eoc.add_data_point(h_max, area_error) # }}} logger.info("surface area error\n%s", str(eoc)) assert eoc.max_error() < 3e-13 or eoc.order_estimate() > builder.order
def test_elementwise_reductions_with_container(actx_factory): actx = actx_factory() from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=2) nelements = 4 mesh = builder.get_mesh(nelements, builder.mesh_order) dcoll = DiscretizationCollection(actx, mesh, order=builder.order) x = thaw(dcoll.nodes(), actx) def f(x): return actx.np.sin(x[0]) * actx.np.sin(x[1]) def g(x): return actx.np.cos(x[0]) * actx.np.cos(x[1]) def h(x): return actx.np.cos(x[0]) * actx.np.sin(x[1]) mass = 2 * f(x) + 0.5 * g(x) momentum = make_obj_array([f(x) / g(x), h(x)]) enthalpy = 3 * h(x) - g(x) ary_container = MyContainer(name="container", mass=mass, momentum=momentum, enthalpy=enthalpy) def _get_ref_data(field): mins = [] maxs = [] sums = [] for grp_f in field: min_res = np.empty(grp_f.shape) max_res = np.empty(grp_f.shape) sum_res = np.empty(grp_f.shape) for eidx in range(dcoll.mesh.nelements): element_data = actx.to_numpy(grp_f[eidx]) min_res[eidx, :] = np.min(element_data) max_res[eidx, :] = np.max(element_data) sum_res[eidx, :] = np.sum(element_data) mins.append(actx.from_numpy(min_res)) maxs.append(actx.from_numpy(max_res)) sums.append(actx.from_numpy(sum_res)) min_field = DOFArray(actx, data=tuple(mins)) max_field = DOFArray(actx, data=tuple(maxs)) sums_field = DOFArray(actx, data=tuple(sums)) return min_field, max_field, sums_field min_mass, max_mass, sums_mass = _get_ref_data(mass) min_enthalpy, max_enthalpy, sums_enthalpy = _get_ref_data(enthalpy) min_mom_x, max_mom_x, sums_mom_x = _get_ref_data(momentum[0]) min_mom_y, max_mom_y, sums_mom_y = _get_ref_data(momentum[1]) min_momentum = make_obj_array([min_mom_x, min_mom_y]) max_momentum = make_obj_array([max_mom_x, max_mom_y]) sums_momentum = make_obj_array([sums_mom_x, sums_mom_y]) reference_min = MyContainer(name="Reference min", mass=min_mass, momentum=min_momentum, enthalpy=min_enthalpy) reference_max = MyContainer(name="Reference max", mass=max_mass, momentum=max_momentum, enthalpy=max_enthalpy) reference_sum = MyContainer(name="Reference sums", mass=sums_mass, momentum=sums_momentum, enthalpy=sums_enthalpy) elem_mins = op.elementwise_min(dcoll, ary_container) elem_maxs = op.elementwise_max(dcoll, ary_container) elem_sums = op.elementwise_sum(dcoll, ary_container) assert actx.to_numpy(op.norm(dcoll, elem_mins - reference_min, np.inf)) < 1.e-14 assert actx.to_numpy(op.norm(dcoll, elem_maxs - reference_max, np.inf)) < 1.e-14 assert actx.to_numpy(op.norm(dcoll, elem_sums - reference_sum, np.inf)) < 1.e-14